From 9eb084dc19175acee34b7a553360694fdaeaccd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Schr=C3=B6der?= Date: Thu, 28 May 2020 12:53:08 +0200 Subject: [PATCH 1/3] Changes to opcache. Fixed AST dump. Proper NULL-handling in reflection. --- Zend/tests/attributes/012-ast-export.phpt | 10 ++--- Zend/zend_ast.c | 2 +- Zend/zend_ast.h | 12 ----- ext/opcache/zend_file_cache.c | 54 +++++++++++------------ ext/opcache/zend_persist.c | 3 +- ext/reflection/php_reflection.c | 2 +- 6 files changed, 32 insertions(+), 51 deletions(-) diff --git a/Zend/tests/attributes/012-ast-export.phpt b/Zend/tests/attributes/012-ast-export.phpt index 90616b00d2813..47176b1b0d02d 100644 --- a/Zend/tests/attributes/012-ast-export.phpt +++ b/Zend/tests/attributes/012-ast-export.phpt @@ -21,13 +21,10 @@ assert(0 && ($a = function () { ?> --EXPECTF-- -Warning: assert(): assert(0 && ($a = <> -<> -function ($a, <> $b) { +Warning: assert(): assert(0 && ($a = <> <> function ($a, <> $b) { })) failed in %s on line %d -Warning: assert(): assert(0 && ($a = <> -fn() => 1)) failed in %s on line %d +Warning: assert(): assert(0 && ($a = <> fn() => 1)) failed in %s on line %d Warning: assert(): assert(0 && ($a = new <> class { <> @@ -35,7 +32,8 @@ Warning: assert(): assert(0 && ($a = new <> class { const FOO = 'foo'; <> public $x; - <> public function a() { + <> + public function a() { } })) failed in %s on line %d diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 18d37ca61dc5d..7f3bc4ef5efad 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1446,7 +1446,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio case ZEND_AST_METHOD: decl = (zend_ast_decl *) ast; if (decl->attributes) { - zend_bool newlines = (ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC); + zend_bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC); zend_ast_export_attributes(str, decl->attributes, indent, newlines); } if (decl->flags & ZEND_ACC_PUBLIC) { diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index 90efaa7bbc107..eae7407461f24 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -315,12 +315,6 @@ static zend_always_inline zend_string *zend_ast_get_constant_name(zend_ast *ast) return Z_STR(((zend_ast_zval *) ast)->val); } -static zend_always_inline HashTable *zend_ast_get_hash(zend_ast *ast) { - zval *zv = zend_ast_get_zval(ast); - ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY); - return Z_ARR_P(zv); -} - static zend_always_inline uint32_t zend_ast_get_num_children(zend_ast *ast) { ZEND_ASSERT(!zend_ast_is_list(ast)); return ast->kind >> ZEND_AST_NUM_CHILDREN_SHIFT; @@ -334,12 +328,6 @@ static zend_always_inline uint32_t zend_ast_get_lineno(zend_ast *ast) { } } -static zend_always_inline zend_ast *zend_ast_create_zval_from_hash(HashTable *hash) { - zval zv; - ZVAL_ARR(&zv, hash); - return zend_ast_create_zval(&zv); -} - static zend_always_inline zend_ast *zend_ast_create_binary_op(uint32_t opcode, zend_ast *op0, zend_ast *op1) { return zend_ast_create_ex(ZEND_AST_BINARY_OP, opcode, op0, op1); } diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index 17def06aac973..3d03100fceea9 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -404,25 +404,23 @@ static void zend_file_cache_serialize_attribute(zval *zv, zend_file_cache_metainfo *info, void *buf) { - if (!IS_SERIALIZED(Z_PTR_P(zv))) { - zend_attribute *attr = Z_PTR_P(zv); - uint32_t i; + zend_attribute *attr = Z_PTR_P(zv); + uint32_t i; - SERIALIZE_PTR(Z_PTR_P(zv)); - attr = Z_PTR_P(zv); - UNSERIALIZE_PTR(attr); + SERIALIZE_PTR(Z_PTR_P(zv)); + attr = Z_PTR_P(zv); + UNSERIALIZE_PTR(attr); - if (!IS_SERIALIZED(attr->name)) { - SERIALIZE_STR(attr->name); - } + if (!IS_SERIALIZED(attr->name)) { + SERIALIZE_STR(attr->name); + } - if (!IS_SERIALIZED(attr->lcname)) { - SERIALIZE_STR(attr->lcname); - } + if (!IS_SERIALIZED(attr->lcname)) { + SERIALIZE_STR(attr->lcname); + } - for (i = 0; i < attr->argc; i++) { - zend_file_cache_serialize_zval(&attr->argv[i], script, info, buf); - } + for (i = 0; i < attr->argc; i++) { + zend_file_cache_serialize_zval(&attr->argv[i], script, info, buf); } } @@ -1175,24 +1173,22 @@ static void zend_file_cache_unserialize_zval(zval *zv, static void zend_file_cache_unserialize_attribute(zval *zv, zend_persistent_script *script, void *buf) { - if (!IS_UNSERIALIZED(Z_PTR_P(zv))) { - zend_attribute *attr; - uint32_t i; + zend_attribute *attr; + uint32_t i; - UNSERIALIZE_PTR(Z_PTR_P(zv)); - attr = Z_PTR_P(zv); + UNSERIALIZE_PTR(Z_PTR_P(zv)); + attr = Z_PTR_P(zv); - if (!IS_UNSERIALIZED(attr->name)) { - UNSERIALIZE_STR(attr->name); - } + if (!IS_UNSERIALIZED(attr->name)) { + UNSERIALIZE_STR(attr->name); + } - if (!IS_UNSERIALIZED(attr->lcname)) { - UNSERIALIZE_STR(attr->lcname); - } + if (!IS_UNSERIALIZED(attr->lcname)) { + UNSERIALIZE_STR(attr->lcname); + } - for (i = 0; i < attr->argc; i++) { - zend_file_cache_unserialize_zval(&attr->argv[i], script, buf); - } + for (i = 0; i < attr->argc; i++) { + zend_file_cache_unserialize_zval(&attr->argv[i], script, buf); } } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 8f2510ddb8044..081f35637d9d2 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -271,7 +271,7 @@ static HashTable *zend_persist_attributes(HashTable *attributes) ZEND_HASH_FOREACH_VAL(attributes, v) { zend_attribute *attr = Z_PTR_P(v); - zend_attribute *copy = zend_shared_memdup(attr, ZEND_ATTRIBUTE_SIZE(attr->argc)); + zend_attribute *copy = zend_shared_memdup_put_free(attr, ZEND_ATTRIBUTE_SIZE(attr->argc)); zend_accel_store_interned_string(copy->name); zend_accel_store_interned_string(copy->lcname); @@ -281,7 +281,6 @@ static HashTable *zend_persist_attributes(HashTable *attributes) } ZVAL_PTR(v, copy); - efree(attr); } ZEND_HASH_FOREACH_END(); ptr = zend_shared_memdup_put_free(attributes, sizeof(HashTable)); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 98198f0404a95..9637ca4608a43 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -1150,7 +1150,7 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut zend_long flags = 0; zend_class_entry *base = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|Sl", &name, &flags) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!l", &name, &flags) == FAILURE) { RETURN_THROWS(); } From 3649c5c16827e7353c9ee9474164c963866646c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Schr=C3=B6der?= Date: Thu, 28 May 2020 13:09:29 +0200 Subject: [PATCH 2/3] Refactored declaration AST to store attributes in child[4]. --- Zend/zend_ast.c | 24 +++++++++++------------- Zend/zend_ast.h | 5 ++--- Zend/zend_compile.c | 8 ++++---- Zend/zend_language_parser.y | 18 +++++++++--------- 4 files changed, 26 insertions(+), 29 deletions(-) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 7f3bc4ef5efad..01d8b6a8a930e 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -114,7 +114,7 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_class_const_or_name(zend_ast * ZEND_API zend_ast *zend_ast_create_decl( zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, - zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3 + zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4 ) { zend_ast_decl *ast; @@ -126,12 +126,12 @@ ZEND_API zend_ast *zend_ast_create_decl( ast->flags = flags; ast->lex_pos = LANG_SCNG(yy_text); ast->doc_comment = doc_comment; - ast->attributes = NULL; ast->name = name; ast->child[0] = child0; ast->child[1] = child1; ast->child[2] = child2; ast->child[3] = child3; + ast->child[4] = child4; return (zend_ast *) ast; } @@ -858,13 +858,11 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast) if (decl->doc_comment) { zend_string_release_ex(decl->doc_comment, 0); } - if (decl->attributes) { - zend_ast_destroy(decl->attributes); - } zend_ast_destroy(decl->child[0]); zend_ast_destroy(decl->child[1]); zend_ast_destroy(decl->child[2]); - ast = decl->child[3]; + zend_ast_destroy(decl->child[3]); + ast = decl->child[4]; goto tail_call; } } @@ -1445,9 +1443,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio case ZEND_AST_ARROW_FUNC: case ZEND_AST_METHOD: decl = (zend_ast_decl *) ast; - if (decl->attributes) { + if (decl->child[4]) { zend_bool newlines = !(ast->kind == ZEND_AST_CLOSURE || ast->kind == ZEND_AST_ARROW_FUNC); - zend_ast_export_attributes(str, decl->attributes, indent, newlines); + zend_ast_export_attributes(str, decl->child[4], indent, newlines); } if (decl->flags & ZEND_ACC_PUBLIC) { smart_str_appends(str, "public "); @@ -1505,8 +1503,8 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio break; case ZEND_AST_CLASS: decl = (zend_ast_decl *) ast; - if (decl->attributes) { - zend_ast_export_attributes(str, decl->attributes, indent, 1); + if (decl->child[4]) { + zend_ast_export_attributes(str, decl->child[4], indent, 1); } if (decl->flags & ZEND_ACC_INTERFACE) { smart_str_appends(str, "interface "); @@ -1839,8 +1837,8 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio smart_str_appends(str, "new "); if (ast->child[0]->kind == ZEND_AST_CLASS) { zend_ast_decl *decl = (zend_ast_decl *) ast->child[0]; - if (decl->attributes) { - zend_ast_export_attributes(str, decl->attributes, indent, 0); + if (decl->child[4]) { + zend_ast_export_attributes(str, decl->child[4], indent, 0); } smart_str_appends(str, "class"); if (zend_ast_get_list(ast->child[1])->children) { @@ -2185,7 +2183,7 @@ zend_ast * ZEND_FASTCALL zend_ast_with_attributes(zend_ast *ast, zend_ast *attr) case ZEND_AST_METHOD: case ZEND_AST_CLASS: case ZEND_AST_ARROW_FUNC: - ((zend_ast_decl *) ast)->attributes = attr; + ((zend_ast_decl *) ast)->child[4] = attr; break; case ZEND_AST_PROP_GROUP: ast->child[2] = attr; diff --git a/Zend/zend_ast.h b/Zend/zend_ast.h index eae7407461f24..0ec922dcea47f 100644 --- a/Zend/zend_ast.h +++ b/Zend/zend_ast.h @@ -194,9 +194,8 @@ typedef struct _zend_ast_decl { uint32_t flags; unsigned char *lex_pos; zend_string *doc_comment; - zend_ast *attributes; zend_string *name; - zend_ast *child[4]; + zend_ast *child[5]; } zend_ast_decl; typedef void (*zend_ast_process_t)(zend_ast *ast); @@ -274,7 +273,7 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zend_ast *list, zend_ast *op ZEND_API zend_ast *zend_ast_create_decl( zend_ast_kind kind, uint32_t flags, uint32_t start_lineno, zend_string *doc_comment, - zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3 + zend_string *name, zend_ast *child0, zend_ast *child1, zend_ast *child2, zend_ast *child3, zend_ast *child4 ); ZEND_API int ZEND_FASTCALL zend_ast_evaluate(zval *result, zend_ast *ast, zend_class_entry *scope); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ceb9a37d04df0..f9e7bc07b4483 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6371,14 +6371,14 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /* if (decl->doc_comment) { op_array->doc_comment = zend_string_copy(decl->doc_comment); } - if (decl->attributes) { + if (decl->child[4]) { int target = ZEND_ATTRIBUTE_TARGET_FUNCTION; if (is_method) { target = ZEND_ATTRIBUTE_TARGET_METHOD; } op_array->attributes = create_attribute_array(); - zend_compile_attributes(op_array->attributes, decl->attributes, 0, target); + zend_compile_attributes(op_array->attributes, decl->child[4], 0, target); } if (decl->kind == ZEND_AST_CLOSURE || decl->kind == ZEND_AST_ARROW_FUNC) { op_array->fn_flags |= ZEND_ACC_CLOSURE; @@ -6824,9 +6824,9 @@ void zend_compile_class_decl(znode *result, zend_ast *ast, zend_bool toplevel) / if (decl->doc_comment) { ce->info.user.doc_comment = zend_string_copy(decl->doc_comment); } - if (decl->attributes) { + if (decl->child[4]) { ce->attributes = create_attribute_array(); - zend_compile_attributes(ce->attributes, decl->attributes, 0, ZEND_ATTRIBUTE_TARGET_CLASS); + zend_compile_attributes(ce->attributes, decl->child[4], 0, ZEND_ATTRIBUTE_TARGET_CLASS); } if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) { diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index b2a770780672d..59d8edf2b7050 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -521,7 +521,7 @@ function_declaration_statement: function returns_ref T_STRING backup_doc_comment '(' parameter_list ')' return_type backup_fn_flags '{' inner_statement_list '}' backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_FUNC_DECL, $2 | $13, $1, $4, - zend_ast_get_str($3), $6, NULL, $11, $8); CG(extra_fn_flags) = $9; } + zend_ast_get_str($3), $6, NULL, $11, $8, NULL); CG(extra_fn_flags) = $9; } ; is_reference: @@ -537,10 +537,10 @@ is_variadic: class_declaration_statement: class_modifiers T_CLASS { $$ = CG(zend_lineno); } T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $3, $7, zend_ast_get_str($4), $5, $6, $9, NULL); } + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, $1, $3, $7, zend_ast_get_str($4), $5, $6, $9, NULL, NULL); } | T_CLASS { $$ = CG(zend_lineno); } T_STRING extends_from implements_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $2, $6, zend_ast_get_str($3), $4, $5, $8, NULL); } + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, 0, $2, $6, zend_ast_get_str($3), $4, $5, $8, NULL, NULL); } ; class_modifiers: @@ -557,13 +557,13 @@ class_modifier: trait_declaration_statement: T_TRAIT { $$ = CG(zend_lineno); } T_STRING backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $2, $4, zend_ast_get_str($3), NULL, NULL, $6, NULL); } + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_TRAIT, $2, $4, zend_ast_get_str($3), NULL, NULL, $6, NULL, NULL); } ; interface_declaration_statement: T_INTERFACE { $$ = CG(zend_lineno); } T_STRING interface_extends_list backup_doc_comment '{' class_statement_list '}' - { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $2, $5, zend_ast_get_str($3), NULL, $4, $7, NULL); } + { $$ = zend_ast_create_decl(ZEND_AST_CLASS, ZEND_ACC_INTERFACE, $2, $5, zend_ast_get_str($3), NULL, $4, $7, NULL, NULL); } ; extends_from: @@ -790,7 +790,7 @@ attributed_class_statement: | method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')' return_type backup_fn_flags method_body backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5, - zend_ast_get_str($4), $7, NULL, $11, $9); CG(extra_fn_flags) = $10; } + zend_ast_get_str($4), $7, NULL, $11, $9, NULL); CG(extra_fn_flags) = $10; } class_statement: attributed_class_statement { $$ = $1; } @@ -928,7 +928,7 @@ anonymous_class: extends_from implements_list backup_doc_comment '{' class_statement_list '}' { zend_ast *decl = zend_ast_create_decl( ZEND_AST_CLASS, ZEND_ACC_ANON_CLASS, $2, $6, NULL, - $4, $5, $8, NULL); + $4, $5, $8, NULL, NULL); $$ = zend_ast_create(ZEND_AST_NEW, decl, $3); } ; @@ -1072,11 +1072,11 @@ inline_function: backup_fn_flags '{' inner_statement_list '}' backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_CLOSURE, $2 | $13, $1, $3, zend_string_init("{closure}", sizeof("{closure}") - 1, 0), - $5, $7, $11, $8); CG(extra_fn_flags) = $9; } + $5, $7, $11, $8, NULL); CG(extra_fn_flags) = $9; } | fn returns_ref '(' parameter_list ')' return_type backup_doc_comment T_DOUBLE_ARROW backup_fn_flags backup_lex_pos expr backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_ARROW_FUNC, $2 | $12, $1, $7, zend_string_init("{closure}", sizeof("{closure}") - 1, 0), $4, NULL, - zend_ast_create(ZEND_AST_RETURN, $11), $6); + zend_ast_create(ZEND_AST_RETURN, $11), $6, NULL); ((zend_ast_decl *) $$)->lex_pos = $10; CG(extra_fn_flags) = $9; } ; From 511e3db98399578b4a324380438d73df6953efa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Schr=C3=B6der?= Date: Thu, 28 May 2020 16:10:08 +0200 Subject: [PATCH 3/3] Aligned scope resolution code. Added closure scope and rebind testing. --- ...e_resolution.phpt => 013_class_scope.phpt} | 49 ++++++++--------- Zend/tests/attributes/017_closure_scope.phpt | 53 +++++++++++++++++++ Zend/zend_compile.c | 32 +++++------ ext/reflection/php_reflection.c | 3 +- 4 files changed, 92 insertions(+), 45 deletions(-) rename Zend/tests/attributes/{013_scope_resolution.phpt => 013_class_scope.phpt} (62%) create mode 100644 Zend/tests/attributes/017_closure_scope.phpt diff --git a/Zend/tests/attributes/013_scope_resolution.phpt b/Zend/tests/attributes/013_class_scope.phpt similarity index 62% rename from Zend/tests/attributes/013_scope_resolution.phpt rename to Zend/tests/attributes/013_class_scope.phpt index 6ee34588945ed..6f5dccd4c84ae 100644 --- a/Zend/tests/attributes/013_scope_resolution.phpt +++ b/Zend/tests/attributes/013_class_scope.phpt @@ -1,5 +1,5 @@ --TEST-- -Attributes make use of correct scope. +Attributes make use of class scope. --FILE-- getMethod('bar')->getParameters()[0]->getAttributes()[0]->getArgum echo "\n"; -class C2 +trait T1 { - private const FOO = 'foo'; - - public static function foo() - { - return <> function (<> $p) { }; - } + <> + public function foo() { } } -$ref = new \ReflectionFunction(C2::foo()); -print_r($ref->getAttributes()[0]->getArguments()); -print_r($ref->getParameters()[0]->getAttributes()[0]->getArguments()); +class C2 +{ + use T1; + + private const FOO = 'bar'; +} +$ref = new \ReflectionClass(C2::class); +print_r($ref->getMethod('foo')->getAttributes()[0]->getArguments()); echo "\n"; class C3 @@ -56,13 +57,13 @@ class C3 } } -$obj = C3::foo(); -$ref = new \ReflectionObject($obj); -$name = $ref->getMethod('bar')->getAttributes()[0]->getArguments()[0]; +$ref = new \ReflectionObject(C3::foo()); -print_r($ref->getAttributes()[0]->getArguments()); -var_dump($name == get_class($obj)); -var_dump($ref->getMethod('bar')->getAttributes()[0]->getArguments()[1]); +$args = $ref->getAttributes()[0]->getArguments(); +var_dump($args[0] == $ref->getName(), $args[1]); + +$args = $ref->getMethod('bar')->getAttributes()[0]->getArguments(); +var_dump($args[0] == $ref->getName(), $args[1]); ?> --EXPECT-- @@ -95,18 +96,10 @@ Array Array ( [0] => C2 - [1] => foo -) -Array -( - [0] => C2 - [1] => foo + [1] => bar ) -Array -( - [0] => C3 - [1] => foo -) +bool(true) +string(3) "bar" bool(true) string(3) "bar" diff --git a/Zend/tests/attributes/017_closure_scope.phpt b/Zend/tests/attributes/017_closure_scope.phpt new file mode 100644 index 0000000000000..f57b4b73b3c08 --- /dev/null +++ b/Zend/tests/attributes/017_closure_scope.phpt @@ -0,0 +1,53 @@ +--TEST-- +Attributes make use of closure scope. +--FILE-- +> function (<> $p) { }; + } +} + +$ref = new \ReflectionFunction(C1::foo()); +print_r($ref->getAttributes()[0]->getArguments()); +print_r($ref->getParameters()[0]->getAttributes()[0]->getArguments()); + +echo "\n"; + +$ref = new \ReflectionFunction(C1::foo()->bindTo(null, Test1::class)); +print_r($ref->getAttributes()[0]->getArguments()); +print_r($ref->getParameters()[0]->getAttributes()[0]->getArguments()); + +?> +--EXPECT-- +Array +( + [0] => C1 + [1] => foo +) +Array +( + [0] => C1 + [1] => foo +) + +Array +( + [0] => Test1 + [1] => bar +) +Array +( + [0] => Test1 + [1] => bar +) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index f9e7bc07b4483..8ba55b3a2dce6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1046,10 +1046,6 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */ ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*))); ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); } - - if (op_array->attributes) { - GC_ADDREF(op_array->attributes); - } } if (function->common.function_name) { @@ -6371,15 +6367,7 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /* if (decl->doc_comment) { op_array->doc_comment = zend_string_copy(decl->doc_comment); } - if (decl->child[4]) { - int target = ZEND_ATTRIBUTE_TARGET_FUNCTION; - if (is_method) { - target = ZEND_ATTRIBUTE_TARGET_METHOD; - } - op_array->attributes = create_attribute_array(); - zend_compile_attributes(op_array->attributes, decl->child[4], 0, target); - } if (decl->kind == ZEND_AST_CLOSURE || decl->kind == ZEND_AST_ARROW_FUNC) { op_array->fn_flags |= ZEND_ACC_CLOSURE; } @@ -6399,6 +6387,17 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /* CG(active_op_array) = op_array; + if (decl->child[4]) { + int target = ZEND_ATTRIBUTE_TARGET_FUNCTION; + + if (is_method) { + target = ZEND_ATTRIBUTE_TARGET_METHOD; + } + + op_array->attributes = create_attribute_array(); + zend_compile_attributes(op_array->attributes, decl->child[4], 0, target); + } + /* Do not leak the class scope into free standing functions, even if they are dynamically * defined inside a class method. This is necessary for correct handling of magic constants. * For example __CLASS__ should always be "" inside a free standing function. */ @@ -6824,10 +6823,6 @@ void zend_compile_class_decl(znode *result, zend_ast *ast, zend_bool toplevel) / if (decl->doc_comment) { ce->info.user.doc_comment = zend_string_copy(decl->doc_comment); } - if (decl->child[4]) { - ce->attributes = create_attribute_array(); - zend_compile_attributes(ce->attributes, decl->child[4], 0, ZEND_ATTRIBUTE_TARGET_CLASS); - } if (UNEXPECTED((decl->flags & ZEND_ACC_ANON_CLASS))) { /* Serialization is not supported for anonymous classes */ @@ -6842,6 +6837,11 @@ void zend_compile_class_decl(znode *result, zend_ast *ast, zend_bool toplevel) / CG(active_class_entry) = ce; + if (decl->child[4]) { + ce->attributes = create_attribute_array(); + zend_compile_attributes(ce->attributes, decl->child[4], 0, ZEND_ATTRIBUTE_TARGET_CLASS); + } + if (implements_ast) { zend_compile_implements(implements_ast); } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 9637ca4608a43..6d4f257eb4a8c 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -6411,8 +6411,9 @@ ZEND_METHOD(ReflectionAttribute, getName) static zend_always_inline int import_attribute_value(zval *ret, zval *val, zend_class_entry *scope) /* {{{ */ { ZVAL_COPY_OR_DUP(ret, val); + if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - if (FAILURE == zval_update_constant_ex(ret, scope)) { + if (SUCCESS != zval_update_constant_ex(ret, scope)) { zval_ptr_dtor(ret); return FAILURE; }