You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/CHANGELOG.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -122,6 +122,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
122
122
### Fixed
123
123
124
124
-**A `"\x8b"` escape no longer takes the server down with it.** A hex or octal escape in a double-quoted string decodes to a raw byte, and a string built that way (`strpos($output, "\x8b")`, a gzip magic number, a binary delimiter) is text no character encoding can express. PHPantom read those literals as though they were ordinary source text, which is undefined behaviour: on the command line the analysis died part-way through, in the editor the server exited, and in a release build it silently read whatever happened to follow in memory. Every place a literal's value is read now checks it first, so a literal like this is simply one PHPantom has nothing to say about. The rest of the file is analysed as before.
125
+
-**An array literal keeps the value written at each position.**`[$violation, $file, $line]` collapsed to a list of everything it held, so every way of reading one slot back out gave the same `RuleViolation|string|int`: destructuring the row with `[$violation, $file, $line] = $row`, indexing it with `$row[1]`, or pulling it out of the collection it was pushed into. Rows written this way now record what sits at each position, so a slot read is the one value that slot holds, and passing it on no longer reports a type mismatch against everything the row happened to contain. This already worked for a literal nested inside another; it now holds wherever the literal is written. A literal that spreads another array, or one long enough that its arity is beside the point, still describes itself as a list.
126
+
-**A literal keyed on something PHP works out at runtime is described by its keys and values.**`[$name => 1]` was reported as `array{mixed: 1}`, a shape with a field named after the key's type rather than after anything in the code, and a read off it found neither the key that was written nor the one that was asked for. Such a literal is now an `array<K, V>` built from the key and value types it does hold, and a key that is not written as a plain string or integer keeps the type it resolves to, so `[Event::class => $handler]` satisfies a parameter declared `array<class-string, …>`. PHP coerces `null`, `true` and `false` before using them as keys, so those now land on the `''`, `1` and `0` entries they index at runtime.
127
+
-**`(object) []` is a `stdClass`.** Casting an empty array to an object produced an `object{}`, a shape with no properties, which nothing else in the engine produces and which was rejected by every parameter declared `stdClass`. It is now the `stdClass` PHP builds. A cast of a non-empty array still keeps the properties it names.
128
+
-**`+` between two arrays keeps their keys.** The compound `+=` already merged both operands' keys, but writing the same union as `$merged = $defaults + $overrides` collapsed it to a bare `array`, so nothing about the merged array completed or hovered. Both spellings now go through the same merge.
125
129
-**`$matches` outside the guard says the match may not have happened.**`preg_match()` fills its out-parameter with the keys the pattern describes, and that shape was applied wherever the call appeared, the code after a guard that may not have been taken included. So a group read on a line PHP reaches with the empty array a failed match leaves behind was typed as a plain `string`, and nothing said the key might not be there. The call now writes what it leaves either way, and the condition that tests its result decides which of the two a branch is looking at: inside the guard the keys are there and a group read is a `string`, the branch that runs on a failed match gets the empty array, and where the two rejoin the keys are marked as ones that may be missing. Comparing the result guards exactly as the bare call does, in an `if`, an `elseif`, a guard clause that returns on a failed match, and a `while`. `preg_match_all()` is unaffected, since a failed match there still writes one empty list per capture group.
126
130
-**Reading a key a shape marks optional carries the `null` a missing offset yields.** A `@var array{file: string, type?: string}` says the `type` entry may not be there, but reading it produced the same `string` a required key does, so a value that is absent at runtime was passed on as though it could not be. The read now says it may be missing, which is what makes the `??` and the `isset()` around it mean something. A key the shape requires is unchanged.
127
131
-**`!empty($row['name'])` proves the key is there.**`isset($row['name'])` narrowed the entry it named, but the `!empty()` spelling of the same check only ever narrowed a plain variable, so a proof about an array entry or a property path was dropped. Both spellings now record what they prove, in an expression position (a ternary, a `match (true)` arm) as much as in an `if` body, so the guarded read no longer reports the falsy half the guard ruled out.
| B147 |[Array literals are not tuples: slot reads return the union of all elements](todo/bugs.md#b147-array-literals-are-not-tuples-slot-reads-return-the-union-of-all-elements)| Medium-High | Medium |
29
28
||**Release 0.10.0**|||
30
29
31
30
## Sprint 7 — 1.0 release & IDE extensions
@@ -100,6 +99,7 @@ unlikely to move the needle for most users.
100
99
| D17 |[`docblock_native_mismatch` only judges nullability](todo/diagnostics.md#d17-docblock_native_mismatch-only-judges-nullability)| Low | Medium |
101
100
||**[Bug Fixes](todo/bugs.md)**|||
102
101
| B151 |[`?T` and `T\|null` are judged by different rules](todo/bugs.md#b151-t-and-tnull-are-judged-by-different-rules)| High | Low-Medium |
102
+
| B152 |[`array_filter` with `ARRAY_FILTER_USE_KEY` does not narrow the key type](todo/bugs.md#b152-array_filter-with-array_filter_use_key-does-not-narrow-the-key-type)| Low-Medium | Medium |
103
103
||**[Code Actions](todo/actions.md)**|||
104
104
| A40 |[Generate method from call](todo/actions.md#a40-generate-method-from-call)| Medium-High | Medium |
105
105
| A41 |[Create class from non-existing name](todo/actions.md#a41-create-class-from-non-existing-name)| Medium | Medium |
0 commit comments