Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1dea063

Browse files
Implement reflection constant
Fixes GH-13570
1 parent bc59e79 commit 1dea063

13 files changed

+453
-5
lines changed

‎Zend/zend_constants.c‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
275275
return NULL;
276276
}
277277

278-
static zend_constant *zend_get_constant_impl(zend_string *name)
278+
ZEND_API zend_constant *zend_get_constant_ptr(zend_string *name)
279279
{
280280
zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
281281
if (c) {
@@ -292,7 +292,7 @@ static zend_constant *zend_get_constant_impl(zend_string *name)
292292

293293
ZEND_API zval *zend_get_constant(zend_string *name)
294294
{
295-
zend_constant *c = zend_get_constant_impl(name);
295+
zend_constant *c = zend_get_constant_ptr(name);
296296
if (c) {
297297
return &c->value;
298298
}
@@ -521,7 +521,7 @@ ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope,
521521
}
522522
} else {
523523
if (cname) {
524-
c = zend_get_constant_impl(cname);
524+
c = zend_get_constant_ptr(cname);
525525
} else {
526526
c = zend_get_constant_str_impl(name, name_len);
527527
}

‎Zend/zend_constants.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void zend_shutdown_constants(void);
7575
void zend_register_standard_constants(void);
7676
ZEND_API bool zend_verify_const_access(zend_class_constant *c, zend_class_entry *ce);
7777
ZEND_API zval *zend_get_constant(zend_string *name);
78+
ZEND_API zend_constant *zend_get_constant_ptr(zend_string *name);
7879
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len);
7980
ZEND_API zval *zend_get_constant_ex(zend_string *name, zend_class_entry *scope, uint32_t flags);
8081
ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string *constant_name, zend_class_entry *scope, uint32_t flags);

‎ext/reflection/php_reflection.c‎

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ PHPAPI zend_class_entry *reflection_enum_ptr;
9797
PHPAPI zend_class_entry *reflection_enum_unit_case_ptr;
9898
PHPAPI zend_class_entry *reflection_enum_backed_case_ptr;
9999
PHPAPI zend_class_entry *reflection_fiber_ptr;
100+
PHPAPI zend_class_entry *reflection_constant_ptr;
100101

101102
/* Exception throwing macro */
102103
#define _DO_THROW(msg) \
@@ -1250,6 +1251,19 @@ static void _zend_extension_string(smart_str *str, zend_extension *extension, ch
12501251
}
12511252
/* }}} */
12521253

