Skip to content

Commit aa79d51

Browse files
committed
Add more tests
1 parent 3f275c4 commit aa79d51

File tree

3 files changed

+112
-1
lines changed

3 files changed

+112
-1
lines changed

ext/reflection/php_reflection.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1518,7 +1518,6 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho
15181518
intern->ref_type = REF_TYPE_FUNCTION;
15191519
intern->ce = ce;
15201520
if (closure_object) {
1521-
intern->ce = zend_ce_closure;
15221521
ZVAL_OBJ_COPY(&intern->obj, closure_object);
15231522
}
15241523

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
ReflectionTypes of relative class types (self, parent) in Closure bound to class automatically
3+
--FILE--
4+
<?php
5+
6+
class A {}
7+
class B extends A {
8+
public function test() {
9+
$fnSelf = function (): self { };
10+
$fnParent = function (): parent {};
11+
$fnStatic = function (): static {};
12+
test_scopes($fnSelf, $fnParent, $fnStatic);
13+
}
14+
}
15+
class C extends B {}
16+
17+
function test_scopes(Closure ...$fns) {
18+
foreach ($fns as $fn) {
19+
$rc = new ReflectionFunction($fn);
20+
echo "Bound to: ", $rc->getClosureCalledClass()->name, PHP_EOL;
21+
$type = $rc->getReturnType();
22+
echo "Type: ", $type, PHP_EOL;
23+
echo "Instance of: ", $type::class, PHP_EOL;
24+
try {
25+
$resolvedType = $type->resolveToNamedType();
26+
echo "\tResolved Type: ", $resolvedType, PHP_EOL;
27+
echo "\tInstance of: ", $resolvedType::class, PHP_EOL;
28+
} catch (\Throwable $e) {
29+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
30+
}
31+
}
32+
}
33+
34+
$b = new C();
35+
$b->test();
36+
37+
38+
?>
39+
--EXPECT--
40+
Bound to: C
41+
Type: self
42+
Instance of: ReflectionRelativeClassType
43+
Resolved Type: B
44+
Instance of: ReflectionNamedType
45+
Bound to: C
46+
Type: parent
47+
Instance of: ReflectionRelativeClassType
48+
Resolved Type: A
49+
Instance of: ReflectionNamedType
50+
Bound to: C
51+
Type: static
52+
Instance of: ReflectionRelativeClassType
53+
Resolved Type: C
54+
Instance of: ReflectionNamedType
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Check that a bound Closure retrieved via getDeclaringFunction() can still resolve types
3+
--FILE--
4+
<?php
5+
6+
class A {}
7+
class B extends A {}
8+
class C extends B {}
9+
10+
$closureSelf = function($op1, $op2 = 0): self { };
11+
$closureParent = function($op1, $op2 = 0): parent { };
12+
$closureStatic = function($op1, $op2 = 0): static { };
13+
14+
const CLOSURE_SELF_NAME = '{closure:' . __FILE__ . ':7}';
15+
const CLOSURE_PARENT_NAME = '{closure:' . __FILE__ . ':8}';
16+
const CLOSURE_STATIC_NAME = '{closure:' . __FILE__ . ':9}';
17+
18+
$cases = [
19+
[$closureSelf, CLOSURE_SELF_NAME],
20+
[$closureParent, CLOSURE_PARENT_NAME],
21+
[$closureStatic, CLOSURE_STATIC_NAME],
22+
];
23+
24+
$c = new C();
25+
foreach ($cases as [$unboundFn, $name]) {
26+
$fn = $unboundFn->bindTo($c, B::class);
27+
$rClosure = new ReflectionFunction($fn);
28+
var_dump($rClosure->name == $name);
29+
30+
$params = $rClosure->getParameters();
31+
unset ($rClosure);
32+
33+
$closureFromParam = $params[0]->getDeclaringFunction();
34+
var_dump($closureFromParam->name == $name);
35+
var_dump($closureFromParam::class);
36+
$type = $closureFromParam->getReturnType();
37+
var_dump((string) $type);
38+
$resolvedType = $type->resolveToNamedType();
39+
var_dump((string) $resolvedType);
40+
}
41+
42+
?>
43+
--EXPECT--
44+
bool(true)
45+
bool(true)
46+
string(16) "ReflectionMethod"
47+
string(4) "self"
48+
string(1) "B"
49+
bool(true)
50+
bool(true)
51+
string(16) "ReflectionMethod"
52+
string(6) "parent"
53+
string(1) "A"
54+
bool(true)
55+
bool(true)
56+
string(16) "ReflectionMethod"
57+
string(6) "static"
58+
string(1) "C"

0 commit comments

Comments
 (0)