Skip to content

Commit 9f29e2d

Browse files
committed
Allow for arbitrary (class) attributes in stubs
This can be easily extended to other types of attributes. Closes #8839.
1 parent 82bcc94 commit 9f29e2d

10 files changed

+282
-57
lines changed

Zend/zend_attributes.c

+26-23
Original file line numberDiff line numberDiff line change
@@ -317,27 +317,39 @@ static void free_internal_attribute(zval *v)
317317
pefree(Z_PTR_P(v), 1);
318318
}
319319

320-
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
320+
ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce)
321321
{
322322
zend_internal_attribute *internal_attr;
323+
zend_attribute *attr;
323324

324325
if (ce->type != ZEND_INTERNAL_CLASS) {
325326
zend_error_noreturn(E_ERROR, "Only internal classes can be registered as compiler attribute");
326327
}
327328

328-
internal_attr = pemalloc(sizeof(zend_internal_attribute), 1);
329-
internal_attr->ce = ce;
330-
internal_attr->flags = flags;
331-
internal_attr->validator = NULL;
329+
ZEND_HASH_FOREACH_PTR(ce->attributes, attr) {
330+
if (zend_string_equals(attr->name, zend_ce_attribute->name)) {
331+
internal_attr = pemalloc(sizeof(zend_internal_attribute), 1);
332+
internal_attr->ce = ce;
333+
internal_attr->flags = Z_LVAL(attr->args[0].value);
334+
internal_attr->validator = NULL;
332335

333-
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
336+
zend_string *lcname = zend_string_tolower_ex(ce->name, 1);
337+
zend_hash_update_ptr(&internal_attributes, lcname, internal_attr);
338+
zend_string_release(lcname);
334339

335-
zend_hash_update_ptr(&internal_attributes, lcname, internal_attr);
340+
return internal_attr;
341+
}
342+
} ZEND_HASH_FOREACH_END();
343+
344+
zend_error_noreturn(E_ERROR, "Classes must be first marked as attribute before being able to be registered as internal attribute class");
345+
}
346+
347+
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags)
348+
{
336349
zend_attribute *attr = zend_add_class_attribute(ce, zend_ce_attribute->name, 1);
337350
ZVAL_LONG(&attr->args[0].value, flags);
338-
zend_string_release(lcname);
339351

340-
return internal_attr;
352+
return zend_mark_internal_attribute(ce);
341353
}
342354

343355
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname)
@@ -352,32 +364,23 @@ void zend_register_attribute_ce(void)
352364
zend_hash_init(&internal_attributes, 8, NULL, free_internal_attribute, 1);
353365

354366
zend_ce_attribute = register_class_Attribute();
355-
attr = zend_internal_attribute_register(zend_ce_attribute, ZEND_ATTRIBUTE_TARGET_CLASS);
367+
attr = zend_mark_internal_attribute(zend_ce_attribute);
356368
attr->validator = validate_attribute;
357369

358-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS"), ZEND_ATTRIBUTE_TARGET_CLASS);
359-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_FUNCTION"), ZEND_ATTRIBUTE_TARGET_FUNCTION);
360-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_METHOD"), ZEND_ATTRIBUTE_TARGET_METHOD);
361-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PROPERTY"), ZEND_ATTRIBUTE_TARGET_PROPERTY);
362-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_CLASS_CONSTANT"), ZEND_ATTRIBUTE_TARGET_CLASS_CONST);
363-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_PARAMETER"), ZEND_ATTRIBUTE_TARGET_PARAMETER);
364-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("TARGET_ALL"), ZEND_ATTRIBUTE_TARGET_ALL);
365-
zend_declare_class_constant_long(zend_ce_attribute, ZEND_STRL("IS_REPEATABLE"), ZEND_ATTRIBUTE_IS_REPEATABLE);
366-
367370
zend_ce_return_type_will_change_attribute = register_class_ReturnTypeWillChange();
368-
zend_internal_attribute_register(zend_ce_return_type_will_change_attribute, ZEND_ATTRIBUTE_TARGET_METHOD);
371+
zend_mark_internal_attribute(zend_ce_return_type_will_change_attribute);
369372

370373
zend_ce_allow_dynamic_properties = register_class_AllowDynamicProperties();
371-
attr = zend_internal_attribute_register(zend_ce_allow_dynamic_properties, ZEND_ATTRIBUTE_TARGET_CLASS);
374+
attr = zend_mark_internal_attribute(zend_ce_allow_dynamic_properties);
372375
attr->validator = validate_allow_dynamic_properties;
373376

