Add ReflectionConstant::getFileName()

Allow determining the name of the file that defined a constant, when the
constant was defined in userland code via const or define(). For constants
defined by PHP core or extensions, false is returned, matching the existing
getFileName() methods on other reflection classes.

Fixes GH-15723
Closes GH-15847
This commit is contained in:
Daniel Scherzer 2024-09-11 18:43:47 -07:00 committed by Ilija Tovilo
parent 94ac1cd1df
commit f5e743a520
No known key found for this signature in database
GPG Key ID: 5050C66BFCD1015A
9 changed files with 98 additions and 1 deletions

View File

@ -88,6 +88,9 @@ PHP 8.5 UPGRADE NOTES
statement from the DEALLOCATE sql command in that we can reuse
its name afterwards.
- Reflection:
. ReflectionConstant::getFileName() was introduced.
========================================
7. New Classes and Interfaces
========================================

View File

@ -46,12 +46,18 @@ void free_zend_constant(zval *zv)
if (c->name) {
zend_string_release_ex(c->name, 0);
}
if (c->filename) {
zend_string_release_ex(c->filename, 0);
}
efree(c);
} else {
zval_internal_ptr_dtor(&c->value);
if (c->name) {
zend_string_release_ex(c->name, 1);
}
if (c->filename) {
zend_string_release_ex(c->filename, 1);
}
free(c);
}
}
@ -68,6 +74,9 @@ static void copy_zend_constant(zval *zv)
c = Z_PTR_P(zv);
c->name = zend_string_copy(c->name);
if (c->filename != NULL) {
c->filename = zend_string_copy(c->filename);
}
if (Z_TYPE(c->value) == IS_STRING) {
Z_STR(c->value) = zend_string_dup(Z_STR(c->value), 1);
}
@ -495,6 +504,13 @@ ZEND_API zend_result zend_register_constant(zend_constant *c)
name = c->name;
}
zend_string *filename = zend_get_executed_filename_ex();
if (filename == NULL) {
c->filename = NULL;
} else {
c->filename = zend_string_copy(filename);
}
/* Check if the user is trying to define any special constant */
if (zend_string_equals_literal(name, "__COMPILER_HALT_OFFSET__")
|| (!persistent && zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)))
@ -502,6 +518,10 @@ ZEND_API zend_result zend_register_constant(zend_constant *c)
) {
zend_error(E_WARNING, "Constant %s already defined", ZSTR_VAL(name));
zend_string_release(c->name);
if (c->filename) {
zend_string_release(c->filename);
c->filename = NULL;
}
if (!persistent) {
zval_ptr_dtor_nogc(&c->value);
}

View File

@ -33,6 +33,7 @@
typedef struct _zend_constant {
zval value;
zend_string *name;
zend_string *filename;
} zend_constant;
#define ZEND_CONSTANT_FLAGS(c) \

View File

@ -299,6 +299,9 @@ ZEND_API void zend_shutdown_executor_values(bool fast_shutdown)
if (c->name) {
zend_string_release_ex(c->name, 0);
}
if (c->filename) {
zend_string_release_ex(c->filename, 0);
}
efree(c);
zend_string_release_ex(key, 0);
} ZEND_HASH_MAP_FOREACH_END_DEL();

View File

@ -7553,6 +7553,20 @@ ZEND_METHOD(ReflectionConstant, isDeprecated)
RETURN_BOOL(ZEND_CONSTANT_FLAGS(const_) & CONST_DEPRECATED);
}
ZEND_METHOD(ReflectionConstant, getFileName)
{
reflection_object *intern;
zend_constant *const_;
ZEND_PARSE_PARAMETERS_NONE();
GET_REFLECTION_OBJECT_PTR(const_);
if (const_->filename != NULL) {
RETURN_STR_COPY(const_->filename);
}
RETURN_FALSE;
}
ZEND_METHOD(ReflectionConstant, __toString)
{
reflection_object *intern;

View File

@ -916,5 +916,7 @@ final class ReflectionConstant implements Reflector
public function isDeprecated(): bool {}
public function getFileName(): string|false {}
public function __toString(): string {}
}

View File

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: e6a47b9a496c588bd6f4611cd9a1226bb93052b4 */
* Stub hash: 603181d7e1d8292ef694913d4495d3cbb9dd7798 */
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0)
ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0)
@ -705,6 +705,9 @@ ZEND_END_ARG_INFO()
#define arginfo_class_ReflectionConstant_isDeprecated arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_ReflectionConstant_getFileName, 0, 0, MAY_BE_STRING|MAY_BE_FALSE)
ZEND_END_ARG_INFO()
#define arginfo_class_ReflectionConstant___toString arginfo_class_ReflectionFunction___toString
ZEND_METHOD(Reflection, getModifierNames);
@ -971,6 +974,7 @@ ZEND_METHOD(ReflectionConstant, getNamespaceName);
ZEND_METHOD(ReflectionConstant, getShortName);
ZEND_METHOD(ReflectionConstant, getValue);
ZEND_METHOD(ReflectionConstant, isDeprecated);
ZEND_METHOD(ReflectionConstant, getFileName);
ZEND_METHOD(ReflectionConstant, __toString);
static const zend_function_entry class_Reflection_methods[] = {
@ -1336,6 +1340,7 @@ static const zend_function_entry class_ReflectionConstant_methods[] = {
ZEND_ME(ReflectionConstant, getShortName, arginfo_class_ReflectionConstant_getShortName, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionConstant, getValue, arginfo_class_ReflectionConstant_getValue, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionConstant, isDeprecated, arginfo_class_ReflectionConstant_isDeprecated, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionConstant, getFileName, arginfo_class_ReflectionConstant_getFileName, ZEND_ACC_PUBLIC)
ZEND_ME(ReflectionConstant, __toString, arginfo_class_ReflectionConstant___toString, ZEND_ACC_PUBLIC)
ZEND_FE_END
};

View File

@ -0,0 +1,44 @@
--TEST--
ReflectionConstant::getFileName()
--FILE--
<?php
include "included5.inc";
function testConstant(string $name): void {
$ref = new ReflectionConstant($name);
echo "$name: ";
var_dump($ref->getFileName());
}
define('IN_CURRENT_FILE_DEFINED', 42);
const IN_CURRENT_FILE_AST = 123;
echo "From PHP:\n";
testConstant('PHP_VERSION');
testConstant('STDIN');
testConstant('STDOUT');
testConstant('STDERR');
echo "\nFrom the current file:\n";
testConstant('IN_CURRENT_FILE_DEFINED');
testConstant('IN_CURRENT_FILE_AST');
echo "\nFrom an included file:\n";
testConstant('INCLUDED_CONSTANT_DEFINED');
testConstant('INCLUDED_CONSTANT_AST');
?>
--EXPECTF--
From PHP:
PHP_VERSION: bool(false)
STDIN: bool(false)
STDOUT: bool(false)
STDERR: bool(false)
From the current file:
IN_CURRENT_FILE_DEFINED: string(%d) "%sReflectionConstant_getFileName.php"
IN_CURRENT_FILE_AST: string(%d) "%sReflectionConstant_getFileName.php"
From an included file:
INCLUDED_CONSTANT_DEFINED: string(%d) "%sincluded5.inc"
INCLUDED_CONSTANT_AST: string(%d) "%sincluded5.inc"

View File

@ -0,0 +1,5 @@
<?php
define('INCLUDED_CONSTANT_DEFINED', 'Foo');
const INCLUDED_CONSTANT_AST = 'Bar';
?>