Skip to content

Commit 3ed05cf

Browse files
committed
Fix enum to bool comparison
The compiler compiles $enum == true to ZEND_BOOL, which always returns true for objects (with the default cast_object handler). However, when compared to a statically unknown value $enum == $true, the resulting opcode ZEND_IS_EQUAL would call the objects compare handler. The zend_objects_not_comparable() handler, which is installed for enums and other internal classes, blanketly returns false. This does not match the ZEND_BOOL semantics. We now handle bools in zend_objects_not_comparable() explicitly. Fixes GH-16954
1 parent b01f5e3 commit 3ed05cf

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

Zend/tests/enum/comparison.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,5 +53,5 @@ bool(false)
5353
bool(false)
5454
bool(false)
5555
bool(false)
56-
bool(false)
57-
bool(false)
56+
bool(true)
57+
bool(true)

Zend/tests/gh16954.phpt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
GH-16954: Enum to bool comparison is inconsistent
3+
--FILE--
4+
<?php
5+
6+
enum E {
7+
case C;
8+
}
9+
10+
$true = true;
11+
$false = false;
12+
13+
var_dump(E::C == true);
14+
var_dump(E::C == $true);
15+
var_dump(true == E::C);
16+
var_dump($true == E::C);
17+
18+
var_dump(E::C != true);
19+
var_dump(E::C != $true);
20+
var_dump(true != E::C);
21+
var_dump($true != E::C);
22+
23+
var_dump(E::C == false);
24+
var_dump(E::C == $false);
25+
var_dump(false == E::C);
26+
var_dump($false == E::C);
27+
28+
var_dump(E::C != false);
29+
var_dump(E::C != $false);
30+
var_dump(false != E::C);
31+
var_dump($false != E::C);
32+
33+
?>
34+
--EXPECT--
35+
bool(true)
36+
bool(true)
37+
bool(true)
38+
bool(true)
39+
bool(false)
40+
bool(false)
41+
bool(false)
42+
bool(false)
43+
bool(false)
44+
bool(false)
45+
bool(false)
46+
bool(false)
47+
bool(true)
48+
bool(true)
49+
bool(true)
50+
bool(true)

Zend/zend_object_handlers.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,6 +2158,13 @@ ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */
21582158

21592159
ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2)
21602160
{
2161+
zval *other = Z_TYPE_P(o1) == IS_OBJECT ? o2 : o1;
2162+
2163+
/* Fall back to zend_std_compare_objects() for bool. */
2164+
if (Z_TYPE_P(other) == IS_TRUE || Z_TYPE_P(other) == IS_FALSE) {
2165+
return zend_std_compare_objects(o1, o2);
2166+
}
2167+
21612168
return ZEND_UNCOMPARABLE;
21622169
}
21632170

0 commit comments

Comments
 (0)