@@ -102,6 +102,9 @@ PHPAPI zend_class_entry *reflection_enum_unit_case_ptr;
102102PHPAPI zend_class_entry * reflection_enum_backed_case_ptr ;
103103PHPAPI zend_class_entry * reflection_fiber_ptr ;
104104PHPAPI zend_class_entry * reflection_constant_ptr ;
105+ PHPAPI zend_class_entry * reflection_generic_type_parameter_ptr ;
106+ PHPAPI zend_class_entry * reflection_type_parameter_reference_ptr ;
107+ PHPAPI zend_class_entry * reflection_generic_variance_ptr ;
105108PHPAPI zend_class_entry * reflection_property_hook_type_ptr ;
106109
107110#define GET_REFLECTION_OBJECT () do { \
@@ -144,6 +147,15 @@ typedef struct _type_reference {
144147 bool legacy_behavior ;
145148} type_reference ;
146149
150+ /* Struct for generic type-parameter reflection. Points back at a parameter slot
151+ * inside the declaring entity's zend_generic_parameter_list. Lifetime is bound
152+ * to the declaring class_entry / op_array. */
153+ typedef struct _generic_parameter_reference {
154+ zend_generic_parameter * param ; /* points into a zend_generic_parameter_list */
155+ uint32_t index ; /* position in the list */
156+ zval declaring ; /* zval-wrapped ReflectionClass / ReflectionFunctionAbstract */
157+ } generic_parameter_reference ;
158+
147159/* Struct for attributes */
148160typedef struct _attribute_reference {
149161 HashTable * attributes ;
@@ -8156,6 +8168,309 @@ ZEND_METHOD(ReflectionConstant, __toString)
81568168 RETURN_STR (smart_str_extract (& str ));
81578169}
81588170
8171+ ZEND_METHOD (ReflectionGenericTypeParameter , __construct )
8172+ {
8173+ zend_throw_exception (reflection_exception_ptr ,
8174+ "Cannot directly instantiate ReflectionGenericTypeParameter" , 0 );
8175+ }
8176+
8177+ ZEND_METHOD (ReflectionTypeParameterReference , __construct )
8178+ {
8179+ zend_throw_exception (reflection_exception_ptr ,
8180+ "Cannot directly instantiate ReflectionTypeParameterReference" , 0 );
8181+ }
8182+
8183+
8184+ static void reflection_generic_type_parameter_factory (
8185+ zend_generic_parameter * param , uint32_t index , zval * declaring , zval * object )
8186+ {
8187+ reflection_object * intern ;
8188+ generic_parameter_reference * reference ;
8189+
8190+ object_init_ex (object , reflection_generic_type_parameter_ptr );
8191+ intern = Z_REFLECTION_P (object );
8192+ reference = emalloc (sizeof (generic_parameter_reference ));
8193+ reference -> param = param ;
8194+ reference -> index = index ;
8195+ ZVAL_COPY (& reference -> declaring , declaring );
8196+ intern -> ptr = reference ;
8197+ intern -> ref_type = REF_TYPE_OTHER ;
8198+
8199+ ZVAL_STR_COPY (reflection_prop_name (object ), param -> name );
8200+ }
8201+
8202+ static void reflection_build_generic_parameters_array (
8203+ zend_generic_parameter_list * list , zval * declaring , zval * return_value )
8204+ {
8205+ if (!list ) {
8206+ array_init (return_value );
8207+ return ;
8208+ }
8209+ array_init_size (return_value , list -> count );
8210+ for (uint32_t i = 0 ; i < list -> count ; i ++ ) {
8211+ zval entry ;
8212+ reflection_generic_type_parameter_factory (& list -> parameters [i ], i , declaring , & entry );
8213+ zend_hash_next_index_insert_new (Z_ARRVAL_P (return_value ), & entry );
8214+ }
8215+ }
8216+
8217+ ZEND_METHOD (ReflectionFunctionAbstract , isGeneric )
8218+ {
8219+ reflection_object * intern ;
8220+ zend_function * fptr ;
8221+
8222+ ZEND_PARSE_PARAMETERS_NONE ();
8223+ GET_REFLECTION_OBJECT_PTR (fptr );
8224+
8225+ if (fptr -> type != ZEND_USER_FUNCTION ) {
8226+ RETURN_FALSE ;
8227+ }
8228+ RETURN_BOOL (fptr -> op_array .generic_parameters != NULL );
8229+ }
8230+
8231+ ZEND_METHOD (ReflectionFunctionAbstract , getGenericParameters )
8232+ {
8233+ reflection_object * intern ;
8234+ zend_function * fptr ;
8235+
8236+ ZEND_PARSE_PARAMETERS_NONE ();
8237+ GET_REFLECTION_OBJECT_PTR (fptr );
8238+
8239+ if (fptr -> type != ZEND_USER_FUNCTION ) {
8240+ array_init (return_value );
8241+ return ;
8242+ }
8243+ reflection_build_generic_parameters_array (fptr -> op_array .generic_parameters , ZEND_THIS , return_value );
8244+ }
8245+
8246+ ZEND_METHOD (ReflectionClass , isGeneric )
8247+ {
8248+ reflection_object * intern ;
8249+ zend_class_entry * ce ;
8250+
8251+ ZEND_PARSE_PARAMETERS_NONE ();
8252+ GET_REFLECTION_OBJECT_PTR (ce );
8253+
8254+ RETURN_BOOL (ce -> generic_parameters != NULL );
8255+ }
8256+
8257+ ZEND_METHOD (ReflectionClass , getGenericParameters )
8258+ {
8259+ reflection_object * intern ;
8260+ zend_class_entry * ce ;
8261+
8262+ ZEND_PARSE_PARAMETERS_NONE ();
8263+ GET_REFLECTION_OBJECT_PTR (ce );
8264+
8265+ reflection_build_generic_parameters_array (ce -> generic_parameters , ZEND_THIS , return_value );
8266+ }
8267+
8268+ #define GET_GENERIC_PARAMETER_REFERENCE (intern , param_ref ) \
8269+ do { \
8270+ (intern) = Z_REFLECTION_P(getThis()); \
8271+ if ((intern)->ptr == NULL) { \
8272+ zend_throw_error(NULL, "Internal error: Failed to retrieve the type parameter reference"); \
8273+ RETURN_THROWS(); \
8274+ } \
8275+ (param_ref) = (generic_parameter_reference *) (intern)->ptr; \
8276+ } while (0)
8277+
8278+ ZEND_METHOD (ReflectionGenericTypeParameter , getName )
8279+ {
8280+ reflection_object * intern ;
8281+ generic_parameter_reference * ref ;
8282+
8283+ ZEND_PARSE_PARAMETERS_NONE ();
8284+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8285+ RETURN_STR_COPY (ref -> param -> name );
8286+ }
8287+
8288+ ZEND_METHOD (ReflectionGenericTypeParameter , getPosition )
8289+ {
8290+ reflection_object * intern ;
8291+ generic_parameter_reference * ref ;
8292+
8293+ ZEND_PARSE_PARAMETERS_NONE ();
8294+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8295+ RETURN_LONG ((zend_long ) ref -> index );
8296+ }
8297+
8298+ ZEND_METHOD (ReflectionGenericTypeParameter , getVariance )
8299+ {
8300+ reflection_object * intern ;
8301+ generic_parameter_reference * ref ;
8302+
8303+ ZEND_PARSE_PARAMETERS_NONE ();
8304+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8305+
8306+ const char * case_name ;
8307+ switch (ref -> param -> variance ) {
8308+ case 1 : case_name = "Covariant" ; break ;
8309+ case 2 : case_name = "Contravariant" ; break ;
8310+ default : case_name = "Invariant" ; break ;
8311+ }
8312+ zend_object * case_obj = zend_enum_get_case_cstr (reflection_generic_variance_ptr , case_name );
8313+ if (!case_obj ) {
8314+ zend_throw_error (NULL , "Internal error: ReflectionGenericVariance enum case not found" );
8315+ RETURN_THROWS ();
8316+ }
8317+ ZVAL_OBJ_COPY (return_value , case_obj );
8318+ }
8319+
8320+ ZEND_METHOD (ReflectionGenericTypeParameter , hasBound )
8321+ {
8322+ reflection_object * intern ;
8323+ generic_parameter_reference * ref ;
8324+
8325+ ZEND_PARSE_PARAMETERS_NONE ();
8326+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8327+ RETURN_BOOL (ZEND_TYPE_IS_SET (ref -> param -> bound ));
8328+ }
8329+
8330+ ZEND_METHOD (ReflectionGenericTypeParameter , getBound )
8331+ {
8332+ reflection_object * intern ;
8333+ generic_parameter_reference * ref ;
8334+
8335+ ZEND_PARSE_PARAMETERS_NONE ();
8336+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8337+
8338+ if (!ZEND_TYPE_IS_SET (ref -> param -> bound )) {
8339+ RETURN_NULL ();
8340+ }
8341+ reflection_type_factory (ref -> param -> bound , return_value , false);
8342+ }
8343+
8344+ ZEND_METHOD (ReflectionGenericTypeParameter , hasDefault )
8345+ {
8346+ reflection_object * intern ;
8347+ generic_parameter_reference * ref ;
8348+
8349+ ZEND_PARSE_PARAMETERS_NONE ();
8350+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8351+ RETURN_BOOL (ZEND_TYPE_IS_SET (ref -> param -> default_type ));
8352+ }
8353+
8354+ ZEND_METHOD (ReflectionGenericTypeParameter , getDefault )
8355+ {
8356+ reflection_object * intern ;
8357+ generic_parameter_reference * ref ;
8358+
8359+ ZEND_PARSE_PARAMETERS_NONE ();
8360+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8361+
8362+ if (!ZEND_TYPE_IS_SET (ref -> param -> default_type )) {
8363+ RETURN_NULL ();
8364+ }
8365+ reflection_type_factory (ref -> param -> default_type , return_value , false);
8366+ }
8367+
8368+ ZEND_METHOD (ReflectionGenericTypeParameter , getDeclaringEntity )
8369+ {
8370+ reflection_object * intern ;
8371+ generic_parameter_reference * ref ;
8372+
8373+ ZEND_PARSE_PARAMETERS_NONE ();
8374+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8375+ ZVAL_COPY (return_value , & ref -> declaring );
8376+ }
8377+
8378+ ZEND_METHOD (ReflectionGenericTypeParameter , __toString )
8379+ {
8380+ reflection_object * intern ;
8381+ generic_parameter_reference * ref ;
8382+ smart_str str = {0 };
8383+
8384+ ZEND_PARSE_PARAMETERS_NONE ();
8385+ GET_GENERIC_PARAMETER_REFERENCE (intern , ref );
8386+
8387+ switch (ref -> param -> variance ) {
8388+ case 1 :
8389+ smart_str_appendc (& str , '+' );
8390+ break ;
8391+ case 2 :
8392+ smart_str_appendc (& str , '-' );
8393+ break ;
8394+ default :
8395+ break ;
8396+ }
8397+ smart_str_append (& str , ref -> param -> name );
8398+ if (ZEND_TYPE_IS_SET (ref -> param -> bound )) {
8399+ zend_string * bound = zend_type_to_string (ref -> param -> bound );
8400+ smart_str_appends (& str , " : " );
8401+ smart_str_append (& str , bound );
8402+ zend_string_release (bound );
8403+ }
8404+ if (ZEND_TYPE_IS_SET (ref -> param -> default_type )) {
8405+ zend_string * def = zend_type_to_string (ref -> param -> default_type );
8406+ smart_str_appends (& str , " = " );
8407+ smart_str_append (& str , def );
8408+ zend_string_release (def );
8409+ }
8410+ RETURN_NEW_STR (smart_str_extract (& str ));
8411+ }
8412+
8413+ ZEND_METHOD (ReflectionTypeParameterReference , getName )
8414+ {
8415+ reflection_object * intern ;
8416+ type_reference * ref ;
8417+
8418+ ZEND_PARSE_PARAMETERS_NONE ();
8419+ GET_REFLECTION_OBJECT_PTR (ref );
8420+
8421+ if (!ZEND_TYPE_HAS_TYPE_PARAMETER (ref -> type )) {
8422+ zend_throw_error (NULL , "Type parameter reference has no parameter" );
8423+ RETURN_THROWS ();
8424+ }
8425+ zend_type_parameter_ref * tp = ZEND_TYPE_TYPE_PARAMETER (ref -> type );
8426+ RETURN_STR_COPY (tp -> name );
8427+ }
8428+
8429+ ZEND_METHOD (ReflectionTypeParameterReference , getTypeParameter )
8430+ {
8431+ /* TODO(azjezz): resolution to the originating ReflectionGenericTypeParameter requires the
8432+ * declaring entity, which is not currently threaded through type_reference. */
8433+ zend_throw_error (NULL ,
8434+ "ReflectionTypeParameterReference::getTypeParameter() requires the declaring "
8435+ "entity to be threaded through; not yet implemented" );
8436+ RETURN_THROWS ();
8437+ }
8438+
8439+ ZEND_METHOD (ReflectionTypeParameterReference , allowsNull )
8440+ {
8441+ ZEND_PARSE_PARAMETERS_NONE ();
8442+ RETURN_TRUE ;
8443+ }
8444+
8445+ ZEND_METHOD (ReflectionTypeParameterReference , __toString )
8446+ {
8447+ reflection_object * intern ;
8448+ type_reference * ref ;
8449+
8450+ ZEND_PARSE_PARAMETERS_NONE ();
8451+ GET_REFLECTION_OBJECT_PTR (ref );
8452+
8453+ if (!ZEND_TYPE_HAS_TYPE_PARAMETER (ref -> type )) {
8454+ RETURN_EMPTY_STRING ();
8455+ }
8456+ zend_type_parameter_ref * tp = ZEND_TYPE_TYPE_PARAMETER (ref -> type );
8457+ RETURN_STR_COPY (tp -> name );
8458+ }
8459+
8460+ ZEND_METHOD (ReflectionNamedType , hasGenericArguments )
8461+ {
8462+ ZEND_PARSE_PARAMETERS_NONE ();
8463+ /* TODO(azjezz): pre-erasure type-argument exposure on use-site named types requires
8464+ * pre-erasure storage in the generic side table to be threaded into reflection_type_factory. */
8465+ RETURN_FALSE ;
8466+ }
8467+
8468+ ZEND_METHOD (ReflectionNamedType , getGenericArguments )
8469+ {
8470+ ZEND_PARSE_PARAMETERS_NONE ();
8471+ array_init (return_value );
8472+ }
8473+
81598474PHP_MINIT_FUNCTION (reflection ) /* {{{ */
81608475{
81618476 memcpy (& reflection_object_handlers , & std_object_handlers , sizeof (zend_object_handlers ));
@@ -8261,6 +8576,16 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
82618576
82628577 reflection_property_hook_type_ptr = register_class_PropertyHookType ();
82638578
8579+ reflection_generic_variance_ptr = register_class_ReflectionGenericVariance ();
8580+
8581+ reflection_generic_type_parameter_ptr = register_class_ReflectionGenericTypeParameter (reflector_ptr );
8582+ reflection_generic_type_parameter_ptr -> create_object = reflection_objects_new ;
8583+ reflection_generic_type_parameter_ptr -> default_object_handlers = & reflection_object_handlers ;
8584+
8585+ reflection_type_parameter_reference_ptr = register_class_ReflectionTypeParameterReference (reflection_type_ptr );
8586+ reflection_type_parameter_reference_ptr -> create_object = reflection_objects_new ;
8587+ reflection_type_parameter_reference_ptr -> default_object_handlers = & reflection_object_handlers ;
8588+
82648589 REFLECTION_G (key_initialized ) = false;
82658590
82668591 return SUCCESS ;
0 commit comments