@@ -82,6 +82,7 @@ PHPAPI zend_class_entry *reflection_generator_ptr;
82
82
PHPAPI zend_class_entry * reflection_parameter_ptr ;
83
83
PHPAPI zend_class_entry * reflection_type_ptr ;
84
84
PHPAPI zend_class_entry * reflection_named_type_ptr ;
85
+ PHPAPI zend_class_entry * reflection_relative_class_type_ptr ;
85
86
PHPAPI zend_class_entry * reflection_intersection_type_ptr ;
86
87
PHPAPI zend_class_entry * reflection_union_type_ptr ;
87
88
PHPAPI zend_class_entry * reflection_class_ptr ;
@@ -1328,6 +1329,7 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje
1328
1329
1329
1330
typedef enum {
1330
1331
NAMED_TYPE = 0 ,
1332
+ RELATIVE_TYPE = 3 ,
1331
1333
UNION_TYPE = 1 ,
1332
1334
INTERSECTION_TYPE = 2
1333
1335
} reflection_type_kind ;
@@ -1355,6 +1357,11 @@ static reflection_type_kind get_type_kind(zend_type type) {
1355
1357
if (type_mask_without_null != 0 ) {
1356
1358
return UNION_TYPE ;
1357
1359
}
1360
+
1361
+ ZEND_ASSERT (ZEND_TYPE_HAS_NAME (type ));
1362
+ if (ZEND_TYPE_IS_RELATIVE_SELF (type ) || ZEND_TYPE_IS_RELATIVE_PARENT (type )) {
1363
+ return RELATIVE_TYPE ;
1364
+ }
1358
1365
return NAMED_TYPE ;
1359
1366
}
1360
1367
if (type_mask_without_null == MAY_BE_BOOL || ZEND_TYPE_PURE_MASK (type ) == MAY_BE_ANY ) {
@@ -1364,12 +1371,22 @@ static reflection_type_kind get_type_kind(zend_type type) {
1364
1371
if ((type_mask_without_null & (type_mask_without_null - 1 )) != 0 ) {
1365
1372
return UNION_TYPE ;
1366
1373
}
1374
+
1375
+ /* "static" is a relative type */
1376
+ if (type_mask_without_null == MAY_BE_STATIC ) {
1377
+ return RELATIVE_TYPE ;
1378
+ }
1367
1379
return NAMED_TYPE ;
1368
1380
}
1369
1381
1370
- /* {{{ reflection_type_factory */
1371
- static void reflection_type_factory (zend_type type , zval * object , bool legacy_behavior )
1372
- {
1382
+ /* ReflectionType private constructor
1383
+ * The object_ce is used to be able to resolve back the "self", "parent", and "static" ReflectionNamedTypes
1384
+ * This can be NULL, e.g. when constructing types of a free function
1385
+ */
1386
+ static void reflection_type_factory (
1387
+ zend_type type , zval * object , bool legacy_behavior ,
1388
+ zend_class_entry * object_ce
1389
+ ) {
1373
1390
reflection_object * intern ;
1374
1391
type_reference * reference ;
1375
1392
reflection_type_kind type_kind = get_type_kind (type );
@@ -1386,6 +1403,9 @@ static void reflection_type_factory(zend_type type, zval *object, bool legacy_be
1386
1403
case NAMED_TYPE :
1387
1404
reflection_instantiate (reflection_named_type_ptr , object );
1388
1405
break ;
1406
+ case RELATIVE_TYPE :
1407
+ reflection_instantiate (reflection_relative_class_type_ptr , object );
1408
+ break ;
1389
1409
EMPTY_SWITCH_DEFAULT_CASE ();
1390
1410
}
1391
1411
@@ -1395,6 +1415,7 @@ static void reflection_type_factory(zend_type type, zval *object, bool legacy_be
1395
1415
reference -> legacy_behavior = legacy_behavior && type_kind == NAMED_TYPE && !is_mixed && !is_only_null ;
1396
1416
intern -> ptr = reference ;
1397
1417
intern -> ref_type = REF_TYPE_TYPE ;
1418
+ intern -> ce = object_ce ;
1398
1419
1399
1420
/* Property types may be resolved during the lifetime of the ReflectionType.
1400
1421
* If we reference a string, make sure it doesn't get released. However, only
@@ -1405,7 +1426,6 @@ static void reflection_type_factory(zend_type type, zval *object, bool legacy_be
1405
1426
zend_string_addref (ZEND_TYPE_NAME (type ));
1406
1427
}
1407
1428
}
1408
- /* }}} */
1409
1429
1410
1430
/* {{{ reflection_function_factory */
1411
1431
static void reflection_function_factory (zend_function * function , zval * closure_object , zval * object )
@@ -2653,17 +2673,14 @@ ZEND_METHOD(ReflectionParameter, getClass)
2653
2673
* TODO: Think about moving these checks to the compiler or some sort of
2654
2674
* lint-mode.
2655
2675
*/
2656
- zend_string * class_name ;
2657
-
2658
- class_name = ZEND_TYPE_NAME (param -> arg_info -> type );
2659
- if (zend_string_equals_literal_ci (class_name , "self" )) {
2676
+ if (ZEND_TYPE_IS_RELATIVE_SELF (param -> arg_info -> type )) {
2660
2677
ce = param -> fptr -> common .scope ;
2661
2678
if (!ce ) {
2662
2679
zend_throw_exception_ex (reflection_exception_ptr , 0 ,
2663
2680
"Parameter uses \"self\" as type but function is not a class member" );
2664
2681
RETURN_THROWS ();
2665
2682
}
2666
- } else if (zend_string_equals_literal_ci ( class_name , "parent" )) {
2683
+ } else if (ZEND_TYPE_IS_RELATIVE_PARENT ( param -> arg_info -> type )) {
2667
2684
ce = param -> fptr -> common .scope ;
2668
2685
if (!ce ) {
2669
2686
zend_throw_exception_ex (reflection_exception_ptr , 0 ,
@@ -2677,6 +2694,7 @@ ZEND_METHOD(ReflectionParameter, getClass)
2677
2694
}
2678
2695
ce = ce -> parent ;
2679
2696
} else {
2697
+ zend_string * class_name = ZEND_TYPE_NAME (param -> arg_info -> type );
2680
2698
ce = zend_lookup_class (class_name );
2681
2699
if (!ce ) {
2682
2700
zend_throw_exception_ex (reflection_exception_ptr , 0 ,
@@ -2718,7 +2736,7 @@ ZEND_METHOD(ReflectionParameter, getType)
2718
2736
if (!ZEND_TYPE_IS_SET (param -> arg_info -> type )) {
2719
2737
RETURN_NULL ();
2720
2738
}
2721
- reflection_type_factory (param -> arg_info -> type , return_value , 1 );
2739
+ reflection_type_factory (param -> arg_info -> type , return_value , /* legacy_behavior */ true, intern -> ce );
2722
2740
}
2723
2741
/* }}} */
2724
2742
@@ -3090,19 +3108,64 @@ ZEND_METHOD(ReflectionNamedType, isBuiltin)
3090
3108
}
3091
3109
/* }}} */
3092
3110
3093
- static void append_type (zval * return_value , zend_type type ) {
3111
+ /* {{{ Returns whether type is a builtin type */
3112
+ ZEND_METHOD (ReflectionRelativeClassType , resolveToNamedType )
3113
+ {
3114
+ reflection_object * intern ;
3115
+ type_reference * param ;
3116
+
3117
+ if (zend_parse_parameters_none () == FAILURE ) {
3118
+ RETURN_THROWS ();
3119
+ }
3120
+ GET_REFLECTION_OBJECT_PTR (param );
3121
+
3122
+ /* Unbound closures can use relative class types */
3123
+ if (!intern -> ce ) {
3124
+ zend_throw_exception_ex (reflection_exception_ptr , 0 ,
3125
+ "Cannot resolve relative class name for a closure" );
3126
+ RETURN_THROWS ();
3127
+ }
3128
+
3129
+ if (intern -> ce -> ce_flags & ZEND_ACC_TRAIT ) {
3130
+ zend_throw_exception_ex (reflection_exception_ptr , 0 ,
3131
+ "Cannot resolve relative class name for a trait" );
3132
+ RETURN_THROWS ();
3133
+ }
3134
+
3135
+ /* Support for legacy behaviour of nullable types and ReflectionNamedType */
3136
+ bool allows_null = ZEND_TYPE_PURE_MASK (param -> type ) & MAY_BE_NULL ;
3137
+ zend_type resolved_type ;
3138
+ /* For static resolved name is the name of the class */
3139
+ if (ZEND_TYPE_PURE_MASK (param -> type ) & MAY_BE_STATIC ) {
3140
+ if (intern -> ce -> ce_flags & ZEND_ACC_INTERFACE ) {
3141
+ zend_throw_exception_ex (reflection_exception_ptr , 0 ,
3142
+ "Cannot resolve \"static\" type of an interface" );
3143
+ RETURN_THROWS ();
3144
+ }
3145
+ resolved_type = (zend_type ) ZEND_TYPE_INIT_CLASS (intern -> ce -> name , allows_null , /*extra flags */ 0 );
3146
+ } else {
3147
+ ZEND_ASSERT (ZEND_TYPE_IS_RELATIVE_SELF (param -> type ) || ZEND_TYPE_IS_RELATIVE_PARENT (param -> type ));
3148
+ ZEND_ASSERT (ZEND_TYPE_HAS_NAME (param -> type ));
3149
+ resolved_type = (zend_type ) ZEND_TYPE_INIT_CLASS (ZEND_TYPE_NAME (param -> type ), allows_null , /*extra flags */ 0 );
3150
+ }
3151
+
3152
+ reflection_type_factory (resolved_type , return_value , /* legacy_behavior */ true, intern -> ce );
3153
+ }
3154
+ /* }}} */
3155
+
3156
+ static void append_type (zval * return_value , zend_type type , zend_class_entry * object_ce ) {
3094
3157
zval reflection_type ;
3095
3158
/* Drop iterable BC bit for type list */
3096
3159
if (ZEND_TYPE_IS_ITERABLE_FALLBACK (type )) {
3097
3160
ZEND_TYPE_FULL_MASK (type ) &= ~_ZEND_TYPE_ITERABLE_BIT ;
3098
3161
}
3099
3162
3100
- reflection_type_factory (type , & reflection_type , 0 );
3163
+ reflection_type_factory (type , & reflection_type , /* legacy_behavior */ false, object_ce );
3101
3164
zend_hash_next_index_insert (Z_ARRVAL_P (return_value ), & reflection_type );
3102
3165
}
3103
3166
3104
- static void append_type_mask (zval * return_value , uint32_t type_mask ) {
3105
- append_type (return_value , (zend_type ) ZEND_TYPE_INIT_MASK (type_mask ));
3167
+ static void append_type_mask (zval * return_value , uint32_t type_mask , zend_class_entry * object_ce ) {
3168
+ append_type (return_value , (zend_type ) ZEND_TYPE_INIT_MASK (type_mask ), object_ce );
3106
3169
}
3107
3170
3108
3171
/* {{{ Returns the types that are part of this union type */
@@ -3121,46 +3184,53 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
3121
3184
if (ZEND_TYPE_HAS_LIST (param -> type )) {
3122
3185
zend_type * list_type ;
3123
3186
ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (param -> type ), list_type ) {
3124
- append_type (return_value , * list_type );
3187
+ append_type (return_value , * list_type , /* object_ce */ intern -> ce );
3125
3188
} ZEND_TYPE_LIST_FOREACH_END ();
3126
3189
} else if (ZEND_TYPE_HAS_NAME (param -> type )) {
3127
3190
zend_string * name = ZEND_TYPE_NAME (param -> type );
3128
- append_type (return_value , (zend_type ) ZEND_TYPE_INIT_CLASS (name , 0 , 0 ));
3191
+ uint32_t type_flags = 0 ;
3192
+ if (ZEND_TYPE_IS_RELATIVE_SELF (param -> type )) {
3193
+ type_flags = _ZEND_TYPE_SELF_BIT ;
3194
+ }
3195
+ if (ZEND_TYPE_IS_RELATIVE_PARENT (param -> type )) {
3196
+ type_flags = _ZEND_TYPE_PARENT_BIT ;
3197
+ }
3198
+ append_type (return_value , (zend_type ) ZEND_TYPE_INIT_CLASS (name , /* allow_null */ false, /* extra flags */ type_flags ), /* object_ce */ intern -> ce );
3129
3199
}
3130
3200
3131
3201
type_mask = ZEND_TYPE_PURE_MASK (param -> type );
3132
3202
ZEND_ASSERT (!(type_mask & MAY_BE_VOID ));
3133
3203
ZEND_ASSERT (!(type_mask & MAY_BE_NEVER ));
3134
3204
if (type_mask & MAY_BE_STATIC ) {
3135
- append_type_mask (return_value , MAY_BE_STATIC );
3205
+ append_type_mask (return_value , MAY_BE_STATIC , /* object_ce */ intern -> ce );
3136
3206
}
3137
3207
if (type_mask & MAY_BE_CALLABLE ) {
3138
- append_type_mask (return_value , MAY_BE_CALLABLE );
3208
+ append_type_mask (return_value , MAY_BE_CALLABLE , /* object_ce */ NULL );
3139
3209
}
3140
3210
if (type_mask & MAY_BE_OBJECT ) {
3141
- append_type_mask (return_value , MAY_BE_OBJECT );
3211
+ append_type_mask (return_value , MAY_BE_OBJECT , /* object_ce */ NULL );
3142
3212
}
3143
3213
if (type_mask & MAY_BE_ARRAY ) {
3144
- append_type_mask (return_value , MAY_BE_ARRAY );
3214
+ append_type_mask (return_value , MAY_BE_ARRAY , /* object_ce */ NULL );
3145
3215
}
3146
3216
if (type_mask & MAY_BE_STRING ) {
3147
- append_type_mask (return_value , MAY_BE_STRING );
3217
+ append_type_mask (return_value , MAY_BE_STRING , /* object_ce */ NULL );
3148
3218
}
3149
3219
if (type_mask & MAY_BE_LONG ) {
3150
- append_type_mask (return_value , MAY_BE_LONG );
3220
+ append_type_mask (return_value , MAY_BE_LONG , /* object_ce */ NULL );
3151
3221
}
3152
3222
if (type_mask & MAY_BE_DOUBLE ) {
3153
- append_type_mask (return_value , MAY_BE_DOUBLE );
3223
+ append_type_mask (return_value , MAY_BE_DOUBLE , /* object_ce */ NULL );
3154
3224
}
3155
3225
if ((type_mask & MAY_BE_BOOL ) == MAY_BE_BOOL ) {
3156
- append_type_mask (return_value , MAY_BE_BOOL );
3226
+ append_type_mask (return_value , MAY_BE_BOOL , /* object_ce */ NULL );
3157
3227
} else if (type_mask & MAY_BE_TRUE ) {
3158
- append_type_mask (return_value , MAY_BE_TRUE );
3228
+ append_type_mask (return_value , MAY_BE_TRUE , /* object_ce */ NULL );
3159
3229
} else if (type_mask & MAY_BE_FALSE ) {
3160
- append_type_mask (return_value , MAY_BE_FALSE );
3230
+ append_type_mask (return_value , MAY_BE_FALSE , /* object_ce */ NULL );
3161
3231
}
3162
3232
if (type_mask & MAY_BE_NULL ) {
3163
- append_type_mask (return_value , MAY_BE_NULL );
3233
+ append_type_mask (return_value , MAY_BE_NULL , /* object_ce */ NULL );
3164
3234
}
3165
3235
}
3166
3236
/* }}} */
@@ -3181,7 +3251,7 @@ ZEND_METHOD(ReflectionIntersectionType, getTypes)
3181
3251
3182
3252
array_init (return_value );
3183
3253
ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (param -> type ), list_type ) {
3184
- append_type (return_value , * list_type );
3254
+ append_type (return_value , * list_type , /* object_ce */ intern -> ce );
3185
3255
} ZEND_TYPE_LIST_FOREACH_END ();
3186
3256
}
3187
3257
/* }}} */
@@ -3578,7 +3648,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getReturnType)
3578
3648
RETURN_NULL ();
3579
3649
}
3580
3650
3581
- reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , 1 );
3651
+ reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , /* legacy_behavior */ true, intern -> ce );
3582
3652
}
3583
3653
/* }}} */
3584
3654
@@ -3614,7 +3684,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType)
3614
3684
RETURN_NULL ();
3615
3685
}
3616
3686
3617
- reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , 1 );
3687
+ reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , /* legacy_behavior */ true, intern -> ce );
3618
3688
}
3619
3689
/* }}} */
3620
3690
@@ -3835,7 +3905,7 @@ ZEND_METHOD(ReflectionClassConstant, getType)
3835
3905
RETURN_NULL ();
3836
3906
}
3837
3907
3838
- reflection_type_factory (ref -> type , return_value , 1 );
3908
+ reflection_type_factory (ref -> type , return_value , /* legacy_behavior */ true, intern -> ce );
3839
3909
}
3840
3910
3841
3911
/* Returns whether class constant has a type */
@@ -5839,7 +5909,7 @@ ZEND_METHOD(ReflectionProperty, getType)
5839
5909
RETURN_NULL ();
5840
5910
}
5841
5911
5842
- reflection_type_factory (ref -> prop -> type , return_value , 1 );
5912
+ reflection_type_factory (ref -> prop -> type , return_value , /* legacy_behavior */ true, intern -> ce );
5843
5913
}
5844
5914
/* }}} */
5845
5915
@@ -6929,7 +6999,7 @@ ZEND_METHOD(ReflectionEnum, getBackingType)
6929
6999
RETURN_NULL ();
6930
7000
} else {
6931
7001
zend_type type = ZEND_TYPE_INIT_CODE (ce -> enum_backing_type , 0 , 0 );
6932
- reflection_type_factory (type , return_value , 0 );
7002
+ reflection_type_factory (type , return_value , /* legacy_behavior */ false, /* object_ce */ NULL );
6933
7003
}
6934
7004
}
6935
7005
@@ -7189,6 +7259,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
7189
7259
reflection_named_type_ptr -> create_object = reflection_objects_new ;
7190
7260
reflection_named_type_ptr -> default_object_handlers = & reflection_object_handlers ;
7191
7261
7262
+ reflection_relative_class_type_ptr = register_class_ReflectionRelativeClassType (reflection_named_type_ptr );
7263
+ reflection_relative_class_type_ptr -> create_object = reflection_objects_new ;
7264
+ reflection_relative_class_type_ptr -> default_object_handlers = & reflection_object_handlers ;
7265
+
7192
7266
reflection_union_type_ptr = register_class_ReflectionUnionType (reflection_type_ptr );
7193
7267
reflection_union_type_ptr -> create_object = reflection_objects_new ;
7194
7268
reflection_union_type_ptr -> default_object_handlers = & reflection_object_handlers ;
0 commit comments