@@ -80,6 +80,7 @@ static zend_always_inline zval *reflection_prop_class(zval *object) {
8080
8181/* Class entry pointers */
8282PHPAPI zend_class_entry * reflector_ptr ;
83+ PHPAPI zend_class_entry * reflection_attribute_target_ptr ;
8384PHPAPI zend_class_entry * reflection_exception_ptr ;
8485PHPAPI zend_class_entry * reflection_ptr ;
8586PHPAPI 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 */
150176typedef 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
158185typedef enum {
@@ -1243,7 +1270,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c
12431270
12441271/* {{{ reflection_attribute_factory */
12451272static 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
12651293static 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
13191348static 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+
75937742ZEND_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
81198270ZEND_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
0 commit comments