Skip to content

Commit ee4a2b7

Browse files
[RFC] ReflectionAttribute::getCurrent()
1 parent 92ba1e4 commit ee4a2b7

17 files changed

+580
-53
lines changed

ext/reflection/php_reflection.c

Lines changed: 171 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static zend_always_inline zval *reflection_prop_class(zval *object) {
8080

8181
/* Class entry pointers */
8282
PHPAPI zend_class_entry *reflector_ptr;
83+
PHPAPI zend_class_entry *reflection_attribute_target_ptr;
8384
PHPAPI zend_class_entry *reflection_exception_ptr;
8485
PHPAPI zend_class_entry *reflection_ptr;
8586
PHPAPI zend_class_entry *reflection_function_abstract_ptr;
@@ -146,13 +147,39 @@ typedef struct _type_reference {
146147
bool legacy_behavior;
147148
} type_reference;
148149

150+
// Based on the target
151+
// TARGET_CLASS: zend_class_entry
152+
// TARGET_FUNCTION: zend_function
153+
// TARGET_METHOD: zend_function
154+
// TARGET_PROPERTY: zend_property_info
155+
// TARGET_CLASS_CONST: zend_class_constant and its name which isn't a part of
156+
// the struct
157+
// TARGET_PARAMETER: target function, closure (or null), and offset
158+
// TARGET_CONST: zend_constant
159+
typedef union _attribute_target_reference {
160+
zend_class_entry *target_class;
161+
zend_function *target_function;
162+
zend_property_info *target_property;
163+
zend_constant *target_const;
164+
struct {
165+
zend_class_constant *constant;
166+
zend_string *name;
167+
} target_class_constant;
168+
struct {
169+
zend_function *target_function;
170+
zval *closure_obj;
171+
uint32_t offset;
172+
} target_parameter;
173+
} attribute_target_reference;
174+
149175
/* Struct for attributes */
150176
typedef struct _attribute_reference {
151177
HashTable *attributes;
152178
zend_attribute *data;
153179
zend_class_entry *scope;
154180
zend_string *filename;
155181
uint32_t target;
182+
attribute_target_reference target_data;
156183
} attribute_reference;
157184

158185
typedef enum {
@@ -1243,7 +1270,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c
12431270

12441271
/* {{{ reflection_attribute_factory */
12451272
static void reflection_attribute_factory(zval *object, HashTable *attributes, zend_attribute *data,
1246-
zend_class_entry *scope, uint32_t target, zend_string *filename)
1273+
zend_class_entry *scope, uint32_t target, zend_string *filename, attribute_target_reference target_data)
12471274
{
12481275
reflection_object *intern;
12491276
attribute_reference *reference;
@@ -1256,14 +1283,16 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze
12561283
reference->scope = scope;
12571284
reference->filename = filename ? zend_string_copy(filename) : NULL;
12581285
reference->target = target;
1286+
reference->target_data = target_data;
12591287
intern->ptr = reference;
12601288
intern->ref_type = REF_TYPE_ATTRIBUTE;
12611289
ZVAL_STR_COPY(reflection_prop_name(object), data->name);
12621290
}
12631291
/* }}} */
12641292

12651293
static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope,
1266-
uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename) /* {{{ */
1294+
uint32_t offset, uint32_t target, zend_string *name, zend_class_entry *base, zend_string *filename,
1295+
attribute_target_reference target_data) /* {{{ */
12671296
{
12681297
ZEND_ASSERT(attributes != NULL);
12691298

@@ -1276,7 +1305,7 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_
12761305

12771306
ZEND_HASH_PACKED_FOREACH_PTR(attributes, attr) {
12781307
if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) {
1279-
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1308+
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename, target_data);
12801309
add_next_index_zval(ret, &tmp);
12811310
}
12821311
} ZEND_HASH_FOREACH_END();
@@ -1308,7 +1337,7 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_
13081337
}
13091338
}
13101339

