Skip to content

Commit 409baac

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
* PHP-8.0: [ci skip] NEWS Add tests Fix phpGH-8932: Provide a way to get the called-scope of closures (php#9299)
2 parents 2cfb028 + 6aedc5e commit 409baac

File tree

4 files changed

+138
-1
lines changed

4 files changed

+138
-1
lines changed

ext/reflection/php_reflection.c

+22
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,28 @@ ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass)
16961696
}
16971697
/* }}} */
16981698

1699+
/* {{{ Returns the called scope associated to the closure */
1700+
ZEND_METHOD(ReflectionFunctionAbstract, getClosureCalledClass)
1701+
{
1702+
reflection_object *intern;
1703+
1704+
if (zend_parse_parameters_none() == FAILURE) {
1705+
RETURN_THROWS();
1706+
}
1707+
GET_REFLECTION_OBJECT();
1708+
if (!Z_ISUNDEF(intern->obj)) {
1709+
zend_class_entry *called_scope;
1710+
zend_function *closure_func;
1711+
zend_object *object;
1712+
if (Z_OBJ_HANDLER(intern->obj, get_closure)
1713+
&& Z_OBJ_HANDLER(intern->obj, get_closure)(Z_OBJ(intern->obj), &called_scope, &closure_func, &object, 1) == SUCCESS
1714+
&& closure_func && (called_scope || closure_func->common.scope)) {
1715+
zend_reflection_class_factory(called_scope ? (zend_class_entry *) called_scope : closure_func->common.scope, return_value);
1716+
}
1717+
}
1718+
}
1719+
/* }}} */
1720+
16991721
/* {{{ Returns an associative array containing the closures lexical scope variables */
17001722
ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables)
17011723
{

ext/reflection/php_reflection.stub.php

+3
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public function getClosureThis(): ?object {}
5454
/** @tentative-return-type */
5555
public function getClosureScopeClass(): ?ReflectionClass {}
5656

57+
/** @tentative-return-type */
58+
public function getClosureCalledClass(): ?ReflectionClass {}
59+
5760
public function getClosureUsedVariables(): array {}
5861

5962
/** @tentative-return-type */

ext/reflection/php_reflection_arginfo.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* This is a generated file, edit the .stub.php file instead.
2-
* Stub hash: 62fcf63d2f3e93537560c3a03e71fda131a31586 */
2+
* Stub hash: ab0dd21b2fc7ff18c39275e1ec82211c7058c32a */
33

44
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0)
55
ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0)
@@ -31,6 +31,8 @@ ZEND_END_ARG_INFO()
3131
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_ReflectionFunctionAbstract_getClosureScopeClass, 0, 0, ReflectionClass, 1)
3232
ZEND_END_ARG_INFO()
3333

34+
#define arginfo_class_ReflectionFunctionAbstract_getClosureCalledClass arginfo_class_ReflectionFunctionAbstract_getClosureScopeClass
35+
3436
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables, 0, 0, IS_ARRAY, 0)
3537
ZEND_END_ARG_INFO()
3638