1254+
static void _const_decl_string(smart_str *str, zend_constant *const_)
1255+
{
1256+
smart_str_append_printf(str, "Const [ ");
1257+
if (ZEND_CONSTANT_FLAGS(const_) & CONST_DEPRECATED) {
1258+
smart_str_append_printf(str, "<deprecated> ");
1259+
}
1260+
smart_str_append_printf(str, "%s = ", ZSTR_VAL(const_->name));
1261+
if (format_default_value(str, &const_->value) == FAILURE) {
1262+
return;
1263+
}
1264+
smart_str_appends(str, " ]\n");
1265+
}
1266+
12531267
/* {{{ _function_check_flag */
12541268
static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
12551269
{
@@ -7207,6 +7221,140 @@ static zval *_reflection_write_property(zend_object *object, zend_string *name,
72077221
}
72087222
/* }}} */
72097223

7224+
ZEND_METHOD(ReflectionConstant, __construct)
7225+
{
7226+
zend_string *name;
7227+
7228+
zval *object = ZEND_THIS;
7229+
reflection_object *intern = Z_REFLECTION_P(object);
7230+
7231+
ZEND_PARSE_PARAMETERS_START(1, 1)
7232+
Z_PARAM_STR(name)
7233+
ZEND_PARSE_PARAMETERS_END();
7234+
7235+
/* Build name with lowercased ns. */
7236+
bool backslash_prefixed = ZSTR_VAL(name)[0] == '\\';
7237+
char *source = ZSTR_VAL(name) + backslash_prefixed;
7238+
size_t source_len = ZSTR_LEN(name) - backslash_prefixed;
7239+
zend_string *lc_name = zend_string_alloc(source_len, /* persistent */ false);
7240+
const char *ns_end = zend_memrchr(source, '\\', source_len);
7241+
size_t ns_len = 0;
7242+
if (ns_end) {
7243+
ns_len = ns_end - ZSTR_VAL(name);
7244+
zend_str_tolower_copy(ZSTR_VAL(lc_name), source, ns_len);
7245+
}
7246+
memcpy(ZSTR_VAL(lc_name) + ns_len, source + ns_len, source_len - ns_len);
7247+
7248+
zend_constant *const_ = zend_get_constant_ptr(lc_name);
7249+
zend_string_release_ex(lc_name, /* persistent */ false);
7250+
if (!const_) {
7251+
zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant \"%s\" does not exist", ZSTR_VAL(name));
7252+
RETURN_THROWS();
7253+
}
7254+
7255+
intern->ptr = const_;
7256+
intern->ref_type = REF_TYPE_OTHER;
7257+
7258+
zval *name_zv = reflection_prop_name(object);
7259+
zval_ptr_dtor(name_zv);
7260+
ZVAL_STR_COPY(name_zv, name);
7261+
}
7262+
7263+
ZEND_METHOD(ReflectionConstant, getName)
7264+
{
7265+
reflection_object *intern;
7266+
zend_constant *const_;
7267+
7268+
if (zend_parse_parameters_none() == FAILURE) {
7269+
RETURN_THROWS();
7270+
}
7271+
7272+
GET_REFLECTION_OBJECT_PTR(const_);
7273+
RETURN_STR_COPY(const_->name);
7274+
}
7275+
7276+
ZEND_METHOD(ReflectionConstant, getNamespaceName)
7277+
{
7278+
reflection_object *intern;
7279+
zend_constant *const_;
7280+
7281+
if (zend_parse_parameters_none() == FAILURE) {
7282+
RETURN_THROWS();
7283+
}
7284+
7285+
GET_REFLECTION_OBJECT_PTR(const_);
7286+
7287+
const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
7288+
if (backslash) {
7289+
size_t length = backslash - ZSTR_VAL(const_->name);
7290+
RETURN_STRINGL(ZSTR_VAL(const_->name), length);
7291+
} else {
7292+
RETURN_EMPTY_STRING();
7293+
}
7294+
}
7295+
7296+
ZEND_METHOD(ReflectionConstant, getShortName)
7297+
{
7298+
reflection_object *intern;
7299+
zend_constant *const_;
7300+
7301+
if (zend_parse_parameters_none() == FAILURE) {
7302+
RETURN_THROWS();
7303+
}
7304+
7305+
GET_REFLECTION_OBJECT_PTR(const_);
7306+
7307+
const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
7308+
if (backslash) {
7309+
size_t prefix = backslash - ZSTR_VAL(const_->name) + 1;
7310+
size_t length = ZSTR_LEN(const_->name) - prefix;
7311+
RETURN_STRINGL(ZSTR_VAL(const_->name) + prefix, length);
7312+
} else {
7313+
RETURN_STR_COPY(const_->name);
7314+
}
7315+
}
7316+
7317+
ZEND_METHOD(ReflectionConstant, getValue)
7318+
{
7319+
reflection_object *intern;
7320+
zend_constant *const_;
7321+
7322+
if (zend_parse_parameters_none() == FAILURE) {
7323+
RETURN_THROWS();
7324+
}
7325+
7326+
GET_REFLECTION_OBJECT_PTR(const_);
7327+
RETURN_COPY(&const_->value);
7328+
}
7329+
7330+
ZEND_METHOD(ReflectionConstant, isDeprecated)
7331+
{
7332+
reflection_object *intern;
7333+
zend_constant *const_;
7334+
7335+
if (zend_parse_parameters_none() == FAILURE) {
7336+
RETURN_THROWS();
7337+
}
7338+
7339+
GET_REFLECTION_OBJECT_PTR(const_);
7340+
RETURN_BOOL(ZEND_CONSTANT_FLAGS(const_) & CONST_DEPRECATED);
7341+
}
7342+
7343+
ZEND_METHOD(ReflectionConstant, __toString)
7344+
{
7345+
reflection_object *intern;
7346+
zend_constant *const_;
7347+
smart_str str = {0};
7348+
7349+
if (zend_parse_parameters_none() == FAILURE) {
7350+
RETURN_THROWS();
7351+
}
7352+
7353+
GET_REFLECTION_OBJECT_PTR(const_);
7354+
_const_decl_string(&str, const_);
7355+
RETURN_STR(smart_str_extract(&str));
7356+
}
7357+
72107358
PHP_MINIT_FUNCTION(reflection) /* {{{ */
72117359
{
72127360
memcpy(&reflection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
@@ -7306,6 +7454,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
73067454
reflection_fiber_ptr->create_object = reflection_objects_new;
73077455
reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers;
73087456

7457+
reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr);
7458+
reflection_constant_ptr->create_object = reflection_objects_new;
7459+
reflection_constant_ptr->default_object_handlers = &reflection_object_handlers;
7460+
73097461
REFLECTION_G(key_initialized) = 0;
73107462

73117463
return SUCCESS;

‎ext/reflection/php_reflection.stub.php‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,3 +826,26 @@ public function getCallable(): callable {}
826826

827827
public function getTrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT): array {}
828828
}
829+
830+
/**
831+
* @strict-properties
832+
* @not-serializable
833+
*/
834+
final class ReflectionConstant implements Reflector
835+
{
836+
public string $name;
837+
838+
public function __construct(string $name) {}
839+
840+
public function getName(): string {}
841+
842+
public function getNamespaceName(): string {}
843+
844+
public function getShortName(): string {}
845+
846+
public function getValue(): mixed {}
847+
848+
public function isDeprecated(): bool {}
849+
850+
public function __toString(): string {}
851+
}