1311-
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1340+
reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename, target_data);
13121341
add_next_index_zval(ret, &tmp);
13131342
} ZEND_HASH_FOREACH_END();
13141343

@@ -1317,7 +1346,8 @@ static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_
13171346
/* }}} */
13181347

13191348
static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes,
1320-
uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */
1349+
uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename,
1350+
attribute_target_reference target_data) /* {{{ */
13211351
{
13221352
zend_string *name = NULL;
13231353
zend_long flags = 0;
@@ -1350,7 +1380,7 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut
13501380

13511381
array_init(return_value);
13521382

1353-
if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) {
1383+
if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename, target_data)) {
13541384
RETURN_THROWS();
13551385
}
13561386
}
@@ -2059,9 +2089,13 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes)
20592089
target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
20602090
}
20612091

2092+
attribute_target_reference ref;
2093+
ref.target_function = fptr;
2094+
20622095
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
20632096
fptr->common.attributes, 0, fptr->common.scope, target,
2064-
fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL);
2097+
fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL,
2098+
ref);
20652099
}
20662100
/* }}} */
20672101

@@ -2870,9 +2904,14 @@ ZEND_METHOD(ReflectionParameter, getAttributes)
28702904
HashTable *attributes = param->fptr->common.attributes;
28712905
zend_class_entry *scope = param->fptr->common.scope;
28722906

2907+
attribute_target_reference ref;
2908+
ref.target_parameter.target_function = param->fptr;
2909+
ref.target_parameter.closure_obj = Z_ISUNDEF(intern->obj) ? NULL : &intern->obj;
2910+
ref.target_parameter.offset = param->offset;
28732911
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
28742912
attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER,
2875-
param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL);
2913+
param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL,
2914+
ref);
28762915
}
28772916

28782917
/* {{{ Returns the index of the parameter, starting from 0 */
@@ -4004,9 +4043,14 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes)
40044043

40054044
GET_REFLECTION_OBJECT_PTR(ref);
40064045

4046+
attribute_target_reference ref_details;
4047+
ref_details.target_class_constant.constant = ref;
4048+
zval *constant_name = reflection_prop_name(ZEND_THIS);
4049+
ref_details.target_class_constant.name = zend_string_copy(Z_STR_P(constant_name));
40074050
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
40084051
ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST,
4009-
ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL);
4052+
ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL,
4053+
ref_details);
40104054
}
40114055
/* }}} */
40124056

@@ -4409,9 +4453,12 @@ ZEND_METHOD(ReflectionClass, getAttributes)
44094453

44104454
GET_REFLECTION_OBJECT_PTR(ce);
44114455

4456+
attribute_target_reference ref;
4457+
ref.target_class = ce;
44124458
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
44134459
ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS,
4414-
ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL);
4460+
ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL,
4461+
ref);
44154462
}
44164463
/* }}} */
44174464

@@ -6357,9 +6404,12 @@ ZEND_METHOD(ReflectionProperty, getAttributes)
63576404
RETURN_EMPTY_ARRAY();
63586405
}
63596406

6407+
attribute_target_reference ref_details;
6408+
ref_details.target_property = ref->prop;
63606409
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
63616410
ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY,
6362-
ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL);
6411+
ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL,
6412+
ref_details);
63636413
}
63646414
/* }}} */
63656415

@@ -7590,6 +7640,105 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
75907640
RETURN_COPY_VALUE(&obj);
75917641
}
75927642

