@@ -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 ;
@@ -1337,6 +1338,7 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje
1337
1338
1338
1339
typedef enum {
1339
1340
NAMED_TYPE = 0 ,
1341
+ RELATIVE_TYPE = 3 ,
1340
1342
UNION_TYPE = 1 ,
1341
1343
INTERSECTION_TYPE = 2
1342
1344
} reflection_type_kind ;
@@ -1364,6 +1366,11 @@ static reflection_type_kind get_type_kind(zend_type type) {
1364
1366
if (type_mask_without_null != 0 ) {
1365
1367
return UNION_TYPE ;
1366
1368
}
1369
+
1370
+ ZEND_ASSERT (ZEND_TYPE_HAS_NAME (type ));
1371
+ if (ZEND_TYPE_IS_RELATIVE_SELF (type ) || ZEND_TYPE_IS_RELATIVE_PARENT (type )) {
1372
+ return RELATIVE_TYPE ;
1373
+ }
1367
1374
return NAMED_TYPE ;
1368
1375
}
1369
1376
if (type_mask_without_null == MAY_BE_BOOL || ZEND_TYPE_PURE_MASK (type ) == MAY_BE_ANY ) {
@@ -1373,12 +1380,22 @@ static reflection_type_kind get_type_kind(zend_type type) {
1373
1380
if ((type_mask_without_null & (type_mask_without_null - 1 )) != 0 ) {
1374
1381
return UNION_TYPE ;
1375
1382
}
1383
+
1384
+ /* "static" is a relative type */
1385
+ if (type_mask_without_null == MAY_BE_STATIC ) {
1386
+ return RELATIVE_TYPE ;
1387
+ }
1376
1388
return NAMED_TYPE ;
1377
1389
}
1378
1390
1379
- /* {{{ reflection_type_factory */
1380
- static void reflection_type_factory (zend_type type , zval * object , bool legacy_behavior )
1381
- {
1391
+ /* ReflectionType private constructor
1392
+ * The object_ce is used to be able to resolve back the "self", "parent", and "static" ReflectionNamedTypes
1393
+ * This can be NULL, e.g. when constructing types of a free function
1394
+ */
1395
+ static void reflection_type_factory (
1396
+ zend_type type , zval * object , bool legacy_behavior ,
1397
+ zend_class_entry * object_ce
1398
+ ) {
1382
1399
reflection_object * intern ;
1383
1400
type_reference * reference ;
1384
1401
reflection_type_kind type_kind = get_type_kind (type );
@@ -1395,6 +1412,9 @@ static void reflection_type_factory(zend_type type, zval *object, bool legacy_be
1395
1412
case NAMED_TYPE :
1396
1413
reflection_instantiate (reflection_named_type_ptr , object );
1397
1414
break ;
1415
+ case RELATIVE_TYPE :
1416
+ reflection_instantiate (reflection_relative_class_type_ptr , object );
1417
+ break ;
1398
1418
EMPTY_SWITCH_DEFAULT_CASE ();
1399
1419
}
1400
1420
@@ -1404,6 +1424,7 @@ static void reflection_type_factory(zend_type type, zval *object, bool legacy_be
1404
1424
reference -> legacy_behavior = legacy_behavior && type_kind == NAMED_TYPE && !is_mixed && !is_only_null ;
1405
1425
intern -> ptr = reference ;
1406
1426
intern -> ref_type = REF_TYPE_TYPE ;
1427
+ intern -> ce = object_ce ;
1407
1428
1408
1429
/* Property types may be resolved during the lifetime of the ReflectionType.
1409
1430
* If we reference a string, make sure it doesn't get released. However, only
@@ -1414,7 +1435,6 @@ static void reflection_type_factory(zend_type type, zval *object, bool legacy_be
1414
1435
zend_string_addref (ZEND_TYPE_NAME (type ));
1415
1436
}
1416
1437
}
1417
- /* }}} */
1418
1438
1419
1439
/* {{{ reflection_function_factory */
1420
1440
static void reflection_function_factory (zend_function * function , zval * closure_object , zval * object )
@@ -2669,17 +2689,14 @@ ZEND_METHOD(ReflectionParameter, getClass)
2669
2689
* TODO: Think about moving these checks to the compiler or some sort of
2670
2690
* lint-mode.
2671
2691
*/
2672
- zend_string * class_name ;
2673
-
2674
- class_name = ZEND_TYPE_NAME (param -> arg_info -> type );
2675
- if (zend_string_equals_literal_ci (class_name , "self" )) {
2692
+ if (ZEND_TYPE_IS_RELATIVE_SELF (param -> arg_info -> type )) {
2676
2693
ce = param -> fptr -> common .scope ;
2677
2694
if (!ce ) {
2678
2695
zend_throw_exception_ex (reflection_exception_ptr , 0 ,
2679
2696
"Parameter uses \"self\" as type but function is not a class member" );
2680
2697
RETURN_THROWS ();
2681
2698
}
2682
- } else if (zend_string_equals_literal_ci ( class_name , "parent" )) {
2699
+ } else if (ZEND_TYPE_IS_RELATIVE_PARENT ( param -> arg_info -> type )) {
2683
2700
ce = param -> fptr -> common .scope ;
2684
2701
if (!ce ) {
2685
2702
zend_throw_exception_ex (reflection_exception_ptr , 0 ,
@@ -2693,6 +2710,7 @@ ZEND_METHOD(ReflectionParameter, getClass)
2693
2710
}
2694
2711
ce = ce -> parent ;
2695
2712
} else {
2713
+ zend_string * class_name = ZEND_TYPE_NAME (param -> arg_info -> type );
2696
2714
ce = zend_lookup_class (class_name );
2697
2715
if (!ce ) {
2698
2716
zend_throw_exception_ex (reflection_exception_ptr , 0 ,
@@ -2734,7 +2752,7 @@ ZEND_METHOD(ReflectionParameter, getType)
2734
2752
if (!ZEND_TYPE_IS_SET (param -> arg_info -> type )) {
2735
2753
RETURN_NULL ();
2736
2754
}
2737
- reflection_type_factory (param -> arg_info -> type , return_value , 1 );
2755
+ reflection_type_factory (param -> arg_info -> type , return_value , /* legacy_behavior */ true, intern -> ce );
2738
2756
}
2739
2757
/* }}} */
2740
2758
@@ -3106,19 +3124,64 @@ ZEND_METHOD(ReflectionNamedType, isBuiltin)
3106
3124
}
3107
3125
/* }}} */
3108
3126
3109
- static void append_type (zval * return_value , zend_type type ) {
3127
+ /* {{{ Returns whether type is a builtin type */
3128
+ ZEND_METHOD (ReflectionRelativeClassType , resolveToNamedType )
3129
+ {
3130
+ reflection_object * intern ;
3131
+ type_reference * param ;
3132
+
3133
+ if (zend_parse_parameters_none () == FAILURE ) {
3134
+ RETURN_THROWS ();
3135
+ }
3136
+ GET_REFLECTION_OBJECT_PTR (param );
3137
+
3138
+ /* Unbound closures can use relative class types */
3139
+ if (!intern -> ce ) {
3140
+ zend_throw_exception_ex (reflection_exception_ptr , 0 ,
3141
+ "Cannot resolve relative class name for a closure" );
3142
+ RETURN_THROWS ();
3143
+ }
3144
+
3145
+ if (intern -> ce -> ce_flags & ZEND_ACC_TRAIT ) {
3146
+ zend_throw_exception_ex (reflection_exception_ptr , 0 ,
3147
+ "Cannot resolve relative class name for a trait" );
3148
+ RETURN_THROWS ();
3149
+ }
3150
+
3151
+ /* Support for legacy behaviour of nullable types and ReflectionNamedType */
3152
+ bool allows_null = ZEND_TYPE_PURE_MASK (param -> type ) & MAY_BE_NULL ;
3153
+ zend_type resolved_type ;
3154
+ /* For static resolved name is the name of the class */
3155
+ if (ZEND_TYPE_PURE_MASK (param -> type ) & MAY_BE_STATIC ) {
3156
+ if (intern -> ce -> ce_flags & ZEND_ACC_INTERFACE ) {
3157
+ zend_throw_exception_ex (reflection_exception_ptr , 0 ,
3158
+ "Cannot resolve \"static\" type of an interface" );
3159
+ RETURN_THROWS ();
3160
+ }
3161
+ resolved_type = (zend_type ) ZEND_TYPE_INIT_CLASS (intern -> ce -> name , allows_null , /*extra flags */ 0 );
3162
+ } else {
3163
+ ZEND_ASSERT (ZEND_TYPE_IS_RELATIVE_SELF (param -> type ) || ZEND_TYPE_IS_RELATIVE_PARENT (param -> type ));
3164
+ ZEND_ASSERT (ZEND_TYPE_HAS_NAME (param -> type ));
3165
+ resolved_type = (zend_type ) ZEND_TYPE_INIT_CLASS (ZEND_TYPE_NAME (param -> type ), allows_null , /*extra flags */ 0 );
3166
+ }
3167
+
3168
+ reflection_type_factory (resolved_type , return_value , /* legacy_behavior */ true, intern -> ce );
3169
+ }
3170
+ /* }}} */
3171
+
3172
+ static void append_type (zval * return_value , zend_type type , zend_class_entry * object_ce ) {
3110
3173
zval reflection_type ;
3111
3174
/* Drop iterable BC bit for type list */
3112
3175
if (ZEND_TYPE_IS_ITERABLE_FALLBACK (type )) {
3113
3176
ZEND_TYPE_FULL_MASK (type ) &= ~_ZEND_TYPE_ITERABLE_BIT ;
3114
3177
}
3115
3178
3116
- reflection_type_factory (type , & reflection_type , 0 );
3179
+ reflection_type_factory (type , & reflection_type , /* legacy_behavior */ false, object_ce );
3117
3180
zend_hash_next_index_insert (Z_ARRVAL_P (return_value ), & reflection_type );
3118
3181
}
3119
3182
3120
- static void append_type_mask (zval * return_value , uint32_t type_mask ) {
3121
- append_type (return_value , (zend_type ) ZEND_TYPE_INIT_MASK (type_mask ));
3183
+ static void append_type_mask (zval * return_value , uint32_t type_mask , zend_class_entry * object_ce ) {
3184
+ append_type (return_value , (zend_type ) ZEND_TYPE_INIT_MASK (type_mask ), object_ce );
3122
3185
}
3123
3186
3124
3187
/* {{{ Returns the types that are part of this union type */
@@ -3137,46 +3200,53 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
3137
3200
if (ZEND_TYPE_HAS_LIST (param -> type )) {
3138
3201
zend_type * list_type ;
3139
3202
ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (param -> type ), list_type ) {
3140
- append_type (return_value , * list_type );
3203
+ append_type (return_value , * list_type , /* object_ce */ intern -> ce );
3141
3204
} ZEND_TYPE_LIST_FOREACH_END ();
3142
3205
} else if (ZEND_TYPE_HAS_NAME (param -> type )) {
3143
3206
zend_string * name = ZEND_TYPE_NAME (param -> type );
3144
- append_type (return_value , (zend_type ) ZEND_TYPE_INIT_CLASS (name , 0 , 0 ));
3207
+ uint32_t type_flags = 0 ;
3208
+ if (ZEND_TYPE_IS_RELATIVE_SELF (param -> type )) {
3209
+ type_flags = _ZEND_TYPE_SELF_BIT ;
3210
+ }
3211
+ if (ZEND_TYPE_IS_RELATIVE_PARENT (param -> type )) {
3212
+ type_flags = _ZEND_TYPE_PARENT_BIT ;
3213
+ }
3214
+ append_type (return_value , (zend_type ) ZEND_TYPE_INIT_CLASS (name , /* allow_null */ false, /* extra flags */ type_flags ), /* object_ce */ intern -> ce );
3145
3215
}
3146
3216
3147
3217
type_mask = ZEND_TYPE_PURE_MASK (param -> type );
3148
3218
ZEND_ASSERT (!(type_mask & MAY_BE_VOID ));
3149
3219
ZEND_ASSERT (!(type_mask & MAY_BE_NEVER ));
3150
3220
if (type_mask & MAY_BE_STATIC ) {
3151
- append_type_mask (return_value , MAY_BE_STATIC );
3221
+ append_type_mask (return_value , MAY_BE_STATIC , /* object_ce */ intern -> ce );
3152
3222
}
3153
3223
if (type_mask & MAY_BE_CALLABLE ) {
3154
- append_type_mask (return_value , MAY_BE_CALLABLE );
3224
+ append_type_mask (return_value , MAY_BE_CALLABLE , /* object_ce */ NULL );
3155
3225
}
3156
3226
if (type_mask & MAY_BE_OBJECT ) {
3157
- append_type_mask (return_value , MAY_BE_OBJECT );
3227
+ append_type_mask (return_value , MAY_BE_OBJECT , /* object_ce */ NULL );
3158
3228
}
3159
3229
if (type_mask & MAY_BE_ARRAY ) {
3160
- append_type_mask (return_value , MAY_BE_ARRAY );
3230
+ append_type_mask (return_value , MAY_BE_ARRAY , /* object_ce */ NULL );
3161
3231
}
3162
3232
if (type_mask & MAY_BE_STRING ) {
3163
- append_type_mask (return_value , MAY_BE_STRING );
3233
+ append_type_mask (return_value , MAY_BE_STRING , /* object_ce */ NULL );
3164
3234
}
3165
3235
if (type_mask & MAY_BE_LONG ) {
3166
- append_type_mask (return_value , MAY_BE_LONG );
3236
+ append_type_mask (return_value , MAY_BE_LONG , /* object_ce */ NULL );
3167
3237
}
3168
3238
if (type_mask & MAY_BE_DOUBLE ) {
3169
- append_type_mask (return_value , MAY_BE_DOUBLE );
3239
+ append_type_mask (return_value , MAY_BE_DOUBLE , /* object_ce */ NULL );
3170
3240
}
3171
3241
if ((type_mask & MAY_BE_BOOL ) == MAY_BE_BOOL ) {
3172
- append_type_mask (return_value , MAY_BE_BOOL );
3242
+ append_type_mask (return_value , MAY_BE_BOOL , /* object_ce */ NULL );
3173
3243
} else if (type_mask & MAY_BE_TRUE ) {
3174
- append_type_mask (return_value , MAY_BE_TRUE );
3244
+ append_type_mask (return_value , MAY_BE_TRUE , /* object_ce */ NULL );
3175
3245
} else if (type_mask & MAY_BE_FALSE ) {
3176
- append_type_mask (return_value , MAY_BE_FALSE );
3246
+ append_type_mask (return_value , MAY_BE_FALSE , /* object_ce */ NULL );
3177
3247
}
3178
3248
if (type_mask & MAY_BE_NULL ) {
3179
- append_type_mask (return_value , MAY_BE_NULL );
3249
+ append_type_mask (return_value , MAY_BE_NULL , /* object_ce */ NULL );
3180
3250
}
3181
3251
}
3182
3252
/* }}} */
@@ -3197,7 +3267,7 @@ ZEND_METHOD(ReflectionIntersectionType, getTypes)
3197
3267
3198
3268
array_init (return_value );
3199
3269
ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (param -> type ), list_type ) {
3200
- append_type (return_value , * list_type );
3270
+ append_type (return_value , * list_type , /* object_ce */ intern -> ce );
3201
3271
} ZEND_TYPE_LIST_FOREACH_END ();
3202
3272
}
3203
3273
/* }}} */
@@ -3620,7 +3690,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getReturnType)
3620
3690
RETURN_NULL ();
3621
3691
}
3622
3692
3623
- reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , 1 );
3693
+ reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , /* legacy_behavior */ true, intern -> ce );
3624
3694
}
3625
3695
/* }}} */
3626
3696
@@ -3656,7 +3726,7 @@ ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType)
3656
3726
RETURN_NULL ();
3657
3727
}
3658
3728
3659
- reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , 1 );
3729
+ reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , /* legacy_behavior */ true, intern -> ce );
3660
3730
}
3661
3731
/* }}} */
3662
3732
@@ -3877,7 +3947,7 @@ ZEND_METHOD(ReflectionClassConstant, getType)
3877
3947
RETURN_NULL ();
3878
3948
}
3879
3949
3880
- reflection_type_factory (ref -> type , return_value , 1 );
3950
+ reflection_type_factory (ref -> type , return_value , /* legacy_behavior */ true, intern -> ce );
3881
3951
}
3882
3952
3883
3953
/* Returns whether class constant has a type */
@@ -5897,7 +5967,7 @@ ZEND_METHOD(ReflectionProperty, getType)
5897
5967
RETURN_NULL ();
5898
5968
}
5899
5969
5900
- reflection_type_factory (ref -> prop -> type , return_value , 1 );
5970
+ reflection_type_factory (ref -> prop -> type , return_value , /* legacy_behavior */ true, intern -> ce );
5901
5971
}
5902
5972
/* }}} */
5903
5973
@@ -6986,7 +7056,7 @@ ZEND_METHOD(ReflectionEnum, getBackingType)
6986
7056
RETURN_NULL ();
6987
7057
} else {
6988
7058
zend_type type = ZEND_TYPE_INIT_CODE (ce -> enum_backing_type , 0 , 0 );
6989
- reflection_type_factory (type , return_value , 0 );
7059
+ reflection_type_factory (type , return_value , /* legacy_behavior */ false, /* object_ce */ NULL );
6990
7060
}
6991
7061
}
6992
7062
@@ -7246,6 +7316,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
7246
7316
reflection_named_type_ptr -> create_object = reflection_objects_new ;
7247
7317
reflection_named_type_ptr -> default_object_handlers = & reflection_object_handlers ;
7248
7318
7319
+ reflection_relative_class_type_ptr = register_class_ReflectionRelativeClassType (reflection_named_type_ptr );
7320
+ reflection_relative_class_type_ptr -> create_object = reflection_objects_new ;
7321
+ reflection_relative_class_type_ptr -> default_object_handlers = & reflection_object_handlers ;
7322
+
7249
7323
reflection_union_type_ptr = register_class_ReflectionUnionType (reflection_type_ptr );
7250
7324
reflection_union_type_ptr -> create_object = reflection_objects_new ;
7251
7325
reflection_union_type_ptr -> default_object_handlers = & reflection_object_handlers ;
0 commit comments