‎ext/reflection/php_reflection_arginfo.h‎

Lines changed: 52 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
ReflectionConstant double construct call
3+
--FILE--
4+
<?php
5+
6+
const C1 = 42;
7+
const C2 = 43;
8+
9+
$r = new ReflectionConstant('C' . mt_rand(1, 1));
10+
var_dump($r);
11+
12+
$r->__construct('C' . mt_rand(2, 2));
13+
var_dump($r);
14+
15+
?>
16+
--EXPECT--
17+
object(ReflectionConstant)#1 (1) {
18+
["name"]=>
19+
string(2) "C1"
20+
}
21+
object(ReflectionConstant)#1 (1) {
22+
["name"]=>
23+
string(2) "C2"
24+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--TEST--
2+
var_dump(ReflectionConstant)
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
define('RT_CONST', 42);
9+
const CT_CONST = [
10+
'foo' => 'foo',
11+
'bar' => ['bar'],
12+
];
13+
14+
function dump($r) {
15+
var_dump($r);
16+
echo $r;
17+
}
18+
19+
dump(new ReflectionConstant('ZEND_CONSTANT_A'));
20+
dump(new ReflectionConstant('ZEND_TEST_DEPRECATED'));
21+
dump(new ReflectionConstant('RT_CONST'));
22+
dump(new ReflectionConstant('CT_CONST'));
23+
24+
?>
25+
--EXPECT--
26+
object(ReflectionConstant)#1 (1) {
27+
["name"]=>
28+
string(15) "ZEND_CONSTANT_A"
29+
}
30+
Const [ ZEND_CONSTANT_A = 'global' ]
31+
object(ReflectionConstant)#1 (1) {
32+
["name"]=>
33+
string(20) "ZEND_TEST_DEPRECATED"
34+
}
35+
Const [ <deprecated> ZEND_TEST_DEPRECATED = 42 ]
36+
object(ReflectionConstant)#1 (1) {
37+
["name"]=>
38+
string(8) "RT_CONST"
39+
}
40+
Const [ RT_CONST = 42 ]
41+
object(ReflectionConstant)#1 (1) {
42+
["name"]=>
43+
string(8) "CT_CONST"
44+
}
45+
Const [ CT_CONST = ['foo' => 'foo', 'bar' => ['bar']] ]

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /