diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | Zend/tests/bug77652.inc | 6 | ||||
-rw-r--r-- | Zend/tests/bug77652.phpt | 16 | ||||
-rw-r--r-- | Zend/zend_compile.c | 24 |
4 files changed, 49 insertions, 1 deletions
@@ -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 { |