7643+
ZEND_METHOD(ReflectionAttribute, getCurrent)
7644+
{
7645+
ZEND_PARSE_PARAMETERS_NONE();
7646+
7647+
zend_execute_data *prev_ex = EX(prev_execute_data);
7648+
7649+
// Previous: attribute constructor
7650+
// Previous of that: ZEND_ACC_CALL_VIA_TRAMPOLINE call set up by
7651+
// zend_get_attribute_object() to make it look like the call is from
7652+
// where the attribute was declared
7653+
// Previous of *that*: ReflectionAttribute::newInstance()
7654+
if (!prev_ex
7655+
|| !prev_ex->prev_execute_data
7656+
|| !prev_ex->prev_execute_data->prev_execute_data
7657+
|| !prev_ex->prev_execute_data->prev_execute_data->func
7658+
) {
7659+
zend_throw_error(NULL, "Current function was not invoked via ReflectionAttribute::newInstance()");
7660+
RETURN_THROWS();
7661+
}
7662+
zend_execute_data *caller_context = prev_ex->prev_execute_data->prev_execute_data;
7663+
zend_function *caller = caller_context->func;
7664+
if (caller->type != ZEND_INTERNAL_FUNCTION) {
7665+
zend_throw_error(NULL, "Current function was not invoked via ReflectionAttribute::newInstance()");
7666+
RETURN_THROWS();
7667+
}
7668+
zend_internal_function *internal_caller = (zend_internal_function *)caller;
7669+
if (internal_caller->handler != zim_ReflectionAttribute_newInstance) {
7670+
zend_throw_error(NULL, "Current function was not invoked via ReflectionAttribute::newInstance()");
7671+
RETURN_THROWS();
7672+
}
7673+
7674+
zval caller_this = caller_context->This;
7675+
ZEND_ASSERT(Z_TYPE(caller_this) == IS_OBJECT);
7676+
ZEND_ASSERT(Z_OBJCE(caller_this) == reflection_attribute_ptr);
7677+
7678+
reflection_object *intern = Z_REFLECTION_P(&caller_this);
7679+
if (intern->ptr == NULL) {
7680+
if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) {
7681+
RETURN_THROWS();
7682+
}
7683+
zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object");
7684+
RETURN_THROWS();
7685+
}
7686+
attribute_reference *attr = intern->ptr;
7687+
7688+
switch (attr->target) {
7689+
case ZEND_ATTRIBUTE_TARGET_CLASS:
7690+
zend_reflection_class_factory(attr->target_data.target_class, return_value);
7691+
return;
7692+
case ZEND_ATTRIBUTE_TARGET_FUNCTION:
7693+
reflection_function_factory(attr->target_data.target_function, NULL, return_value);
7694+
return;
7695+
case ZEND_ATTRIBUTE_TARGET_METHOD:
7696+
reflection_method_factory(
7697+
attr->target_data.target_function->common.scope,
7698+
attr->target_data.target_function,
7699+
NULL,
7700+
return_value
7701+
);
7702+
return;
7703+
case ZEND_ATTRIBUTE_TARGET_PROPERTY:
7704+
reflection_property_factory(
7705+
attr->target_data.target_property->ce,
7706+
attr->target_data.target_property->name,
7707+
attr->target_data.target_property,
7708+
return_value
7709+
);
7710+
return;
7711+
case ZEND_ATTRIBUTE_TARGET_CLASS_CONST:
7712+
reflection_class_constant_factory(
7713+
attr->target_data.target_class_constant.name,
7714+
attr->target_data.target_class_constant.constant,
7715+
return_value
7716+
);
7717+
return;
7718+
case ZEND_ATTRIBUTE_TARGET_PARAMETER:
7719+
zend_function *target_function = attr->target_data.target_parameter.target_function;
7720+
reflection_parameter_factory(
7721+
_copy_function(target_function),
7722+
attr->target_data.target_parameter.closure_obj,
7723+
target_function->common.arg_info,
7724+
attr->target_data.target_parameter.offset,
7725+
attr->target_data.target_parameter.offset < target_function->common.required_num_args,
7726+
return_value
7727+
);
7728+
return;
7729+
case ZEND_ATTRIBUTE_TARGET_CONST:
7730+
object_init_ex(return_value, reflection_constant_ptr);
7731+
reflection_object *intern = Z_REFLECTION_P(return_value);
7732+
intern->ptr = attr->target_data.target_const;
7733+
intern->ref_type = REF_TYPE_OTHER;
7734+
zval *name_zv = reflection_prop_name(return_value);
7735+
zval_ptr_dtor(name_zv);
7736+
ZVAL_STR_COPY(name_zv, attr->target_data.target_const->name);
7737+
return;
7738+
EMPTY_SWITCH_DEFAULT_CASE()
7739+
}
7740+
}
7741+
75937742
ZEND_METHOD(ReflectionEnum, __construct)
75947743
{
75957744
reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
@@ -8111,9 +8260,11 @@ ZEND_METHOD(ReflectionConstant, getAttributes)
81118260

81128261
GET_REFLECTION_OBJECT_PTR(const_);
81138262

8263+
attribute_target_reference ref;
8264+
ref.target_const = const_;
81148265
reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
81158266
const_->attributes, 0, NULL, ZEND_ATTRIBUTE_TARGET_CONST,
8116-
const_->filename);
8267+
const_->filename, ref);
81178268
}
81188269