374377
zend_ce_sensitive_parameter = register_class_SensitiveParameter();
375-
attr = zend_internal_attribute_register(zend_ce_sensitive_parameter, ZEND_ATTRIBUTE_TARGET_PARAMETER);
378+
zend_mark_internal_attribute(zend_ce_sensitive_parameter);
376379

377380
memcpy(&attributes_object_handlers_sensitive_parameter_value, &std_object_handlers, sizeof(zend_object_handlers));
378381
attributes_object_handlers_sensitive_parameter_value.get_properties_for = attributes_sensitive_parameter_value_get_properties_for;
379382

380-
/* This is not an actual attribute, thus the zend_internal_attribute_register() call is missing. */
383+
/* This is not an actual attribute, thus the zend_mark_internal_attribute() call is missing. */
381384
zend_ce_sensitive_parameter_value = register_class_SensitiveParameterValue();
382385
zend_ce_sensitive_parameter_value->create_object = attributes_sensitive_parameter_value_new;
383386
}

Zend/zend_attributes.h

+1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ ZEND_API zend_result zend_get_attribute_value(zval *ret, zend_attribute *attr, u
7777
ZEND_API zend_string *zend_get_attribute_target_names(uint32_t targets);
7878
ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *attr);
7979

80+
ZEND_API zend_internal_attribute *zend_mark_internal_attribute(zend_class_entry *ce);
8081
ZEND_API zend_internal_attribute *zend_internal_attribute_register(zend_class_entry *ce, uint32_t flags);
8182
ZEND_API zend_internal_attribute *zend_internal_attribute_get(zend_string *lcname);
8283

Zend/zend_attributes.stub.php

+45
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,62 @@
22

33
/** @generate-class-entries */
44

5+
#[Attribute(Attribute::TARGET_CLASS)]
56
final class Attribute
67
{
8+
/**
9+
* @var int
10+
* @cname ZEND_ATTRIBUTE_TARGET_CLASS
11+
*/
12+
const TARGET_CLASS = UNKNOWN;
13+
/**
14+
* @var int
15+
* @cname ZEND_ATTRIBUTE_TARGET_FUNCTION
16+
*/
17+
const TARGET_FUNCTION = UNKNOWN;
18+
/**
19+
* @var int
20+
* @cname ZEND_ATTRIBUTE_TARGET_METHOD
21+
*/
22+
const TARGET_METHOD = UNKNOWN;
23+
/**
24+
* @var int
25+
* @cname ZEND_ATTRIBUTE_TARGET_PROPERTY
26+
*/
27+
const TARGET_PROPERTY = UNKNOWN;
28+
/**
29+
* @var int
30+
* @cname ZEND_ATTRIBUTE_TARGET_CLASS_CONST
31+
*/
32+
const TARGET_CLASS_CONSTANT = UNKNOWN;
33+
/**
34+
* @var int
35+
* @cname ZEND_ATTRIBUTE_TARGET_PARAMETER
36+
*/
37+
const TARGET_PARAMETER = UNKNOWN;
38+
/**
39+
* @var int
40+
* @cname ZEND_ATTRIBUTE_TARGET_ALL
41+
*/
42+
const TARGET_ALL = UNKNOWN;
43+
/**
44+
* @var int
45+
* @cname ZEND_ATTRIBUTE_IS_REPEATABLE
46+
*/
47+
const IS_REPEATABLE = UNKNOWN;
48+
749
public int $flags;
850

951
public function __construct(int $flags = Attribute::TARGET_ALL) {}
1052
}
1153

54+
#[Attribute(Attribute::TARGET_METHOD)]
1255
final class ReturnTypeWillChange
1356
{
1457
public function __construct() {}
1558
}
1659

60+
#[Attribute(Attribute::TARGET_CLASS)]
1761
final class AllowDynamicProperties
1862
{
1963
public function __construct() {}
@@ -22,6 +66,7 @@ public function __construct() {}
2266
/**
2367
* @strict-properties
2468
*/
69+
#[Attribute(Attribute::TARGET_PARAMETER)]
2570
final class SensitiveParameter
2671
{
2772
public function __construct() {}

Zend/zend_attributes_arginfo.h

+77-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_builtin_functions_arginfo.h

+4-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)