[php-src] PR #24653: Optimizer: array keys whose conversion may throw
| From: | jorgsowa | Date: | Sat, 24 Oct 2026 15:45:46 +0000 |
| Subject: | [php-src] PR #24653: Optimizer: array keys whose conversion may throw | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39826@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24653
Author: jorgsowa
Float keys that lose precision (
1.5, 1e20) emit a deprecation and resource
keys emit a warning. An error handler can turn either into an exception.
zend_may_throw_ex() decides whether a key type can throw, and each array-key opcode has
its own copy of that list. The copies drifted apart. Before this change:
| Opcode | Float key | Resource key |
|----------------------------|:---------:|:------------:|
| ASSIGN_DIM | ✗ | ✓ |
| INIT_ARRAY | ✗ | ✓ |
| ADD_ARRAY_ELEMENT | ✗ | ✓ |
| FETCH_DIM_W / FETCH_LIST_W | ✗ | ✓ |
| ARRAY_KEY_EXISTS | ✗ | ✓ |
| FETCH_DIM_IS | ✓ | ✓ |
| ISSET_ISEMPTY_DIM_OBJ | ✓ | ✗ |
✓ means zend_may_throw_ex() already counts that key type as possibly throwing; ✗
means it doesn't. After the change, every row is ✓ in both columns. Array and object keys
aren't listed because every row already counted them.
When it wrongly answers "cannot throw":
- **JIT:** the exception check after the opcode is omitted, so execution continues past a thrown
exception.
- **Dead code elimination (DCE):** an unused write such as $a[1.5] = 1; is removed, so
the error handler never runs.
[GH-16396](https://github.com/php/php-src/issues/16396) reported the DCE case and was closed as
intended optimizer behavior. However, these opcodes already treat resource keys as throwing,
although they only emit a warning. A float key only emits a deprecation, so leaving it out is an
oversight, not a policy.
[b33e3eb8c2d](https://github.com/php/php-src/commit/b33e3eb8c2d0b10856072c93ed70c599cc8da4d1)
already added float keys for FETCH_DIM_IS and ISSET_ISEMPTY_DIM_OBJ. The JIT case was not discussed
in GH-16396.
One shared MAY_BE_THROWING_KEY mask replaces the seven separate lists, so they cannot
drift again. A follow-up for PHP-8.5 adds MAY_BE_NULL for the null offset deprecation.