-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Description
The nullsafe operator (?->) short-circuits execution of subsequent array access operations ([]) if the base object is null. This behavior violates operator precedence rules.
The array subscript [] applies to the result of the method call/property access.
Expression: $nullable?->meth()[0]
- Since
$nullableisnull,$nullable?->meth()evaluates tonull. - The remaining expression is effectively
(null)[0]. - This should trigger a Warning, but currently returns
nullsilently.
The compiler generates a JMP_NULL that skips the FETCH_DIM_R opcode entirely. This is incorrect because the array access is outside the scope of the nullsafe interaction. The issue is even more evident when parentheses are used to strictly contain the nullsafe expression, yet the compiler still jumps over the array access.
Test:
<?php
function example(): void {
$nullable = null;
// Case 1: Standard Chain
// Precedence dictates this is ($nullable?->meth())[0]
// Expected: Warning (accessing offset 0 on null)
// Actual: Silent null
$nullable?->meth()[0];
// Case 2: Parenthesized
// The grouping explicitly separates the operations.
// Expected: Warning
// Actual: Silent null
($nullable?->meth())[0];
// Case 3: Control
// Demonstrates that accessing an offset on null throws a warning.
(null)[0];
}
example();
Expected Result:
Warning: Trying to access array offset on value of type null in %s on line %d
Warning: Trying to access array offset on value of type null in %s on line %d
Warning: Trying to access array offset on value of type null in %s on line %d
Actual Result:
Warning: Trying to access array offset on value of type null in %s on line %d
(Only the control case emits the warning)
The issue is confirmed by the generated opcodes. The JMP_NULL instruction (generated by ?->) targets the instruction after the FETCH_DIM_R (array access).
In the dump below (for ($nullable?->meth())[0]), JMP_NULL at line #6 jumps to ~5. The FETCH_DIM_R at #9 writes to ~5. The jump skips the fetch, improperly treating the array access as part of the nullsafe short-circuit.
filename: /in/n6rgk
function name: example
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
6 1 JMP_NULL ~3 !0
2 INIT_METHOD_CALL !0, 'meth'
3 DO_FCALL 0 $2
4 FETCH_DIM_R ~3 $2, 0
5 FREE ~3
7 6 JMP_NULL ~5 !0 <-- Jumps to result of FETCH_DIM_R
7 INIT_METHOD_CALL !0, 'meth'
8 DO_FCALL 0 $4
9 FETCH_DIM_R ~5 $4, 0
10 FREE ~5
PHP Version
All supported versions
Operating System
N/A