81198270
ZEND_METHOD(ReflectionConstant, __toString)
@@ -8144,7 +8295,9 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
81448295

81458296
reflector_ptr = register_class_Reflector(zend_ce_stringable);
81468297

8147-
reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr);
8298+
reflection_attribute_target_ptr = register_class_ReflectionAttributeTarget(reflector_ptr);
8299+
8300+
reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr, reflection_attribute_target_ptr);
81488301
reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers;
81498302
reflection_function_abstract_ptr->create_object = reflection_objects_new;
81508303

@@ -8156,7 +8309,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
81568309
reflection_generator_ptr->create_object = reflection_objects_new;
81578310
reflection_generator_ptr->default_object_handlers = &reflection_object_handlers;
81588311

8159-
reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr);
8312+
reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr, reflection_attribute_target_ptr);
81608313
reflection_parameter_ptr->create_object = reflection_objects_new;
81618314
reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers;
81628315

@@ -8180,19 +8333,19 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
81808333
reflection_method_ptr->create_object = reflection_objects_new;
81818334
reflection_method_ptr->default_object_handlers = &reflection_object_handlers;
81828335

8183-
reflection_class_ptr = register_class_ReflectionClass(reflector_ptr);
8336+
reflection_class_ptr = register_class_ReflectionClass(reflector_ptr, reflection_attribute_target_ptr);
81848337
reflection_class_ptr->create_object = reflection_objects_new;
81858338
reflection_class_ptr->default_object_handlers = &reflection_object_handlers;
81868339

81878340
reflection_object_ptr = register_class_ReflectionObject(reflection_class_ptr);
81888341
reflection_object_ptr->create_object = reflection_objects_new;
81898342
reflection_object_ptr->default_object_handlers = &reflection_object_handlers;
81908343

8191-
reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr);
8344+
reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr, reflection_attribute_target_ptr);
81928345
reflection_property_ptr->create_object = reflection_objects_new;
81938346
reflection_property_ptr->default_object_handlers = &reflection_object_handlers;
81948347

8195-
reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr);
8348+
reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr, reflection_attribute_target_ptr);
81968349
reflection_class_constant_ptr->create_object = reflection_objects_new;
81978350
reflection_class_constant_ptr->default_object_handlers = &reflection_object_handlers;
81988351

@@ -8228,7 +8381,7 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
82288381
reflection_fiber_ptr->create_object = reflection_objects_new;
82298382
reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers;
82308383

8231-
reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr);
8384+
reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr, reflection_attribute_target_ptr);
82328385
reflection_constant_ptr->create_object = reflection_objects_new;
82338386
reflection_constant_ptr->default_object_handlers = &reflection_object_handlers;
82348387

ext/reflection/php_reflection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ BEGIN_EXTERN_C()
2929

3030
/* Class entry pointers */
3131
extern PHPAPI zend_class_entry *reflector_ptr;
32+
extern PHPAPI zend_class_entry *reflection_attribute_target_ptr;
3233
extern PHPAPI zend_class_entry *reflection_exception_ptr;
3334
extern PHPAPI zend_class_entry *reflection_ptr;
3435
extern PHPAPI zend_class_entry *reflection_function_abstract_ptr;

0 commit comments

Comments
 (0)