summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--Zend/tests/bug77652.inc6
-rw-r--r--Zend/tests/bug77652.phpt16
-rw-r--r--Zend/zend_compile.c24
4 files changed, 49 insertions, 1 deletions
diff --git a/NEWS b/NEWS
index 66b1603571..1276fd6f42 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? ????, PHP 7.3.4
+- Core:
+ . Fixed bug #77652 (Anonymous classes can lose their interface information).
+ (Nikita)
+
- MySQLi:
. Fixed bug #77597 (mysqli_fetch_field hangs scripts). (Nikita)
diff --git a/Zend/tests/bug77652.inc b/Zend/tests/bug77652.inc
new file mode 100644
index 0000000000..ee8b7dc469
--- /dev/null
+++ b/Zend/tests/bug77652.inc
@@ -0,0 +1,6 @@
+<?php
+return [
+ 'I' => function() {
+ return new class implements I {};
+ },
+];
diff --git a/Zend/tests/bug77652.phpt b/Zend/tests/bug77652.phpt
new file mode 100644
index 0000000000..62b2350c8d
--- /dev/null
+++ b/Zend/tests/bug77652.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #77652: Anonymous classes can lose their interface information
+--FILE--
+<?php
+
+interface I {}
+require __DIR__ . '/bug77652.inc';
+$data = require __DIR__ . '/bug77652.inc';
+print_r(class_implements($data['I']()));
+
+?>
+--EXPECT--
+Array
+(
+ [I] => I
+)
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index fccc45c994..b7fa412d9f 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -6440,10 +6440,32 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */
if (!zend_hash_exists(CG(class_table), lcname)) {
zend_hash_add_ptr(CG(class_table), lcname, ce);
} else {
- /* this anonymous class has been included */
+ /* This anonymous class has been included, reuse the existing definition.
+ * NB: This behavior is buggy, and this should always result in a separate
+ * class declaration. However, until the problem of RTD key collisions is
+ * solved, this gives a behavior close to what is expected. */
zval zv;
ZVAL_PTR(&zv, ce);
destroy_zend_class(&zv);
+ ce = zend_hash_find_ptr(CG(class_table), lcname);
+
+ /* Manually replicate emission of necessary inheritance opcodes here. We cannot
+ * reuse the general code, as we only want to emit the opcodes, without modifying
+ * the reused class definition. */
+ if (ce->ce_flags & ZEND_ACC_IMPLEMENT_TRAITS) {
+ zend_emit_op(NULL, ZEND_BIND_TRAITS, &declare_node, NULL);
+ }
+ if (implements_ast) {
+ zend_ast_list *iface_list = zend_ast_get_list(implements_ast);
+ uint32_t i;
+ for (i = 0; i < iface_list->children; i++) {
+ opline = zend_emit_op(NULL, ZEND_ADD_INTERFACE, &declare_node, NULL);
+ opline->op2_type = IS_CONST;
+ opline->op2.constant = zend_add_class_name_literal(CG(active_op_array),
+ zend_resolve_class_name_ast(iface_list->child[i]));
+ }
+ zend_emit_op(NULL, ZEND_VERIFY_ABSTRACT_CLASS, &declare_node, NULL);
+ }
return;
}
} else {