@@ -90,22 +90,24 @@ static zend_function *zend_duplicate_function(zend_function *func, zend_class_en
90
90
91
91
static void do_inherit_parent_constructor (zend_class_entry * ce ) /* {{{ */
92
92
{
93
- ZEND_ASSERT (ce -> parent != NULL );
93
+ zend_class_entry * parent = ce -> parent ;
94
+
95
+ ZEND_ASSERT (parent != NULL );
94
96
95
97
/* You cannot change create_object */
96
- ce -> create_object = ce -> parent -> create_object ;
98
+ ce -> create_object = parent -> create_object ;
97
99
98
100
/* Inherit special functions if needed */
99
101
if (EXPECTED (!ce -> get_iterator )) {
100
- ce -> get_iterator = ce -> parent -> get_iterator ;
102
+ ce -> get_iterator = parent -> get_iterator ;
101
103
}
102
- if (EXPECTED (!ce -> iterator_funcs_ptr ) && UNEXPECTED (ce -> parent -> iterator_funcs_ptr )) {
104
+ if (EXPECTED (!ce -> iterator_funcs_ptr ) && UNEXPECTED (parent -> iterator_funcs_ptr )) {
103
105
if (ce -> type == ZEND_INTERNAL_CLASS ) {
104
106
ce -> iterator_funcs_ptr = calloc (1 , sizeof (zend_class_iterator_funcs ));
105
- if (ce -> parent -> iterator_funcs_ptr -> zf_new_iterator ) {
107
+ if (parent -> iterator_funcs_ptr -> zf_new_iterator ) {
106
108
ce -> iterator_funcs_ptr -> zf_new_iterator = zend_hash_str_find_ptr (& ce -> function_table , "getiterator" , sizeof ("getiterator" ) - 1 );
107
109
}
108
- if (ce -> parent -> iterator_funcs_ptr -> zf_current ) {
110
+ if (parent -> iterator_funcs_ptr -> zf_current ) {
109
111
ce -> iterator_funcs_ptr -> zf_rewind = zend_hash_str_find_ptr (& ce -> function_table , "rewind" , sizeof ("rewind" ) - 1 );
110
112
ce -> iterator_funcs_ptr -> zf_valid = zend_hash_str_find_ptr (& ce -> function_table , "valid" , sizeof ("valid" ) - 1 );
111
113
ce -> iterator_funcs_ptr -> zf_key = zend_hash_str_find_ptr (& ce -> function_table , "key" , sizeof ("key" ) - 1 );
@@ -118,52 +120,52 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
118
120
}
119
121
}
120
122
if (EXPECTED (!ce -> __get )) {
121
- ce -> __get = ce -> parent -> __get ;
123
+ ce -> __get = parent -> __get ;
122
124
}
123
125
if (EXPECTED (!ce -> __set )) {
124
- ce -> __set = ce -> parent -> __set ;
126
+ ce -> __set = parent -> __set ;
125
127
}
126
128
if (EXPECTED (!ce -> __unset )) {
127
- ce -> __unset = ce -> parent -> __unset ;
129
+ ce -> __unset = parent -> __unset ;
128
130
}
129
131
if (EXPECTED (!ce -> __isset )) {
130
- ce -> __isset = ce -> parent -> __isset ;
132
+ ce -> __isset = parent -> __isset ;
131
133
}
132
134
if (EXPECTED (!ce -> __call )) {
133
- ce -> __call = ce -> parent -> __call ;
135
+ ce -> __call = parent -> __call ;
134
136
}
135
137
if (EXPECTED (!ce -> __callstatic )) {
136
- ce -> __callstatic = ce -> parent -> __callstatic ;
138
+ ce -> __callstatic = parent -> __callstatic ;
137
139
}
138
140
if (EXPECTED (!ce -> __tostring )) {
139
- ce -> __tostring = ce -> parent -> __tostring ;
141
+ ce -> __tostring = parent -> __tostring ;
140
142
}
141
143
if (EXPECTED (!ce -> clone )) {
142
- ce -> clone = ce -> parent -> clone ;
144
+ ce -> clone = parent -> clone ;
143
145
}
144
146
if (EXPECTED (!ce -> serialize )) {
145
- ce -> serialize = ce -> parent -> serialize ;
147
+ ce -> serialize = parent -> serialize ;
146
148
}
147
149
if (EXPECTED (!ce -> unserialize )) {
148
- ce -> unserialize = ce -> parent -> unserialize ;
150
+ ce -> unserialize = parent -> unserialize ;
149
151
}
150
152
if (!ce -> destructor ) {
151
- ce -> destructor = ce -> parent -> destructor ;
153
+ ce -> destructor = parent -> destructor ;
152
154
}
153
155
if (EXPECTED (!ce -> __debugInfo )) {
154
- ce -> __debugInfo = ce -> parent -> __debugInfo ;
156
+ ce -> __debugInfo = parent -> __debugInfo ;
155
157
}
156
158
157
159
if (ce -> constructor ) {
158
- if (ce -> parent -> constructor && UNEXPECTED (ce -> parent -> constructor -> common .fn_flags & ZEND_ACC_FINAL )) {
160
+ if (parent -> constructor && UNEXPECTED (parent -> constructor -> common .fn_flags & ZEND_ACC_FINAL )) {
159
161
zend_error_noreturn (E_ERROR , "Cannot override final %s::%s() with %s::%s()" ,
160
- ZSTR_VAL (ce -> parent -> name ), ZSTR_VAL (ce -> parent -> constructor -> common .function_name ),
162
+ ZSTR_VAL (parent -> name ), ZSTR_VAL (parent -> constructor -> common .function_name ),
161
163
ZSTR_VAL (ce -> name ), ZSTR_VAL (ce -> constructor -> common .function_name ));
162
164
}
163
165
return ;
164
166
}
165
167
166
- ce -> constructor = ce -> parent -> constructor ;
168
+ ce -> constructor = parent -> constructor ;
167
169
}
168
170
/* }}} */
169
171
@@ -284,14 +286,14 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
284
286
* we still need to do the arg number checks. We are only willing to ignore this for internal
285
287
* functions because extensions don't always define arg_info.
286
288
*/
287
- if (!proto || (! proto -> common .arg_info && proto -> common .type != ZEND_USER_FUNCTION ) ) {
289
+ if (!proto -> common .arg_info && proto -> common .type != ZEND_USER_FUNCTION ) {
288
290
return 1 ;
289
291
}
290
292
291
293
/* Checks for constructors only if they are declared in an interface,
292
294
* or explicitly marked as abstract
293
295
*/
294
- if ((fe -> common .fn_flags & ZEND_ACC_CTOR )
296
+ if ((fe -> common .scope -> constructor == fe )
295
297
&& ((proto -> common .scope -> ce_flags & ZEND_ACC_INTERFACE ) == 0
296
298
&& (proto -> common .fn_flags & ZEND_ACC_ABSTRACT ) == 0 )) {
297
299
return 1 ;
@@ -584,55 +586,64 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
584
586
zend_error_noreturn (E_COMPILE_ERROR , "Cannot make non abstract method %s::%s() abstract in class %s" , ZEND_FN_SCOPE_NAME (parent ), ZSTR_VAL (child -> common .function_name ), ZEND_FN_SCOPE_NAME (child ));
585
587
}
586
588
587
- /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
588
- if (UNEXPECTED ((!(child_flags & ZEND_ACC_CTOR ) || (parent_flags & (ZEND_ACC_ABSTRACT | ZEND_ACC_IMPLEMENTED_ABSTRACT ))) &&
589
- (child_flags & ZEND_ACC_PPP_MASK ) > (parent_flags & ZEND_ACC_PPP_MASK ))) {
590
- zend_error_noreturn (E_COMPILE_ERROR , "Access level to %s::%s() must be %s (as in class %s)%s" , ZEND_FN_SCOPE_NAME (child ), ZSTR_VAL (child -> common .function_name ), zend_visibility_string (parent_flags ), ZEND_FN_SCOPE_NAME (parent ), (parent_flags & ZEND_ACC_PUBLIC ) ? "" : " or weaker" );
591
- }
592
-
593
589
if ((child_flags & ZEND_ACC_PRIVATE ) < (parent_flags & (ZEND_ACC_PRIVATE |ZEND_ACC_CHANGED ))) {
594
590
child -> common .fn_flags |= ZEND_ACC_CHANGED ;
595
591
}
596
592
597
- if (parent_flags & ZEND_ACC_PRIVATE ) {
598
- child -> common .prototype = NULL ;
599
- } else if (parent_flags & ZEND_ACC_ABSTRACT ) {
600
- child -> common .fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT ;
601
- child -> common .prototype = parent ;
602
- } else if (!(parent -> common .fn_flags & ZEND_ACC_CTOR )) {
603
- child -> common .prototype = parent -> common .prototype ? parent -> common .prototype : parent ;
604
- } else if (parent -> common .prototype && (parent -> common .prototype -> common .scope -> ce_flags & ZEND_ACC_INTERFACE )) {
605
- /* ctors only have a prototype if it comes from an interface */
606
- child -> common .prototype = parent -> common .prototype ? parent -> common .prototype : parent ;
607
- /* and if that is the case, we want to check inheritance against it */
608
- parent = child -> common .prototype ;
609
- }
610
-
611
- if (UNEXPECTED (!zend_do_perform_implementation_check (child , parent ))) {
612
- int error_level ;
613
- const char * error_verb ;
614
- zend_string * method_prototype = zend_get_function_declaration (parent );
615
- zend_string * child_prototype = zend_get_function_declaration (child );
616
-
617
- if (child -> common .prototype && (
618
- child -> common .prototype -> common .fn_flags & ZEND_ACC_ABSTRACT
619
- )) {
620
- error_level = E_COMPILE_ERROR ;
621
- error_verb = "must" ;
622
- } else if ((parent -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) &&
623
- (!(child -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) ||
624
- !zend_do_perform_type_hint_check (child , child -> common .arg_info - 1 , parent , parent -> common .arg_info - 1 ) ||
625
- (ZEND_TYPE_ALLOW_NULL (child -> common .arg_info [-1 ].type ) && !ZEND_TYPE_ALLOW_NULL (parent -> common .arg_info [-1 ].type )))) {
626
- error_level = E_COMPILE_ERROR ;
627
- error_verb = "must" ;
628
- } else {
629
- error_level = E_WARNING ;
630
- error_verb = "should" ;
593
+ do {
594
+ if (!(parent_flags & ZEND_ACC_PRIVATE )) {
595
+ if (parent_flags & ZEND_ACC_ABSTRACT ) {
596
+ child -> common .prototype = parent ;
597
+ } else {
598
+ zend_function * proto = parent -> common .prototype ;
599
+
600
+ if (parent -> common .scope -> constructor != parent ) {
601
+ child -> common .prototype = proto ? proto : parent ;
602
+ } else if (proto ) {
603
+ if (proto -> common .scope -> ce_flags & ZEND_ACC_INTERFACE ) {
604
+ /* ctors only have a prototype if it comes from an interface */
605
+ child -> common .prototype = proto ;
606
+ /* and if that is the case, we want to check inheritance against it */
607
+ parent = proto ;
608
+ } else if (!(proto -> common .fn_flags & ZEND_ACC_ABSTRACT )) {
609
+ break ;
610
+ }
611
+ } else {
612
+ break ;
613
+ }
614
+ }
615
+ /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
616
+ if ((child_flags & ZEND_ACC_PPP_MASK ) > (parent_flags & ZEND_ACC_PPP_MASK )) {
617
+ zend_error_noreturn (E_COMPILE_ERROR , "Access level to %s::%s() must be %s (as in class %s)%s" , ZEND_FN_SCOPE_NAME (child ), ZSTR_VAL (child -> common .function_name ), zend_visibility_string (parent_flags ), ZEND_FN_SCOPE_NAME (parent ), (parent_flags & ZEND_ACC_PUBLIC ) ? "" : " or weaker" );
618
+ }
619
+
620
+ if (UNEXPECTED (!zend_do_perform_implementation_check (child , parent ))) {
621
+ int error_level ;
622
+ const char * error_verb ;
623
+ zend_string * method_prototype = zend_get_function_declaration (parent );
624
+ zend_string * child_prototype = zend_get_function_declaration (child );
625
+
626
+ if (child -> common .prototype && (
627
+ child -> common .prototype -> common .fn_flags & ZEND_ACC_ABSTRACT
628
+ )) {
629
+ error_level = E_COMPILE_ERROR ;
630
+ error_verb = "must" ;
631
+ } else if ((parent -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) &&
632
+ (!(child -> common .fn_flags & ZEND_ACC_HAS_RETURN_TYPE ) ||
633
+ !zend_do_perform_type_hint_check (child , child -> common .arg_info - 1 , parent , parent -> common .arg_info - 1 ) ||
634
+ (ZEND_TYPE_ALLOW_NULL (child -> common .arg_info [-1 ].type ) && !ZEND_TYPE_ALLOW_NULL (parent -> common .arg_info [-1 ].type )))) {
635
+ error_level = E_COMPILE_ERROR ;
636
+ error_verb = "must" ;
637
+ } else {
638
+ error_level = E_WARNING ;
639
+ error_verb = "should" ;
640
+ }
641
+ zend_error (error_level , "Declaration of %s %s be compatible with %s" , ZSTR_VAL (child_prototype ), error_verb , ZSTR_VAL (method_prototype ));
642
+ zend_string_efree (child_prototype );
643
+ zend_string_efree (method_prototype );
644
+ }
631
645
}
632
- zend_error (error_level , "Declaration of %s %s be compatible with %s" , ZSTR_VAL (child_prototype ), error_verb , ZSTR_VAL (method_prototype ));
633
- zend_string_efree (child_prototype );
634
- zend_string_efree (method_prototype );
635
- }
646
+ } while (0 );
636
647
}
637
648
/* }}} */
638
649
@@ -1202,11 +1213,10 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen
1202
1213
zend_string * lowercase_name = zend_string_tolower (ce -> name );
1203
1214
lowercase_name = zend_new_interned_string (lowercase_name );
1204
1215
if (!memcmp (ZSTR_VAL (mname ), ZSTR_VAL (lowercase_name ), ZSTR_LEN (mname ))) {
1205
- if (ce -> constructor && (!ce -> parent || ce -> constructor != ce -> parent -> constructor )) {
1216
+ if (ce -> constructor && (!ce -> parent || ce -> constructor != ce -> parent -> constructor )) {
1206
1217
zend_error_noreturn (E_COMPILE_ERROR , "%s has colliding constructor definitions coming from traits" , ZSTR_VAL (ce -> name ));
1207
1218
}
1208
1219
ce -> constructor = fe ;
1209
- fe -> common .fn_flags |= ZEND_ACC_CTOR ;
1210
1220
}
1211
1221
zend_string_release_ex (lowercase_name , 0 );
1212
1222
} else if (ZSTR_VAL (mname )[0 ] != '_' || ZSTR_VAL (mname )[1 ] != '_' ) {
@@ -1217,9 +1227,9 @@ static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zen
1217
1227
if (ce -> constructor && (!ce -> parent || ce -> constructor != ce -> parent -> constructor )) {
1218
1228
zend_error_noreturn (E_COMPILE_ERROR , "%s has colliding constructor definitions coming from traits" , ZSTR_VAL (ce -> name ));
1219
1229
}
1220
- ce -> constructor = fe ; fe -> common . fn_flags |= ZEND_ACC_CTOR ;
1230
+ ce -> constructor = fe ;
1221
1231
} else if (zend_string_equals_literal (mname , ZEND_DESTRUCTOR_FUNC_NAME )) {
1222
- ce -> destructor = fe ; fe -> common . fn_flags |= ZEND_ACC_DTOR ;
1232
+ ce -> destructor = fe ;
1223
1233
} else if (zend_string_equals_literal (mname , ZEND_GET_FUNC_NAME )) {
1224
1234
ce -> __get = fe ;
1225
1235
ce -> ce_flags |= ZEND_ACC_USE_GUARDS ;
@@ -1903,7 +1913,7 @@ static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract
1903
1913
if (ai -> cnt < MAX_ABSTRACT_INFO_CNT ) {
1904
1914
ai -> afn [ai -> cnt ] = fn ;
1905
1915
}
1906
- if (fn -> common .fn_flags & ZEND_ACC_CTOR ) {
1916
+ if (fn -> common .scope -> constructor == fn ) {
1907
1917
if (!ai -> ctor ) {
1908
1918
ai -> cnt ++ ;
1909
1919
ai -> ctor = 1 ;
0 commit comments