@@ -608,6 +610,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, isVariadic);
608610
ZEND_METHOD(ReflectionFunctionAbstract, isStatic);
609611
ZEND_METHOD(ReflectionFunctionAbstract, getClosureThis);
610612
ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass);
613+
ZEND_METHOD(ReflectionFunctionAbstract, getClosureCalledClass);
611614
ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables);
612615
ZEND_METHOD(ReflectionFunctionAbstract, getDocComment);
613616
ZEND_METHOD(ReflectionFunctionAbstract, getEndLine);
@@ -851,6 +854,7 @@ static const zend_function_entry class_ReflectionFunctionAbstract_methods[] = {
851854
ZEND_ME(ReflectionFunctionAbstract, isStatic, arginfo_class_ReflectionFunctionAbstract_isStatic, ZEND_ACC_PUBLIC)
852855
ZEND_ME(ReflectionFunctionAbstract, getClosureThis, arginfo_class_ReflectionFunctionAbstract_getClosureThis, ZEND_ACC_PUBLIC)
853856
ZEND_ME(ReflectionFunctionAbstract, getClosureScopeClass, arginfo_class_ReflectionFunctionAbstract_getClosureScopeClass, ZEND_ACC_PUBLIC)
857+
ZEND_ME(ReflectionFunctionAbstract, getClosureCalledClass, arginfo_class_ReflectionFunctionAbstract_getClosureCalledClass, ZEND_ACC_PUBLIC)
854858
ZEND_ME(ReflectionFunctionAbstract, getClosureUsedVariables, arginfo_class_ReflectionFunctionAbstract_getClosureUsedVariables, ZEND_ACC_PUBLIC)
855859
ZEND_ME(ReflectionFunctionAbstract, getDocComment, arginfo_class_ReflectionFunctionAbstract_getDocComment, ZEND_ACC_PUBLIC)
856860
ZEND_ME(ReflectionFunctionAbstract, getEndLine, arginfo_class_ReflectionFunctionAbstract_getEndLine, ZEND_ACC_PUBLIC)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
--TEST--
2+
GH-8932 (Provide a way to get the called-scope of closures)
3+
--FILE--
4+
<?php
5+
class A {
6+
public static function __callStatic($name, $args) {
7+
echo static::class.'::'.$name, "\n";
8+
}
9+
10+
public function __call($name, $args) {
11+
echo static::class.'->'.$name, "\n";
12+
}
13+
14+
public static function b() {
15+
echo static::class.'::b', "\n";
16+
}
17+
18+
19+
public function c() {
20+
echo static::class.'->c', "\n";
21+
}
22+
23+
public function makeClosure() {
24+
return function () {
25+
echo static::class.'::{closure}'."\n";
26+
};
27+
}
28+
}
29+
30+
class B extends A {}
31+
32+
$c = ['B', 'b'];
33+
$d = \Closure::fromCallable($c);
34+
$r = new \ReflectionFunction($d);
35+
var_dump($r->getClosureCalledClass());
36+
$d();
37+
38+
$c = [new B(), 'c'];
39+
$d = \Closure::fromCallable($c);
40+
$r = new \ReflectionFunction($d);
41+
var_dump($r->getClosureCalledClass());
42+
$d();
43+
44+
$c = ['B', 'd'];
45+
$d = \Closure::fromCallable($c);
46+
$r = new \ReflectionFunction($d);
47+
var_dump($r->getClosureCalledClass());
48+
$d();
49+
50+
$c = [new B(), 'e'];
51+
$d = \Closure::fromCallable($c);
52+
$r = new \ReflectionFunction($d);
53+
var_dump($r->getClosureCalledClass());
54+
$d();
55+
56+
$c = ['A', 'b'];
57+
$d = \Closure::fromCallable($c);
58+
$r = new \ReflectionFunction($d);
59+
var_dump($r->getClosureCalledClass());
60+
$d();
61+
62+
$b = new B();
63+
$d = $b->makeClosure();
64+
$r = new \ReflectionFunction($d);
65+
var_dump($r->getClosureCalledClass());
66+
$d();
67+
68+
$d = function () {
69+
echo "{closure}\n";
70+
};
71+
$r = new \ReflectionFunction($d);
72+
var_dump($r->getClosureCalledClass());
73+
$d();
74+
75+
?>
76+
--EXPECTF--
77+
object(ReflectionClass)#%d (1) {
78+
["name"]=>
79+
string(1) "B"
80+
}
81+
B::b
82+
object(ReflectionClass)#%d (1) {
83+
["name"]=>
84+
string(1) "B"
85+
}
86+
B->c
87+
object(ReflectionClass)#%d (1) {
88+
["name"]=>
89+
string(1) "B"
90+
}
91+
B::d
92+
object(ReflectionClass)#%d (1) {
93+
["name"]=>
94+
string(1) "B"
95+
}
96+
B->e
97+
object(ReflectionClass)#%d (1) {
98+
["name"]=>
99+
string(1) "A"
100+
}
101+
A::b
102+
object(ReflectionClass)#%d (1) {
103+
["name"]=>
104+
string(1) "B"
105+
}
106+
B::{closure}
107+
NULL
108+
{closure}

0 commit comments

Comments
 (0)