Skip to content

Commit 3310fa3

Browse files
Zend: Make instanceof object equivalent to is_object()
`$x instanceof object` was syntactically valid but always returned false because `object` is a pseudo-type with no corresponding class entry in the class table. This made the construct silently unusable. At compile time, when the right-hand side of `instanceof` is the literal `object` pseudo-type, emit `ZEND_TYPE_CHECK` with `MAY_BE_OBJECT` instead of `ZEND_INSTANCEOF`. This is the same opcode used by `is_object()`, so `$x instanceof object` now behaves identically to `is_object($x)`. The fix is entirely at compile time; no VM handler changes are required.
1 parent d87d0c6 commit 3310fa3

4 files changed

Lines changed: 75 additions & 0 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ PHP NEWS
33
?? ??? ????, PHP 8.6.0alpha1
44

55
- Core:
6+
. `$x instanceof object` now evaluates like `is_object($x)`, correctly
7+
returning true for any object. (Damien Seguy)
68
. Added first-class callable cache to share instances for the duration of the
79
request. (ilutov)
810
. It is now possible to use reference assign on WeakMap without the key

UPGRADING

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ PHP 8.6 UPGRADE NOTES
1919
1. Backward Incompatible Changes
2020
========================================
2121

22+
- Core:
23+
. `$x instanceof object` previously always evaluated to false. It now
24+
evaluates identically to `is_object($x)`, returning true for any object.
25+
2226
- DOM:
2327
. Properties previously documented as @readonly (e.g. DOMNode::$nodeType,
2428
DOMDocument::$xmlEncoding, DOMEntity::$actualEncoding, ::$encoding,
@@ -181,6 +185,8 @@ PHP 8.6 UPGRADE NOTES
181185
========================================
182186

183187
- Core:
188+
. `$x instanceof object` now evaluates like `is_object($x)`, correctly
189+
returning true for any object.
184190
. It is now possible to use reference assign on WeakMap without the key
185191
needing to be present beforehand.
186192
. It is now possible to define the `__debugInfo()` magic method on enums.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
instanceof with pseudo-type "object" is equivalent to is_object()
3+
--FILE--
4+
<?php
5+
6+
// Objects
7+
$obj = new stdClass;
8+
var_dump($obj instanceof object);
9+
10+
$anon = new class {};
11+
var_dump($anon instanceof object);
12+
13+
// Case-insensitive
14+
var_dump($obj instanceof Object);
15+
var_dump($obj instanceof OBJECT);
16+
17+
// Non-objects (variables, so they go through ZEND_TYPE_CHECK, not the const early-return)
18+
$null = null;
19+
var_dump($null instanceof object);
20+
21+
$int = 42;
22+
var_dump($int instanceof object);
23+
24+
$str = "string";
25+
var_dump($str instanceof object);
26+
27+
$arr = [];
28+
var_dump($arr instanceof object);
29+
30+
// Must be identical to is_object() for any value
31+
$values = [new stdClass, new class {}, null, 42, "str", [], true, 1.5];
32+
foreach ($values as $v) {
33+
if (($v instanceof object) !== is_object($v)) {
34+
echo "MISMATCH for: ";
35+
var_dump($v);
36+
}
37+
}
38+
echo "All match is_object()\n";
39+
40+
// Inside a class scope — class context must not affect the result
41+
class Foo {}
42+
$foo = new Foo;
43+
var_dump($foo instanceof object);
44+
var_dump($foo instanceof Foo); // still works normally
45+
46+
?>
47+
--EXPECT--
48+
bool(true)
49+
bool(true)
50+
bool(true)
51+
bool(true)
52+
bool(false)
53+
bool(false)
54+
bool(false)
55+
bool(false)
56+
All match is_object()
57+
bool(true)
58+
bool(true)

Zend/zend_compile.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11077,6 +11077,15 @@ static void zend_compile_instanceof(znode *result, zend_ast *ast) /* {{{ */
1107711077
return;
1107811078
}
1107911079

11080+
/* "instanceof object" is equivalent to is_object(): emit a type-check instead of a class lookup */
11081+
if (class_ast->kind == ZEND_AST_ZVAL
11082+
&& Z_TYPE_P(zend_ast_get_zval(class_ast)) == IS_STRING
11083+
&& zend_string_equals_ci(zend_ast_get_str(class_ast), ZSTR_KNOWN(ZEND_STR_OBJECT))) {
11084+
opline = zend_emit_op_tmp(result, ZEND_TYPE_CHECK, &obj_node, NULL);
11085+
opline->extended_value = (1 << IS_OBJECT);
11086+
return;
11087+
}
11088+
1108011089
zend_compile_class_ref(&class_node, class_ast,
1108111090
ZEND_FETCH_CLASS_NO_AUTOLOAD | ZEND_FETCH_CLASS_EXCEPTION | ZEND_FETCH_CLASS_SILENT);
1108211091

0 commit comments

Comments
 (0)