Skip to content

Commit a1cc091

Browse files
authored
reflection: Fix the return value of ReflectionFunction::{getNamespaceName,inNamespace}() for closures (#16129)
* reflection: Fix the return value of ReflectionFunction::{getNamespaceName,inNamespace}() for closures Fixes GH-16122 * reflection: Clean up implementation of `ReflectionFunctionAbstract::inNamespace()` * reflection: Clean up implementation of `ReflectionFunctionAbstract::getNamespaceName()`
1 parent ebee8df commit a1cc091

File tree

4 files changed

+38
-2
lines changed

4 files changed

+38
-2
lines changed

NEWS

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ PHP NEWS
3737
. Fixed bug GH-16009 (Segmentation fault with frameless functions and
3838
undefined CVs). (nielsdos)
3939

40+
- Reflection:
41+
. Fixed bug GH-16122 (The return value of ReflectionFunction::getNamespaceName()
42+
and ReflectionFunction::inNamespace() for closures is incorrect). (timwolla)
43+
4044
- SAPI:
4145
. Fixed bug GHSA-9pqp-7h25-4f32 (Erroneous parsing of multipart form data).
4246
(CVE-2024-8925) (Arnaud)

Zend/tests/closure_067.phpt

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
ReflectionFunction::getShortName() returns the full name for closures defined in namespaces.
2+
ReflectionFunction::get{Short,Namespace}Name() and inNamespace() return the correct data for closures defined in namespaces.
33
--FILE--
44
<?php
55
namespace Foo;
@@ -14,7 +14,17 @@ class Bar {
1414

1515
$c = (new Bar())->baz();
1616
$r = new \ReflectionFunction($c);
17+
// Closures are not inside of a namespace, thus the short name is the full name.
1718
var_dump($r->getShortName());
19+
// The namespace is empty.
20+
var_dump($r->getNamespaceName());
21+
// The function is not inside of a namespace.
22+
var_dump($r->inNamespace());
23+
// And the namespace name + the short name together must be the full name.
24+
var_dump($r->getNamespaceName() . ($r->inNamespace() ? '\\' : '') . $r->getShortName() === $r->getName());
1825
?>
1926
--EXPECT--
2027
string(26) "{closure:Foo\Bar::baz():6}"
28+
string(0) ""
29+
bool(false)
30+
bool(true)

Zend/tests/closure_068.phpt

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
--TEST--
2-
ReflectionFunction::getShortName() returns the short name for first class callables defined in namespaces.
2+
ReflectionFunction::get{Short,Namespace}Name() and inNamespace() return the correct data for first class callables defined in namespaces.
33
--FILE--
44
<?php
55
namespace Foo;
66

77
function foo() {
88
}
99
$r = new \ReflectionFunction(foo(...));
10+
$r2 = new \ReflectionFunction('Foo\\foo');
1011
var_dump($r->getShortName());
12+
var_dump($r->getNamespaceName());
13+
var_dump($r->inNamespace());
14+
var_dump($r->getNamespaceName() . ($r->inNamespace() ? '\\' : '') . $r->getShortName() === $r->getName());
15+
16+
var_dump($r->getShortName() === $r2->getShortName());
17+
var_dump($r->getNamespaceName() === $r2->getNamespaceName());
18+
var_dump($r->inNamespace() === $r2->inNamespace());
1119
?>
1220
--EXPECT--
1321
string(3) "foo"
22+
string(3) "Foo"
23+
bool(true)
24+
bool(true)
25+
bool(true)
26+
bool(true)
27+
bool(true)

ext/reflection/php_reflection.c

+8
Original file line numberDiff line numberDiff line change
@@ -3584,6 +3584,10 @@ ZEND_METHOD(ReflectionFunctionAbstract, inNamespace)
35843584

35853585
GET_REFLECTION_OBJECT_PTR(fptr);
35863586

3587+
if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
3588+
RETURN_FALSE;
3589+
}
3590+
35873591
zend_string *name = fptr->common.function_name;
35883592
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
35893593
RETURN_BOOL(backslash);
@@ -3602,6 +3606,10 @@ ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName)
36023606

36033607
GET_REFLECTION_OBJECT_PTR(fptr);
36043608

3609+
if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
3610+
RETURN_EMPTY_STRING();
3611+
}
3612+
36053613
zend_string *name = fptr->common.function_name;
36063614
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
36073615
if (backslash) {

0 commit comments

Comments
 (0)