@@ -74,6 +74,7 @@ PHPAPI zend_class_entry *reflection_generator_ptr;
74
74
PHPAPI zend_class_entry * reflection_parameter_ptr ;
75
75
PHPAPI zend_class_entry * reflection_type_ptr ;
76
76
PHPAPI zend_class_entry * reflection_named_type_ptr ;
77
+ PHPAPI zend_class_entry * reflection_union_type_ptr ;
77
78
PHPAPI zend_class_entry * reflection_class_ptr ;
78
79
PHPAPI zend_class_entry * reflection_object_ptr ;
79
80
PHPAPI zend_class_entry * reflection_method_ptr ;
@@ -127,6 +128,8 @@ typedef struct _parameter_reference {
127
128
/* Struct for type hints */
128
129
typedef struct _type_reference {
129
130
zend_type type ;
131
+ /* Whether to use backwards compatible null representation */
132
+ zend_bool legacy_behavior ;
130
133
} type_reference ;
131
134
132
135
typedef enum {
@@ -1124,16 +1127,37 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje
1124
1127
}
1125
1128
/* }}} */
1126
1129
1130
+ /* For backwards compatibility reasons, we need to return T|null style unions
1131
+ * as a ReflectionNamedType. Here we determine what counts as a union type and
1132
+ * what doesn't. */
1133
+ static zend_bool is_union_type (zend_type type ) {
1134
+ if (ZEND_TYPE_HAS_LIST (type )) {
1135
+ return 1 ;
1136
+ }
1137
+ uint32_t type_mask_without_null = ZEND_TYPE_PURE_MASK_WITHOUT_NULL (type );
1138
+ if (ZEND_TYPE_HAS_CLASS (type )) {
1139
+ return type_mask_without_null != 0 ;
1140
+ }
1141
+ if (type_mask_without_null == MAY_BE_BOOL ) {
1142
+ return 0 ;
1143
+ }
1144
+ /* Check that only one bit is set. */
1145
+ return (type_mask_without_null & (type_mask_without_null - 1 )) != 0 ;
1146
+ }
1147
+
1127
1148
/* {{{ reflection_type_factory */
1128
- static void reflection_type_factory (zend_type type , zval * object )
1149
+ static void reflection_type_factory (zend_type type , zval * object , zend_bool legacy_behavior )
1129
1150
{
1130
1151
reflection_object * intern ;
1131
1152
type_reference * reference ;
1153
+ zend_bool is_union = is_union_type (type );
1132
1154
1133
- reflection_instantiate (reflection_named_type_ptr , object );
1155
+ reflection_instantiate (
1156
+ is_union ? reflection_union_type_ptr : reflection_named_type_ptr , object );
1134
1157
intern = Z_REFLECTION_P (object );
1135
1158
reference = (type_reference * ) emalloc (sizeof (type_reference ));
1136
1159
reference -> type = type ;
1160
+ reference -> legacy_behavior = legacy_behavior && !is_union ;
1137
1161
intern -> ptr = reference ;
1138
1162
intern -> ref_type = REF_TYPE_TYPE ;
1139
1163
}
@@ -2540,7 +2564,7 @@ ZEND_METHOD(reflection_parameter, getType)
2540
2564
if (!ZEND_TYPE_IS_SET (param -> arg_info -> type )) {
2541
2565
RETURN_NULL ();
2542
2566
}
2543
- reflection_type_factory (param -> arg_info -> type , return_value );
2567
+ reflection_type_factory (param -> arg_info -> type , return_value , 1 );
2544
2568
}
2545
2569
/* }}} */
2546
2570
@@ -2840,7 +2864,10 @@ ZEND_METHOD(reflection_named_type, getName)
2840
2864
}
2841
2865
GET_REFLECTION_OBJECT_PTR (param );
2842
2866
2843
- RETURN_STR (zend_type_to_string_without_null (param -> type ));
2867
+ if (param -> legacy_behavior ) {
2868
+ RETURN_STR (zend_type_to_string_without_null (param -> type ));
2869
+ }
2870
+ RETURN_STR (zend_type_to_string (param -> type ));
2844
2871
}
2845
2872
/* }}} */
2846
2873
@@ -2860,6 +2887,83 @@ ZEND_METHOD(reflection_named_type, isBuiltin)
2860
2887
}
2861
2888
/* }}} */
2862
2889
2890
+ static void append_type (zval * return_value , zend_type type ) {
2891
+ zval reflection_type ;
2892
+ reflection_type_factory (type , & reflection_type , 0 );
2893
+ zend_hash_next_index_insert (Z_ARRVAL_P (return_value ), & reflection_type );
2894
+ }
2895
+
2896
+ static void append_type_mask (zval * return_value , uint32_t type_mask ) {
2897
+ append_type (return_value , (zend_type ) ZEND_TYPE_INIT_MASK (type_mask ));
2898
+ }
2899
+
2900
+ /* {{{ proto public string ReflectionUnionType::getTypes()
2901
+ Returns the types that are part of this union type */
2902
+ ZEND_METHOD (reflection_union_type , getTypes )
2903
+ {
2904
+ reflection_object * intern ;
2905
+ type_reference * param ;
2906
+ uint32_t type_mask ;
2907
+
2908
+ if (zend_parse_parameters_none () == FAILURE ) {
2909
+ return ;
2910
+ }
2911
+ GET_REFLECTION_OBJECT_PTR (param );
2912
+
2913
+ array_init (return_value );
2914
+ if (ZEND_TYPE_HAS_LIST (param -> type )) {
2915
+ void * entry ;
2916
+ ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (param -> type ), entry ) {
2917
+ if (ZEND_TYPE_LIST_IS_NAME (entry )) {
2918
+ append_type (return_value ,
2919
+ (zend_type ) ZEND_TYPE_INIT_CLASS (ZEND_TYPE_LIST_GET_NAME (entry ), 0 , 0 ));
2920
+ } else {
2921
+ append_type (return_value ,
2922
+ (zend_type ) ZEND_TYPE_INIT_CE (ZEND_TYPE_LIST_GET_CE (entry ), 0 , 0 ));
2923
+ }
2924
+ } ZEND_TYPE_LIST_FOREACH_END ();
2925
+ } else if (ZEND_TYPE_HAS_NAME (param -> type )) {
2926
+ append_type (return_value ,
2927
+ (zend_type ) ZEND_TYPE_INIT_CLASS (ZEND_TYPE_NAME (param -> type ), 0 , 0 ));
2928
+ } else if (ZEND_TYPE_HAS_CE (param -> type )) {
2929
+ append_type (return_value ,
2930
+ (zend_type ) ZEND_TYPE_INIT_CE (ZEND_TYPE_CE (param -> type ), 0 , 0 ));
2931
+ }
2932
+
2933
+ type_mask = ZEND_TYPE_PURE_MASK (param -> type );
2934
+ ZEND_ASSERT (!(type_mask & MAY_BE_VOID ));
2935
+ if (type_mask & MAY_BE_CALLABLE ) {
2936
+ append_type_mask (return_value , MAY_BE_CALLABLE );
2937
+ }
2938
+ if (type_mask & MAY_BE_ITERABLE ) {
2939
+ append_type_mask (return_value , MAY_BE_ITERABLE );
2940
+ }
2941
+ if (type_mask & MAY_BE_OBJECT ) {
2942
+ append_type_mask (return_value , MAY_BE_OBJECT );
2943
+ }
2944
+ if (type_mask & MAY_BE_ARRAY ) {
2945
+ append_type_mask (return_value , MAY_BE_ARRAY );
2946
+ }
2947
+ if (type_mask & MAY_BE_STRING ) {
2948
+ append_type_mask (return_value , MAY_BE_STRING );
2949
+ }
2950
+ if (type_mask & MAY_BE_LONG ) {
2951
+ append_type_mask (return_value , MAY_BE_LONG );
2952
+ }
2953
+ if (type_mask & MAY_BE_DOUBLE ) {
2954
+ append_type_mask (return_value , MAY_BE_DOUBLE );
2955
+ }
2956
+ if ((type_mask & MAY_BE_BOOL ) == MAY_BE_BOOL ) {
2957
+ append_type_mask (return_value , MAY_BE_BOOL );
2958
+ } else if (type_mask & MAY_BE_FALSE ) {
2959
+ append_type_mask (return_value , MAY_BE_FALSE );
2960
+ }
2961
+ if (type_mask & MAY_BE_NULL ) {
2962
+ append_type_mask (return_value , MAY_BE_NULL );
2963
+ }
2964
+ }
2965
+ /* }}} */
2966
+
2863
2967
/* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
2864
2968
Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
2865
2969
ZEND_METHOD (reflection_method , export )
@@ -3325,7 +3429,7 @@ ZEND_METHOD(reflection_function, getReturnType)
3325
3429
RETURN_NULL ();
3326
3430
}
3327
3431
3328
- reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value );
3432
+ reflection_type_factory (fptr -> common .arg_info [-1 ].type , return_value , 1 );
3329
3433
}
3330
3434
/* }}} */
3331
3435
@@ -5580,7 +5684,7 @@ ZEND_METHOD(reflection_property, getType)
5580
5684
RETURN_NULL ();
5581
5685
}
5582
5686
5583
- reflection_type_factory (ref -> prop .type , return_value );
5687
+ reflection_type_factory (ref -> prop .type , return_value , 1 );
5584
5688
}
5585
5689
/* }}} */
5586
5690
@@ -6637,6 +6741,11 @@ static const zend_function_entry reflection_named_type_functions[] = {
6637
6741
PHP_FE_END
6638
6742
};
6639
6743
6744
+ static const zend_function_entry reflection_union_type_functions [] = {
6745
+ ZEND_ME (reflection_union_type , getTypes , arginfo_reflection__void , 0 )
6746
+ PHP_FE_END
6747
+ };
6748
+
6640
6749
ZEND_BEGIN_ARG_INFO_EX (arginfo_reflection_extension_export , 0 , 0 , 1 )
6641
6750
ZEND_ARG_INFO (0 , name )
6642
6751
ZEND_ARG_INFO (0 , return )
@@ -6778,6 +6887,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
6778
6887
reflection_init_class_handlers (& _reflection_entry );
6779
6888
reflection_named_type_ptr = zend_register_internal_class_ex (& _reflection_entry , reflection_type_ptr );
6780
6889
6890
+ INIT_CLASS_ENTRY (_reflection_entry , "ReflectionUnionType" , reflection_union_type_functions );
6891
+ reflection_init_class_handlers (& _reflection_entry );
6892
+ reflection_union_type_ptr = zend_register_internal_class_ex (& _reflection_entry , reflection_type_ptr );
6893
+
6781
6894
INIT_CLASS_ENTRY (_reflection_entry , "ReflectionMethod" , reflection_method_functions );
6782
6895
reflection_init_class_handlers (& _reflection_entry );
6783
6896
reflection_method_ptr = zend_register_internal_class_ex (& _reflection_entry , reflection_function_abstract_ptr );
0 commit comments