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()`
This commit is contained in:
Tim Düsterhus 2024-09-30 16:33:46 +02:00 committed by GitHub
parent ebee8df27e
commit a1cc091808
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 38 additions and 2 deletions

4
NEWS
View file

@ -37,6 +37,10 @@ PHP NEWS
. Fixed bug GH-16009 (Segmentation fault with frameless functions and . Fixed bug GH-16009 (Segmentation fault with frameless functions and
undefined CVs). (nielsdos) undefined CVs). (nielsdos)
- Reflection:
. Fixed bug GH-16122 (The return value of ReflectionFunction::getNamespaceName()
and ReflectionFunction::inNamespace() for closures is incorrect). (timwolla)
- SAPI: - SAPI:
. Fixed bug GHSA-9pqp-7h25-4f32 (Erroneous parsing of multipart form data). . Fixed bug GHSA-9pqp-7h25-4f32 (Erroneous parsing of multipart form data).
(CVE-2024-8925) (Arnaud) (CVE-2024-8925) (Arnaud)

View file

@ -1,5 +1,5 @@
--TEST-- --TEST--
ReflectionFunction::getShortName() returns the full name for closures defined in namespaces. ReflectionFunction::get{Short,Namespace}Name() and inNamespace() return the correct data for closures defined in namespaces.
--FILE-- --FILE--
<?php <?php
namespace Foo; namespace Foo;
@ -14,7 +14,17 @@ class Bar {
$c = (new Bar())->baz(); $c = (new Bar())->baz();
$r = new \ReflectionFunction($c); $r = new \ReflectionFunction($c);
// Closures are not inside of a namespace, thus the short name is the full name.
var_dump($r->getShortName()); var_dump($r->getShortName());
// The namespace is empty.
var_dump($r->getNamespaceName());
// The function is not inside of a namespace.
var_dump($r->inNamespace());
// And the namespace name + the short name together must be the full name.
var_dump($r->getNamespaceName() . ($r->inNamespace() ? '\\' : '') . $r->getShortName() === $r->getName());
?> ?>
--EXPECT-- --EXPECT--
string(26) "{closure:Foo\Bar::baz():6}" string(26) "{closure:Foo\Bar::baz():6}"
string(0) ""
bool(false)
bool(true)

View file

@ -1,5 +1,5 @@
--TEST-- --TEST--
ReflectionFunction::getShortName() returns the short name for first class callables defined in namespaces. ReflectionFunction::get{Short,Namespace}Name() and inNamespace() return the correct data for first class callables defined in namespaces.
--FILE-- --FILE--
<?php <?php
namespace Foo; namespace Foo;
@ -7,7 +7,21 @@ namespace Foo;
function foo() { function foo() {
} }
$r = new \ReflectionFunction(foo(...)); $r = new \ReflectionFunction(foo(...));
$r2 = new \ReflectionFunction('Foo\\foo');
var_dump($r->getShortName()); var_dump($r->getShortName());
var_dump($r->getNamespaceName());
var_dump($r->inNamespace());
var_dump($r->getNamespaceName() . ($r->inNamespace() ? '\\' : '') . $r->getShortName() === $r->getName());
var_dump($r->getShortName() === $r2->getShortName());
var_dump($r->getNamespaceName() === $r2->getNamespaceName());
var_dump($r->inNamespace() === $r2->inNamespace());
?> ?>
--EXPECT-- --EXPECT--
string(3) "foo" string(3) "foo"
string(3) "Foo"
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)

View file

@ -3584,6 +3584,10 @@ ZEND_METHOD(ReflectionFunctionAbstract, inNamespace)
GET_REFLECTION_OBJECT_PTR(fptr); GET_REFLECTION_OBJECT_PTR(fptr);
if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
RETURN_FALSE;
}
zend_string *name = fptr->common.function_name; zend_string *name = fptr->common.function_name;
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
RETURN_BOOL(backslash); RETURN_BOOL(backslash);
@ -3602,6 +3606,10 @@ ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName)
GET_REFLECTION_OBJECT_PTR(fptr); GET_REFLECTION_OBJECT_PTR(fptr);
if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
RETURN_EMPTY_STRING();
}
zend_string *name = fptr->common.function_name; zend_string *name = fptr->common.function_name;
const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
if (backslash) { if (backslash) {