Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Zend/tests/first_class_callable/constexpr/autoload.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ var_dump(Closure);
Autoloading AutoloadedClass
object(Closure)#%d (1) {
["function"]=>
string(16) "withStaticMethod"
string(33) "AutoloadedClass::withStaticMethod"
}
Called AutoloadedClass::withStaticMethod
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
FCC in initializer errors for static reference to instance method.
FCC in initializer warns for static reference to trait method.
--FILE--
<?php

Expand All @@ -20,7 +20,7 @@ var_dump(Closure);
Deprecated: Calling static trait method Foo::myMethod is deprecated, it should only be called on a class using the trait in %s on line %d
object(Closure)#%d (2) {
["function"]=>
string(8) "myMethod"
string(13) "Foo::myMethod"
["parameter"]=>
array(1) {
["$foo"]=>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
FCC in initializer errors for static reference to instance method (Exception).
FCC in initializer emits deprecation for static reference to trait method (Exception).
--FILE--
<?php

Expand Down
108 changes: 108 additions & 0 deletions Zend/tests/first_class_callable/constexpr/gh19637_closure_scope.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
--TEST--
FCC in attribute sets Closure scope.
--EXTENSIONS--
reflection
--FILE--
<?php

#[Attribute(Attribute::TARGET_CLASS)]
class Attr {
public function __construct(public array $value) {}
}

class F {
public static function foreign() {}
}

class G extends F { }

#[Attr([
F::foreign(...),
G::foreign(...),
self::myMethod(...),
strrev(...),
])]
class C {
private static function myMethod(string $foo) {
return "XXX";
}

public static function foo() {
foreach ([
F::foreign(...),
G::foreign(...),
self::myMethod(...),
strrev(...),
] as $fn) {
$r = new \ReflectionFunction($fn);
var_dump($r->getClosureCalledClass());
var_dump($r->getClosureScopeClass());
}
}
}

foreach ((new ReflectionClass(C::class))->getAttributes() as $reflectionAttribute) {
foreach ($reflectionAttribute->newInstance()->value as $fn) {
$r = new \ReflectionFunction($fn);
var_dump($r->getClosureCalledClass());
var_dump($r->getClosureScopeClass());
}
}
echo "=======\n";
C::foo();

?>
--EXPECTF--
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "F"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "F"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "G"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "F"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "C"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "C"
}
NULL
NULL
=======
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "F"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "F"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "G"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "F"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "C"
}
object(ReflectionClass)#%d (1) {
["name"]=>
string(1) "C"
}
NULL
NULL
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ var_dump(($c->d)("abc"));
--EXPECTF--
object(Closure)#%d (2) {
["function"]=>
string(11) "C::myMethod"
string(11) "P::myMethod"
["parameter"]=>
array(1) {
["$foo"]=>
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/first_class_callable/constexpr/static_call.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var_dump(Closure);
--EXPECTF--
object(Closure)#%d (2) {
["function"]=>
string(8) "myMethod"
string(13) "Foo::myMethod"
["parameter"]=>
array(1) {
["$foo"]=>
Expand Down
13 changes: 8 additions & 5 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
case ZEND_AST_STATIC_CALL:
{
zend_function *fptr;
zend_class_entry *called_scope = NULL;
switch (ast->kind) {
case ZEND_AST_CALL: {
ZEND_ASSERT(ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT);
Expand Down Expand Up @@ -1086,13 +1087,15 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
ZEND_ASSERT(ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT);
zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[2];

zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
if (!ce) {
return FAILURE;
}
called_scope = ce;

fptr = ZEND_MAP_PTR_GET(fcc_ast->fptr);

if (!fptr) {
zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope);
if (!ce) {
return FAILURE;
}
zend_string *method_name = zend_ast_get_str(ast->child[1]);
if (ce->get_static_method) {
fptr = ce->get_static_method(ce, method_name);
Expand Down Expand Up @@ -1145,7 +1148,7 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
}
}

zend_create_fake_closure(result, fptr, scope, scope, NULL);
zend_create_fake_closure(result, fptr, fptr->common.scope, called_scope, NULL);

return SUCCESS;
}
Expand Down