29
29
30
30
static void add_dependency_obligation (zend_class_entry * ce , zend_class_entry * dependency_ce );
31
31
static void add_compatibility_obligation (
32
- zend_class_entry * ce , const zend_function * child_fn , const zend_function * parent_fn ,
33
- zend_class_entry * parent_scope );
32
+ zend_class_entry * ce , const zend_function * child_fn , zend_class_entry * child_scope ,
33
+ const zend_function * parent_fn , zend_class_entry * parent_scope );
34
34
static void add_property_compatibility_obligation (
35
35
zend_class_entry * ce , const zend_property_info * child_prop ,
36
36
const zend_property_info * parent_prop );
@@ -522,12 +522,12 @@ static inheritance_status zend_do_perform_arg_type_hint_check(
522
522
}
523
523
/* }}} */
524
524
525
- /* For abstract trait methods, proto_scope will differ from proto->common.scope,
525
+ /* For trait methods, fe_scope/ proto_scope may differ from fe/ proto->common.scope,
526
526
* as self will refer to the self of the class the trait is used in, not the trait
527
527
* the method was declared in. */
528
528
static inheritance_status zend_do_perform_implementation_check (
529
- const zend_function * fe , const zend_function * proto ,
530
- zend_class_entry * proto_scope ) /* {{{ */
529
+ const zend_function * fe , zend_class_entry * fe_scope ,
530
+ const zend_function * proto , zend_class_entry * proto_scope ) /* {{{ */
531
531
{
532
532
uint32_t i , num_args , proto_num_args , fe_num_args ;
533
533
inheritance_status status , local_status ;
@@ -589,7 +589,7 @@ static inheritance_status zend_do_perform_implementation_check(
589
589
}
590
590
591
591
local_status = zend_do_perform_arg_type_hint_check (
592
- fe -> common . scope , fe_arg_info , proto_scope , proto_arg_info );
592
+ fe_scope , fe_arg_info , proto_scope , proto_arg_info );
593
593
594
594
if (UNEXPECTED (local_status != INHERITANCE_SUCCESS )) {
595
595
if (UNEXPECTED (local_status == INHERITANCE_ERROR )) {
@@ -614,7 +614,7 @@ static inheritance_status zend_do_perform_implementation_check(
614
614
}
615
615
616
616
local_status = zend_perform_covariant_type_check (
617
- fe -> common . scope , fe -> common .arg_info [-1 ].type ,
617
+ fe_scope , fe -> common .arg_info [-1 ].type ,
618
618
proto_scope , proto -> common .arg_info [-1 ].type );
619
619
620
620
if (UNEXPECTED (local_status != INHERITANCE_SUCCESS )) {
@@ -778,10 +778,11 @@ static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
778
778
}
779
779
780
780
static void ZEND_COLD emit_incompatible_method_error (
781
- const zend_function * child , const zend_function * parent , zend_class_entry * parent_scope ,
781
+ const zend_function * child , zend_class_entry * child_scope ,
782
+ const zend_function * parent , zend_class_entry * parent_scope ,
782
783
inheritance_status status ) {
783
784
zend_string * parent_prototype = zend_get_function_declaration (parent , parent_scope );
784
- zend_string * child_prototype = zend_get_function_declaration (child , child -> common . scope );
785
+ zend_string * child_prototype = zend_get_function_declaration (child , child_scope );
785
786
if (status == INHERITANCE_UNRESOLVED ) {
786
787
/* Fetch the first unresolved class from registered autoloads */
787
788
zend_string * unresolved_class = NULL ;
@@ -803,23 +804,26 @@ static void ZEND_COLD emit_incompatible_method_error(
803
804
}
804
805
805
806
static void perform_delayable_implementation_check (
806
- zend_class_entry * ce , const zend_function * fe ,
807
+ zend_class_entry * ce ,
808
+ const zend_function * fe , zend_class_entry * fe_scope ,
807
809
const zend_function * proto , zend_class_entry * proto_scope )
808
810
{
809
- inheritance_status status = zend_do_perform_implementation_check (fe , proto , proto_scope );
811
+ inheritance_status status =
812
+ zend_do_perform_implementation_check (fe , fe_scope , proto , proto_scope );
810
813
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
811
814
if (EXPECTED (status == INHERITANCE_UNRESOLVED )) {
812
- add_compatibility_obligation (ce , fe , proto , proto_scope );
815
+ add_compatibility_obligation (ce , fe , fe_scope , proto , proto_scope );
813
816
} else {
814
817
ZEND_ASSERT (status == INHERITANCE_ERROR );
815
- emit_incompatible_method_error (fe , proto , proto_scope , status );
818
+ emit_incompatible_method_error (fe , fe_scope , proto , proto_scope , status );
816
819
}
817
820
}
818
821
}
819
822
820
823
static zend_always_inline inheritance_status do_inheritance_check_on_method_ex (
821
- zend_function * child , zend_function * parent ,
822
- zend_class_entry * ce , zend_class_entry * parent_scope , zval * child_zv ,
824
+ zend_function * child , zend_class_entry * child_scope ,
825
+ zend_function * parent , zend_class_entry * parent_scope ,
826
+ zend_class_entry * ce , zval * child_zv ,
823
827
zend_bool check_visibility , zend_bool check_only , zend_bool checked ) /* {{{ */
824
828
{
825
829
uint32_t child_flags ;
@@ -919,22 +923,21 @@ static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
919
923
920
924
if (!checked ) {
921
925
if (check_only ) {
922
- return zend_do_perform_implementation_check (child , parent , parent_scope );
926
+ return zend_do_perform_implementation_check (child , child_scope , parent , parent_scope );
923
927
}
924
- perform_delayable_implementation_check (ce , child , parent , parent_scope );
928
+ perform_delayable_implementation_check (ce , child , child_scope , parent , parent_scope );
925
929
}
926
930
return INHERITANCE_SUCCESS ;
927
931
}
928
932
/* }}} */
929
933
930
934
static zend_never_inline void do_inheritance_check_on_method (
931
- zend_function * child , zend_function * parent ,
932
- zend_class_entry * ce , zend_class_entry * parent_scope ,
933
- zval * child_zv , zend_bool check_visibility ) /* {{{ */
935
+ zend_function * child , zend_class_entry * child_scope ,
936
+ zend_function * parent , zend_class_entry * parent_scope ,
937
+ zend_class_entry * ce , zval * child_zv , zend_bool check_visibility )
934
938
{
935
- do_inheritance_check_on_method_ex (child , parent , ce , parent_scope , child_zv , check_visibility , 0 , 0 );
939
+ do_inheritance_check_on_method_ex (child , child_scope , parent , parent_scope , ce , child_zv , check_visibility , 0 , 0 );
936
940
}
937
- /* }}} */
938
941
939
942
static zend_always_inline void do_inherit_method (zend_string * key , zend_function * parent , zend_class_entry * ce , zend_bool is_interface , zend_bool checked ) /* {{{ */
940
943
{
@@ -950,11 +953,12 @@ static zend_always_inline void do_inherit_method(zend_string *key, zend_function
950
953
951
954
if (checked ) {
952
955
do_inheritance_check_on_method_ex (
953
- func , parent , ce , parent -> common .scope , child ,
956
+ func , func -> common . scope , parent , parent -> common .scope , ce , child ,
954
957
/* check_visibility */ 1 , 0 , checked );
955
958
} else {
956
959
do_inheritance_check_on_method (
957
- func , parent , ce , parent -> common .scope , child , /* check_visibility */ 1 );
960
+ func , func -> common .scope , parent , parent -> common .scope , ce , child ,
961
+ /* check_visibility */ 1 );
958
962
}
959
963
} else {
960
964
@@ -1557,6 +1561,12 @@ static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry
1557
1561
}
1558
1562
/* }}} */
1559
1563
1564
+ static zend_class_entry * fixup_trait_scope (const zend_function * fn , zend_class_entry * ce )
1565
+ {
1566
+ /* self in trait methods should be resolved to the using class, not the trait. */
1567
+ return fn -> common .scope -> ce_flags & ZEND_ACC_TRAIT ? ce : fn -> common .scope ;
1568
+ }
1569
+
1560
1570
static void zend_add_trait_method (zend_class_entry * ce , zend_string * name , zend_string * key , zend_function * fn ) /* {{{ */
1561
1571
{
1562
1572
zend_function * existing_fn = NULL ;
@@ -1577,12 +1587,10 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
1577
1587
* As such, "abstract protected" was sometimes used to indicate trait requirements,
1578
1588
* even though the "implementing" method was private. Do not check visibility
1579
1589
* requirements to maintain backwards-compatibility with such usage.
1580
- *
1581
- * The parent_scope passed here is not fn->common.scope, because we want "self" to be
1582
- * resolved against the using class, not the declaring trait.
1583
1590
*/
1584
1591
do_inheritance_check_on_method (
1585
- existing_fn , fn , ce , /* parent_scope */ ce , NULL , /* check_visibility */ 0 );
1592
+ existing_fn , fixup_trait_scope (existing_fn , ce ), fn , fixup_trait_scope (fn , ce ),
1593
+ ce , NULL , /* check_visibility */ 0 );
1586
1594
return ;
1587
1595
}
1588
1596
@@ -1597,10 +1605,11 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
1597
1605
ZSTR_VAL (ce -> name ), ZSTR_VAL (name ),
1598
1606
ZSTR_VAL (existing_fn -> common .scope -> name ), ZSTR_VAL (existing_fn -> common .function_name ));
1599
1607
} else {
1600
- /* inherited members are overridden by members inserted by traits */
1601
- /* check whether the trait method fulfills the inheritance requirements */
1608
+ /* Inherited members are overridden by members inserted by traits.
1609
+ * Check whether the trait method fulfills the inheritance requirements. */
1602
1610
do_inheritance_check_on_method (
1603
- fn , existing_fn , ce , existing_fn -> common .scope , NULL , /* check_visibility */ 1 );
1611
+ fn , fixup_trait_scope (fn , ce ), existing_fn , fixup_trait_scope (existing_fn , ce ),
1612
+ ce , NULL , /* check_visibility */ 1 );
1604
1613
}
1605
1614
}
1606
1615
@@ -2186,6 +2195,7 @@ typedef struct {
2186
2195
* so use copies of functions here as well. */
2187
2196
zend_function parent_fn ;
2188
2197
zend_function child_fn ;
2198
+ zend_class_entry * child_scope ;
2189
2199
zend_class_entry * parent_scope ;
2190
2200
};
2191
2201
struct {
@@ -2234,8 +2244,9 @@ static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *de
2234
2244
}
2235
2245
2236
2246
static void add_compatibility_obligation (
2237
- zend_class_entry * ce , const zend_function * child_fn , const zend_function * parent_fn ,
2238
- zend_class_entry * parent_scope ) {
2247
+ zend_class_entry * ce ,
2248
+ const zend_function * child_fn , zend_class_entry * child_scope ,
2249
+ const zend_function * parent_fn , zend_class_entry * parent_scope ) {
2239
2250
HashTable * obligations = get_or_init_obligations_for_class (ce );
2240
2251
variance_obligation * obligation = emalloc (sizeof (variance_obligation ));
2241
2252
obligation -> type = OBLIGATION_COMPATIBILITY ;
@@ -2250,6 +2261,7 @@ static void add_compatibility_obligation(
2250
2261
} else {
2251
2262
memcpy (& obligation -> parent_fn , parent_fn , sizeof (zend_op_array ));
2252
2263
}
2264
+ obligation -> child_scope = child_scope ;
2253
2265
obligation -> parent_scope = parent_scope ;
2254
2266
zend_hash_next_index_insert_ptr (obligations , obligation );
2255
2267
}
@@ -2279,14 +2291,16 @@ static int check_variance_obligation(zval *zv) {
2279
2291
}
2280
2292
} else if (obligation -> type == OBLIGATION_COMPATIBILITY ) {
2281
2293
inheritance_status status = zend_do_perform_implementation_check (
2282
- & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope );
2294
+ & obligation -> child_fn , obligation -> child_scope ,
2295
+ & obligation -> parent_fn , obligation -> parent_scope );
2283
2296
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
2284
2297
if (EXPECTED (status == INHERITANCE_UNRESOLVED )) {
2285
2298
return ZEND_HASH_APPLY_KEEP ;
2286
2299
}
2287
2300
ZEND_ASSERT (status == INHERITANCE_ERROR );
2288
2301
emit_incompatible_method_error (
2289
- & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope , status );
2302
+ & obligation -> child_fn , obligation -> child_scope ,
2303
+ & obligation -> parent_fn , obligation -> parent_scope , status );
2290
2304
}
2291
2305
/* Either the compatibility check was successful or only threw a warning. */
2292
2306
} else {
@@ -2353,10 +2367,12 @@ static void report_variance_errors(zend_class_entry *ce) {
2353
2367
/* Just used to populate the delayed_autoloads table,
2354
2368
* which will be used when printing the "unresolved" error. */
2355
2369
inheritance_status status = zend_do_perform_implementation_check (
2356
- & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope );
2370
+ & obligation -> child_fn , obligation -> child_scope ,
2371
+ & obligation -> parent_fn , obligation -> parent_scope );
2357
2372
ZEND_ASSERT (status == INHERITANCE_UNRESOLVED );
2358
2373
emit_incompatible_method_error (
2359
- & obligation -> child_fn , & obligation -> parent_fn , obligation -> parent_scope , status );
2374
+ & obligation -> child_fn , obligation -> child_scope ,
2375
+ & obligation -> parent_fn , obligation -> parent_scope , status );
2360
2376
} else if (obligation -> type == OBLIGATION_PROPERTY_COMPATIBILITY ) {
2361
2377
emit_incompatible_property_error (obligation -> child_prop , obligation -> parent_prop );
2362
2378
} else {
@@ -2482,8 +2498,9 @@ static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_e
2482
2498
zend_function * child_func = Z_FUNC_P (zv );
2483
2499
inheritance_status status =
2484
2500
do_inheritance_check_on_method_ex (
2485
- child_func , parent_func , ce , parent_func -> common .scope , NULL ,
2486
- /* check_visibility */ 1 , 1 , 0 );
2501
+ child_func , child_func -> common .scope ,
2502
+ parent_func , parent_func -> common .scope ,
2503
+ ce , NULL , /* check_visibility */ 1 , 1 , 0 );
2487
2504
2488
2505
if (UNEXPECTED (status != INHERITANCE_SUCCESS )) {
2489
2506
return status ;
0 commit comments