@@ -157,6 +157,7 @@ typedef struct _attribute_reference {
157
157
zend_class_entry * scope ;
158
158
zend_string * filename ;
159
159
uint32_t target ;
160
+ bool on_property_hook ;
160
161
} attribute_reference ;
161
162
162
163
typedef enum {
@@ -1236,7 +1237,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c
1236
1237
1237
1238
/* {{{ reflection_attribute_factory */
1238
1239
static void reflection_attribute_factory (zval * object , HashTable * attributes , zend_attribute * data ,
1239
- zend_class_entry * scope , uint32_t target , zend_string * filename )
1240
+ zend_class_entry * scope , uint32_t target , zend_string * filename , bool on_property_hook )
1240
1241
{
1241
1242
reflection_object * intern ;
1242
1243
attribute_reference * reference ;
@@ -1249,14 +1250,16 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze
1249
1250
reference -> scope = scope ;
1250
1251
reference -> filename = filename ? zend_string_copy (filename ) : NULL ;
1251
1252
reference -> target = target ;
1253
+ reference -> on_property_hook = on_property_hook ;
1252
1254
intern -> ptr = reference ;
1253
1255
intern -> ref_type = REF_TYPE_ATTRIBUTE ;
1254
1256
ZVAL_STR_COPY (reflection_prop_name (object ), data -> name );
1255
1257
}
1256
1258
/* }}} */
1257
1259
1258
1260
static int read_attributes (zval * ret , HashTable * attributes , zend_class_entry * scope ,
1259
- uint32_t offset , uint32_t target , zend_string * name , zend_class_entry * base , zend_string * filename ) /* {{{ */
1261
+ uint32_t offset , uint32_t target , zend_string * name , zend_class_entry * base , zend_string * filename ,
1262
+ bool on_property_hook ) /* {{{ */
1260
1263
{
1261
1264
ZEND_ASSERT (attributes != NULL );
1262
1265
@@ -1269,7 +1272,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
1269
1272
1270
1273
ZEND_HASH_PACKED_FOREACH_PTR (attributes , attr ) {
1271
1274
if (attr -> offset == offset && zend_string_equals (attr -> lcname , filter )) {
1272
- reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename );
1275
+ reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename , on_property_hook );
1273
1276
add_next_index_zval (ret , & tmp );
1274
1277
}
1275
1278
} ZEND_HASH_FOREACH_END ();
@@ -1301,7 +1304,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
1301
1304
}
1302
1305
}
1303
1306
1304
- reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename );
1307
+ reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename , on_property_hook );
1305
1308
add_next_index_zval (ret , & tmp );
1306
1309
} ZEND_HASH_FOREACH_END ();
1307
1310
@@ -1310,7 +1313,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
1310
1313
/* }}} */
1311
1314
1312
1315
static void reflect_attributes (INTERNAL_FUNCTION_PARAMETERS , HashTable * attributes ,
1313
- uint32_t offset , zend_class_entry * scope , uint32_t target , zend_string * filename ) /* {{{ */
1316
+ uint32_t offset , zend_class_entry * scope , uint32_t target , zend_string * filename , bool on_property_hook ) /* {{{ */
1314
1317
{
1315
1318
zend_string * name = NULL ;
1316
1319
zend_long flags = 0 ;
@@ -1343,7 +1346,7 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut
1343
1346
1344
1347
array_init (return_value );
1345
1348
1346
- if (FAILURE == read_attributes (return_value , attributes , scope , offset , target , name , base , filename )) {
1349
+ if (FAILURE == read_attributes (return_value , attributes , scope , offset , target , name , base , filename , on_property_hook )) {
1347
1350
RETURN_THROWS ();
1348
1351
}
1349
1352
}
@@ -2048,15 +2051,21 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes)
2048
2051
2049
2052
GET_REFLECTION_OBJECT_PTR (fptr );
2050
2053
2054
+ bool on_property_hook = false;
2055
+
2051
2056
if (fptr -> common .scope && (fptr -> common .fn_flags & (ZEND_ACC_CLOSURE |ZEND_ACC_FAKE_CLOSURE )) != ZEND_ACC_CLOSURE ) {
2052
2057
target = ZEND_ATTRIBUTE_TARGET_METHOD ;
2058
+ if (fptr -> common .prop_info != NULL ) {
2059
+ on_property_hook = true;
2060
+ }
2053
2061
} else {
2054
2062
target = ZEND_ATTRIBUTE_TARGET_FUNCTION ;
2055
2063
}
2056
2064
2057
2065
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
2058
2066
fptr -> common .attributes , 0 , fptr -> common .scope , target ,
2059
- fptr -> type == ZEND_USER_FUNCTION ? fptr -> op_array .filename : NULL );
2067
+ fptr -> type == ZEND_USER_FUNCTION ? fptr -> op_array .filename : NULL ,
2068
+ on_property_hook );
2060
2069
}
2061
2070
/* }}} */
2062
2071
@@ -2898,7 +2907,8 @@ ZEND_METHOD(ReflectionParameter, getAttributes)
2898
2907
2899
2908
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
2900
2909
attributes , param -> offset + 1 , scope , ZEND_ATTRIBUTE_TARGET_PARAMETER ,
2901
- param -> fptr -> type == ZEND_USER_FUNCTION ? param -> fptr -> op_array .filename : NULL );
2910
+ param -> fptr -> type == ZEND_USER_FUNCTION ? param -> fptr -> op_array .filename : NULL ,
2911
+ false);
2902
2912
}
2903
2913
2904
2914
/* {{{ Returns the index of the parameter, starting from 0 */
@@ -4020,7 +4030,8 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes)
4020
4030
4021
4031
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
4022
4032
ref -> attributes , 0 , ref -> ce , ZEND_ATTRIBUTE_TARGET_CLASS_CONST ,
4023
- ref -> ce -> type == ZEND_USER_CLASS ? ref -> ce -> info .user .filename : NULL );
4033
+ ref -> ce -> type == ZEND_USER_CLASS ? ref -> ce -> info .user .filename : NULL ,
4034
+ false);
4024
4035
}
4025
4036
/* }}} */
4026
4037
@@ -4425,7 +4436,8 @@ ZEND_METHOD(ReflectionClass, getAttributes)
4425
4436
4426
4437
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
4427
4438
ce -> attributes , 0 , ce , ZEND_ATTRIBUTE_TARGET_CLASS ,
4428
- ce -> type == ZEND_USER_CLASS ? ce -> info .user .filename : NULL );
4439
+ ce -> type == ZEND_USER_CLASS ? ce -> info .user .filename : NULL ,
4440
+ false);
4429
4441
}
4430
4442
/* }}} */
4431
4443
@@ -6353,7 +6365,8 @@ ZEND_METHOD(ReflectionProperty, getAttributes)
6353
6365
6354
6366
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
6355
6367
ref -> prop -> attributes , 0 , ref -> prop -> ce , ZEND_ATTRIBUTE_TARGET_PROPERTY ,
6356
- ref -> prop -> ce -> type == ZEND_USER_CLASS ? ref -> prop -> ce -> info .user .filename : NULL );
6368
+ ref -> prop -> ce -> type == ZEND_USER_CLASS ? ref -> prop -> ce -> info .user .filename : NULL ,
6369
+ false);
6357
6370
}
6358
6371
/* }}} */
6359
6372
@@ -7319,13 +7332,21 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
7319
7332
if (config != NULL && config -> validator != NULL ) {
7320
7333
config -> validator (
7321
7334
attr -> data ,
7322
- flags | ZEND_ATTRIBUTE_DELAYED_TARGET_VALIDATION ,
7335
+ attr -> target | ZEND_ATTRIBUTE_DELAYED_TARGET_VALIDATION ,
7323
7336
attr -> scope
7324
7337
);
7325
7338
if (EG (exception )) {
7326
7339
RETURN_THROWS ();
7327
7340
}
7328
7341
}
7342
+ /* For #[NoDiscard], the attribute does not work on property hooks, but
7343
+ * at runtime the validator has no way to access the method that an
7344
+ * attribute is applied to, attr->scope is just the overall class entry
7345
+ * that the method is a part of. */
7346
+ if (ce == zend_ce_nodiscard && attr -> on_property_hook ) {
7347
+ zend_throw_error (NULL , "#[\\NoDiscard] is not supported for property hooks" );;
7348
+ RETURN_THROWS ();
7349
+ }
7329
7350
}
7330
7351
7331
7352
/* Repetition validation is done even if #[DelayedTargetValidation] is used
@@ -7857,7 +7878,7 @@ ZEND_METHOD(ReflectionConstant, getAttributes)
7857
7878
7858
7879
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
7859
7880
const_ -> attributes , 0 , NULL , ZEND_ATTRIBUTE_TARGET_CONST ,
7860
- const_ -> filename );
7881
+ const_ -> filename , false );
7861
7882
}
7862
7883
7863
7884
ZEND_METHOD (ReflectionConstant , __toString )
0 commit comments