|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2021-05-06 04:14 UTC] redwormik at gmail dot com
Description:
------------
I have opcache enabled and opcache.optimization_level at least 0x000000b0 (bits 4, 5 and 8 all set, other irrelevant).
When I compare a variable to NULL in a "false" part of a ternary operator in an if-condition, the variable changes to NULL in the respective branch of the if-condition (i.e. if comparison is === NULL, the variable changes to NULL in the if-branch; if comparison is !== NULL, the variable changes to NULL in the else-branch), even though the ternary operator condition is true.
Returning the value, changing the condition so it does not use ternary operator, moving the NULL-equality out of the condition to a local variable or comparing to anything else other than NULL all work as expected.
Test script:
---------------
<?php
declare(strict_types=1);
function ternary(bool $enabled, ?string $value): void
{
// the "true" part is not as trivial in the real case
if ($enabled ? true : $value === null) {
echo ($value ?? 'NULL') . "\n";
} else {
echo "INVALID\n";
}
}
ternary(true, 'value');
ternary(true, null);
ternary(false, 'value');
ternary(false, null);
Expected result:
----------------
value
NULL
INVALID value
NULL
Actual result:
--------------
NULL
NULL
INVALID value
NULL
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 14:00:01 2025 UTC |
Sorry, changed the output at last minute, but did not change the script. The condition should be (the else-branch output changed): if ($enabled ? true : $value === null) { echo ($value ?? 'NULL') . "\n"; } else { echo "INVALID " . ($value ?? 'NULL') . "\n"; }This happens due to an incorrect pi-node placement: 0000 #2.CV0($enabled) [bool] RANGE[0..1] = RECV 1 0001 #3.CV1($value) [null, string] = RECV 2 0002 JMPZ #2.CV0($enabled) [bool] RANGE[0..1] BB2 BB1: ; follow lines=[3-4] ; from=(BB0) ; to=(BB3) ; idom=BB0 ; level=1 0003 #4.T2 [true] RANGE[1..1] = QM_ASSIGN bool(true) 0004 JMP BB3 BB2: ; target lines=[5-5] ; from=(BB0) ; to=(BB3) ; idom=BB0 ; level=1 0005 #5.T2 [bool] = TYPE_CHECK (null) #3.CV1($value) [null, string] BB3: ; follow target lines=[6-6] ; from=(BB1, BB2) ; to=(BB7, BB4) ; idom=BB0 ; level=1 ; children=(BB4, BB7) #6.X2 [bool] = Phi(#4.X2 [true] RANGE[1..1], #5.X2 [bool]) 0006 JMPZ #6.T2 [bool] BB7 BB4: ; follow lines=[7-7] ; from=(BB3) ; to=(BB6, BB5) ; idom=BB3 ; level=2 ; children=(BB5, BB6) #7.CV1($value) [null] = Pi<BB3>(#3.CV1($value) [null, string] & TYPE [undef, ref, null]) 0007 #8.T4 [] = COALESCE #7.CV1($value) [null] BB6 A pi node was placed in BB4 based on the JMPZ of TYPE_CHECK, but what that didn't account for is that this TYPE_CHECK is only one of the possible values of T2 at that point.