@@ -1179,6 +1179,61 @@ static zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bo
11791179 name , type , is_fully_qualified , 1 , FC (imports_const ));
11801180}
11811181
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+
11821237static zend_string * zend_resolve_class_name (zend_string * name , uint32_t type ) /* {{{ */
11831238{
11841239 char * compound ;
@@ -1237,6 +1292,13 @@ static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /*
12371292 }
12381293 }
12391294
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+
12401302 /* If not fully qualified and not an alias, prepend the current namespace */
12411303 return zend_prefix_with_ns (name );
12421304}
@@ -9139,6 +9201,27 @@ static void zend_defer_class_decl(zend_ast *ast) {
91399201 zend_hash_next_index_insert_ptr (inner_class_queue , ast );
91409202}
91419203
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+
91429225static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
91439226{
91449227 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)
92879370 zend_enum_register_props (ce );
92889371 }
92899372
9373+ zend_scan_nested_class_decl (stmt_ast );
92909374 zend_compile_stmt (stmt_ast );
92919375
92929376 /* Reset lineno for final opcodes and errors */
@@ -11683,6 +11767,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1168311767 zend_compile_use_trait (ast );
1168411768 break ;
1168511769 case ZEND_AST_CLASS :
11770+ if (CG (active_class_entry )) {
11771+ zend_defer_class_decl (ast );
11772+ break ;
11773+ }
1168611774 zend_compile_class_decl (NULL , ast , 0 );
1168711775 break ;
1168811776 case ZEND_AST_GROUP_USE :
@@ -11692,10 +11780,6 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1169211780 zend_compile_use (ast );
1169311781 break ;
1169411782 case ZEND_AST_CONST_DECL :
11695- if (CG (active_class_entry )) {
11696- zend_defer_class_decl (ast );
11697- break ;
11698- }
1169911783 zend_compile_const_decl (ast );
1170011784 break ;
1170111785 case ZEND_AST_NAMESPACE :
0 commit comments