@@ -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 {
@@ -1254,7 +1255,7 @@ static void _extension_string(smart_str *str, const zend_module_entry *module, c
1254
1255
1255
1256
/* {{{ reflection_attribute_factory */
1256
1257
static void reflection_attribute_factory (zval * object , HashTable * attributes , zend_attribute * data ,
1257
- zend_class_entry * scope , uint32_t target , zend_string * filename )
1258
+ zend_class_entry * scope , uint32_t target , zend_string * filename , bool on_property_hook )
1258
1259
{
1259
1260
reflection_object * intern ;
1260
1261
attribute_reference * reference ;
@@ -1267,14 +1268,16 @@ static void reflection_attribute_factory(zval *object, HashTable *attributes, ze
1267
1268
reference -> scope = scope ;
1268
1269
reference -> filename = filename ? zend_string_copy (filename ) : NULL ;
1269
1270
reference -> target = target ;
1271
+ reference -> on_property_hook = on_property_hook ;
1270
1272
intern -> ptr = reference ;
1271
1273
intern -> ref_type = REF_TYPE_ATTRIBUTE ;
1272
1274
ZVAL_STR_COPY (reflection_prop_name (object ), data -> name );
1273
1275
}
1274
1276
/* }}} */
1275
1277
1276
1278
static int read_attributes (zval * ret , HashTable * attributes , zend_class_entry * scope ,
1277
- uint32_t offset , uint32_t target , zend_string * name , zend_class_entry * base , zend_string * filename ) /* {{{ */
1279
+ uint32_t offset , uint32_t target , zend_string * name , zend_class_entry * base , zend_string * filename ,
1280
+ bool on_property_hook ) /* {{{ */
1278
1281
{
1279
1282
ZEND_ASSERT (attributes != NULL );
1280
1283
@@ -1287,7 +1290,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
1287
1290
1288
1291
ZEND_HASH_PACKED_FOREACH_PTR (attributes , attr ) {
1289
1292
if (attr -> offset == offset && zend_string_equals (attr -> lcname , filter )) {
1290
- reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename );
1293
+ reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename , on_property_hook );
1291
1294
add_next_index_zval (ret , & tmp );
1292
1295
}
1293
1296
} ZEND_HASH_FOREACH_END ();
@@ -1319,7 +1322,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
1319
1322
}
1320
1323
}
1321
1324
1322
- reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename );
1325
+ reflection_attribute_factory (& tmp , attributes , attr , scope , target , filename , on_property_hook );
1323
1326
add_next_index_zval (ret , & tmp );
1324
1327
} ZEND_HASH_FOREACH_END ();
1325
1328
@@ -1328,7 +1331,7 @@ static int read_attributes(zval *ret, HashTable *attributes, zend_class_entry *s
1328
1331
/* }}} */
1329
1332
1330
1333
static void reflect_attributes (INTERNAL_FUNCTION_PARAMETERS , HashTable * attributes ,
1331
- uint32_t offset , zend_class_entry * scope , uint32_t target , zend_string * filename ) /* {{{ */
1334
+ uint32_t offset , zend_class_entry * scope , uint32_t target , zend_string * filename , bool on_property_hook ) /* {{{ */
1332
1335
{
1333
1336
zend_string * name = NULL ;
1334
1337
zend_long flags = 0 ;
@@ -1361,7 +1364,7 @@ static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attribut
1361
1364
1362
1365
array_init (return_value );
1363
1366
1364
- if (FAILURE == read_attributes (return_value , attributes , scope , offset , target , name , base , filename )) {
1367
+ if (FAILURE == read_attributes (return_value , attributes , scope , offset , target , name , base , filename , on_property_hook )) {
1365
1368
RETURN_THROWS ();
1366
1369
}
1367
1370
}
@@ -2066,15 +2069,21 @@ ZEND_METHOD(ReflectionFunctionAbstract, getAttributes)
2066
2069
2067
2070
GET_REFLECTION_OBJECT_PTR (fptr );
2068
2071
2072
+ bool on_property_hook = false;
2073
+
2069
2074
if (fptr -> common .scope && (fptr -> common .fn_flags & (ZEND_ACC_CLOSURE |ZEND_ACC_FAKE_CLOSURE )) != ZEND_ACC_CLOSURE ) {
2070
2075
target = ZEND_ATTRIBUTE_TARGET_METHOD ;
2076
+ if (fptr -> common .prop_info != NULL ) {
2077
+ on_property_hook = true;
2078
+ }
2071
2079
} else {
2072
2080
target = ZEND_ATTRIBUTE_TARGET_FUNCTION ;
2073
2081
}
2074
2082
2075
2083
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
2076
2084
fptr -> common .attributes , 0 , fptr -> common .scope , target ,
2077
- fptr -> type == ZEND_USER_FUNCTION ? fptr -> op_array .filename : NULL );
2085
+ fptr -> type == ZEND_USER_FUNCTION ? fptr -> op_array .filename : NULL ,
2086
+ on_property_hook );
2078
2087
}
2079
2088
/* }}} */
2080
2089
@@ -2916,7 +2925,8 @@ ZEND_METHOD(ReflectionParameter, getAttributes)
2916
2925
2917
2926
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
2918
2927
attributes , param -> offset + 1 , scope , ZEND_ATTRIBUTE_TARGET_PARAMETER ,
2919
- param -> fptr -> type == ZEND_USER_FUNCTION ? param -> fptr -> op_array .filename : NULL );
2928
+ param -> fptr -> type == ZEND_USER_FUNCTION ? param -> fptr -> op_array .filename : NULL ,
2929
+ false);
2920
2930
}
2921
2931
2922
2932
/* {{{ Returns the index of the parameter, starting from 0 */
@@ -4038,7 +4048,8 @@ ZEND_METHOD(ReflectionClassConstant, getAttributes)
4038
4048
4039
4049
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
4040
4050
ref -> attributes , 0 , ref -> ce , ZEND_ATTRIBUTE_TARGET_CLASS_CONST ,
4041
- ref -> ce -> type == ZEND_USER_CLASS ? ref -> ce -> info .user .filename : NULL );
4051
+ ref -> ce -> type == ZEND_USER_CLASS ? ref -> ce -> info .user .filename : NULL ,
4052
+ false);
4042
4053
}
4043
4054
/* }}} */
4044
4055
@@ -4443,7 +4454,8 @@ ZEND_METHOD(ReflectionClass, getAttributes)
4443
4454
4444
4455
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
4445
4456
ce -> attributes , 0 , ce , ZEND_ATTRIBUTE_TARGET_CLASS ,
4446
- ce -> type == ZEND_USER_CLASS ? ce -> info .user .filename : NULL );
4457
+ ce -> type == ZEND_USER_CLASS ? ce -> info .user .filename : NULL ,
4458
+ false);
4447
4459
}
4448
4460
/* }}} */
4449
4461
@@ -6385,7 +6397,8 @@ ZEND_METHOD(ReflectionProperty, getAttributes)
6385
6397
6386
6398
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
6387
6399
ref -> prop -> attributes , 0 , ref -> prop -> ce , ZEND_ATTRIBUTE_TARGET_PROPERTY ,
6388
- ref -> prop -> ce -> type == ZEND_USER_CLASS ? ref -> prop -> ce -> info .user .filename : NULL );
6400
+ ref -> prop -> ce -> type == ZEND_USER_CLASS ? ref -> prop -> ce -> info .user .filename : NULL ,
6401
+ false);
6389
6402
}
6390
6403
/* }}} */
6391
6404
@@ -7348,13 +7361,21 @@ ZEND_METHOD(ReflectionAttribute, newInstance)
7348
7361
if (config != NULL && config -> validator != NULL ) {
7349
7362
config -> validator (
7350
7363
attr -> data ,
7351
- flags | ZEND_ATTRIBUTE_DELAYED_TARGET_VALIDATION ,
7364
+ attr -> target | ZEND_ATTRIBUTE_DELAYED_TARGET_VALIDATION ,
7352
7365
attr -> scope
7353
7366
);
7354
7367
if (EG (exception )) {
7355
7368
RETURN_THROWS ();
7356
7369
}
7357
7370
}
7371
+ /* For #[NoDiscard], the attribute does not work on property hooks, but
7372
+ * at runtime the validator has no way to access the method that an
7373
+ * attribute is applied to, attr->scope is just the overall class entry
7374
+ * that the method is a part of. */
7375
+ if (ce == zend_ce_nodiscard && attr -> on_property_hook ) {
7376
+ zend_throw_error (NULL , "#[\\NoDiscard] is not supported for property hooks" );;
7377
+ RETURN_THROWS ();
7378
+ }
7358
7379
}
7359
7380
7360
7381
/* Repetition validation is done even if #[DelayedTargetValidation] is used
@@ -7886,7 +7907,7 @@ ZEND_METHOD(ReflectionConstant, getAttributes)
7886
7907
7887
7908
reflect_attributes (INTERNAL_FUNCTION_PARAM_PASSTHRU ,
7888
7909
const_ -> attributes , 0 , NULL , ZEND_ATTRIBUTE_TARGET_CONST ,
7889
- const_ -> filename );
7910
+ const_ -> filename , false );
7890
7911
}
7891
7912
7892
7913
ZEND_METHOD (ReflectionConstant , __toString )
0 commit comments