@@ -1179,6 +1179,61 @@ static zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bo
1179
1179
name , type , is_fully_qualified , 1 , FC (imports_const ));
1180
1180
}
1181
1181
1182
+ static zend_string * get_namespace_from_scope (const zend_class_entry * scope ) {
1183
+ ZEND_ASSERT (scope != NULL );
1184
+ while (scope && scope -> lexical_scope && scope -> type != ZEND_NAMESPACE_CLASS ) {
1185
+ scope = scope -> lexical_scope ;
1186
+ }
1187
+ return zend_string_copy (scope -> name );
1188
+ }
1189
+
1190
+ static zend_string * get_scoped_name (zend_string * ns , zend_string * name ) {
1191
+ // remove the matching prefix from name
1192
+ name = zend_string_tolower (name );
1193
+ if (ns && ZSTR_LEN (ns ) && ZSTR_LEN (name ) > ZSTR_LEN (ns ) + 1 &&
1194
+ memcmp (ZSTR_VAL (name ), ZSTR_VAL (ns ), ZSTR_LEN (ns )) == 0 &&
1195
+ ZSTR_VAL (name )[ZSTR_LEN (ns )] == '\\' ) {
1196
+ zend_string * ret = zend_string_init (ZSTR_VAL (name ) + ZSTR_LEN (ns ) + 1 , ZSTR_LEN (name ) - ZSTR_LEN (ns ) - 1 , 0 );
1197
+ zend_string_release (name );
1198
+ return ret ;
1199
+ }
1200
+ return name ;
1201
+ }
1202
+
1203
+ zend_string * zend_resolve_class_in_scope (zend_string * name , const zend_class_entry * scope ) {
1204
+ zend_string * ns_name = get_namespace_from_scope (scope );
1205
+ zend_string * original_suffix = get_scoped_name (ns_name , name );
1206
+ zend_string_release (ns_name );
1207
+
1208
+ const zend_class_entry * current_scope = scope ;
1209
+
1210
+ // Traverse upwards in lexical scope, stop at namespace boundary
1211
+ while (current_scope && current_scope -> type != ZEND_NAMESPACE_CLASS ) {
1212
+ // build fully-qualified name: current_scope->name + "\\" + original_suffix
1213
+ zend_string * try_name = zend_string_concat3 (
1214
+ ZSTR_VAL (current_scope -> name ), ZSTR_LEN (current_scope -> name ),
1215
+ "\\" , 1 ,
1216
+ ZSTR_VAL (original_suffix ), ZSTR_LEN (original_suffix )
1217
+ );
1218
+
1219
+ zend_string * lc_try_name = zend_string_tolower (try_name );
1220
+
1221
+ bool has_seen = zend_have_seen_symbol (lc_try_name , ZEND_SYMBOL_CLASS );
1222
+ zend_string_release (lc_try_name );
1223
+
1224
+ if (has_seen ) {
1225
+ zend_string_release (original_suffix );
1226
+ return try_name ;
1227
+ }
1228
+ zend_string_release (try_name );
1229
+
1230
+ current_scope = current_scope -> lexical_scope ;
1231
+ }
1232
+
1233
+ zend_string_release (original_suffix );
1234
+ return NULL ;
1235
+ }
1236
+
1182
1237
static zend_string * zend_resolve_class_name (zend_string * name , uint32_t type ) /* {{{ */
1183
1238
{
1184
1239
char * compound ;
@@ -1237,6 +1292,13 @@ static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /*
1237
1292
}
1238
1293
}
1239
1294
1295
+ if (CG (active_class_entry )) {
1296
+ zend_string * import_name = zend_resolve_class_in_scope (name , CG (active_class_entry ));
1297
+ if (import_name ) {
1298
+ return import_name ;
1299
+ }
1300
+ }
1301
+
1240
1302
/* If not fully qualified and not an alias, prepend the current namespace */
1241
1303
return zend_prefix_with_ns (name );
1242
1304
}
@@ -9139,6 +9201,27 @@ static void zend_defer_class_decl(zend_ast *ast) {
9139
9201
zend_hash_next_index_insert_ptr (inner_class_queue , ast );
9140
9202
}
9141
9203
9204
+ static void zend_scan_nested_class_decl (zend_ast * ast ) {
9205
+ ZEND_ASSERT (CG (active_class_entry ));
9206
+
9207
+ const zend_ast_list * list = zend_ast_get_list (ast );
9208
+ for (int i = 0 ; i < list -> children ; i ++ ) {
9209
+ ast = list -> child [i ];
9210
+ if (ast -> kind == ZEND_AST_CLASS ) {
9211
+ const zend_ast_decl * decl = (zend_ast_decl * ) ast ;
9212
+ zend_string * name = zend_string_concat3 (
9213
+ ZSTR_VAL (CG (active_class_entry )-> name ), ZSTR_LEN (CG (active_class_entry )-> name ),
9214
+ "\\" , 1 ,
9215
+ ZSTR_VAL (decl -> name ), ZSTR_LEN (decl -> name )
9216
+ );
9217
+ zend_string * lc_name = zend_string_tolower (name );
9218
+ zend_register_seen_symbol (lc_name , ZEND_SYMBOL_CLASS );
9219
+ zend_string_release (name );
9220
+ zend_string_release (lc_name );
9221
+ }
9222
+ }
9223
+ }
9224
+
9142
9225
static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
9143
9226
{
9144
9227
zend_ast_decl * decl = (zend_ast_decl * ) ast ;
@@ -9287,6 +9370,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9287
9370
zend_enum_register_props (ce );
9288
9371
}
9289
9372
9373
+ zend_scan_nested_class_decl (stmt_ast );
9290
9374
zend_compile_stmt (stmt_ast );
9291
9375
9292
9376
/* Reset lineno for final opcodes and errors */
@@ -11683,6 +11767,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
11683
11767
zend_compile_use_trait (ast );
11684
11768
break ;
11685
11769
case ZEND_AST_CLASS :
11770
+ if (CG (active_class_entry )) {
11771
+ zend_defer_class_decl (ast );
11772
+ break ;
11773
+ }
11686
11774
zend_compile_class_decl (NULL , ast , 0 );
11687
11775
break ;
11688
11776
case ZEND_AST_GROUP_USE :
@@ -11692,10 +11780,6 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
11692
11780
zend_compile_use (ast );
11693
11781
break ;
11694
11782
case ZEND_AST_CONST_DECL :
11695
- if (CG (active_class_entry )) {
11696
- zend_defer_class_decl (ast );
11697
- break ;
11698
- }
11699
11783
zend_compile_const_decl (ast );
11700
11784
break ;
11701
11785
case ZEND_AST_NAMESPACE :
0 commit comments