@@ -1099,6 +1099,21 @@ static zend_string *zend_concat_names(char *name1, size_t name1_len, char *name2
10991099 return zend_string_concat3 (name1 , name1_len , "\\" , 1 , name2 , name2_len );
11001100}
11011101
1102+ static zend_string * zend_prefix_with_outer_class (zend_string * name ) {
1103+ ZEND_ASSERT (CG (active_class_entry ));
1104+
1105+ zend_string * ns = CG (active_class_entry )-> name ;
1106+
1107+ // If the current ns is the current name, return the ns.
1108+ // we only need to check if ns[len(ns) - len(name) + 1] == '\\' and the end of ns is name.
1109+ if (ZSTR_LEN (ns ) >= ZSTR_LEN (name ) && ZSTR_VAL (ns )[ZSTR_LEN (ns ) - ZSTR_LEN (name ) - 1 ] == '\\'
1110+ && memcmp (ZSTR_VAL (ns ) + ZSTR_LEN (ns ) - ZSTR_LEN (name ), ZSTR_VAL (name ), ZSTR_LEN (name )) == 0 ) {
1111+ return zend_string_copy (ns );
1112+ }
1113+
1114+ return zend_concat_names (ZSTR_VAL (ns ), ZSTR_LEN (ns ), ZSTR_VAL (name ), ZSTR_LEN (name ));
1115+ }
1116+
11021117static zend_string * zend_prefix_with_ns (zend_string * name ) {
11031118 if (FC (current_namespace )) {
11041119 zend_string * ns = FC (current_namespace );
@@ -1236,6 +1251,10 @@ static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /*
12361251 }
12371252 }
12381253
1254+ if (CG (active_class_entry )) {
1255+ return zend_prefix_with_outer_class (name );
1256+ }
1257+
12391258 /* If not fully qualified and not an alias, prepend the current namespace */
12401259 return zend_prefix_with_ns (name );
12411260}
@@ -9093,10 +9112,9 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
90939112}
90949113/* }}} */
90959114
9096- static void zend_compile_implements (zend_ast * ast ) /* {{{ */
9115+ static void zend_compile_implements (zend_ast * ast , zend_class_entry * ce ) /* {{{ */
90979116{
90989117 zend_ast_list * list = zend_ast_get_list (ast );
9099- zend_class_entry * ce = CG (active_class_entry );
91009118 zend_class_name * interface_names ;
91019119 uint32_t i ;
91029120
@@ -9154,6 +9172,18 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_
91549172 zend_type_release (type , 0 );
91559173}
91569174
9175+ HashTable * inner_class_queue = NULL ;
9176+
9177+ static void zend_defer_class_decl (zend_ast * ast )
9178+ {
9179+ if (inner_class_queue == NULL ) {
9180+ ALLOC_HASHTABLE (inner_class_queue );
9181+ zend_hash_init (inner_class_queue , 0 , NULL , ZVAL_PTR_DTOR , 0 );
9182+ }
9183+
9184+ zend_hash_next_index_insert_ptr (inner_class_queue , ast );
9185+ }
9186+
91579187static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
91589188{
91599189 zend_ast_decl * decl = (zend_ast_decl * ) ast ;
@@ -9188,7 +9218,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91889218 // rename the inner class so we may reference it by name
91899219 name = zend_string_concat3 (
91909220 ZSTR_VAL (CG (active_class_entry )-> name ), ZSTR_LEN (CG (active_class_entry )-> name ),
9191- ":> " , 2 ,
9221+ "\\ " , 1 ,
91929222 ZSTR_VAL (unqualified_name ), ZSTR_LEN (unqualified_name )
91939223 );
91949224
@@ -9284,16 +9314,16 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92849314 zend_resolve_const_class_name_reference (extends_ast , "class name" );
92859315 }
92869316
9317+ if (implements_ast ) {
9318+ zend_compile_implements (implements_ast , ce );
9319+ }
9320+
92879321 CG (active_class_entry ) = ce ;
92889322
92899323 if (decl -> child [3 ]) {
92909324 zend_compile_attributes (& ce -> attributes , decl -> child [3 ], 0 , ZEND_ATTRIBUTE_TARGET_CLASS , 0 );
92919325 }
92929326
9293- if (implements_ast ) {
9294- zend_compile_implements (implements_ast );
9295- }
9296-
92979327 if (ce -> ce_flags & ZEND_ACC_ENUM ) {
92989328 if (enum_backing_type_ast != NULL ) {
92999329 zend_compile_enum_backing_type (ce , enum_backing_type_ast );
@@ -9311,8 +9341,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
93119341 zend_verify_abstract_class (ce );
93129342 }
93139343
9314- CG (active_class_entry ) = original_ce ;
9315-
93169344 if (toplevel ) {
93179345 ce -> ce_flags |= ZEND_ACC_TOP_LEVEL ;
93189346 }
@@ -9333,7 +9361,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
93339361 && !zend_compile_ignore_class (parent_ce , ce -> info .user .filename )) {
93349362 if (zend_try_early_bind (ce , parent_ce , lcname , NULL )) {
93359363 zend_string_release (lcname );
9336- return ;
9364+ goto compile_inner_classes ;
93379365 }
93389366 }
93399367 } else if (EXPECTED (zend_hash_add_ptr (CG (class_table ), lcname , ce ) != NULL )) {
@@ -9342,7 +9370,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
93429370 zend_inheritance_check_override (ce );
93439371 ce -> ce_flags |= ZEND_ACC_LINKED ;
93449372 zend_observer_class_linked_notify (ce , lcname );
9345- return ;
9373+ goto compile_inner_classes ;
93469374 } else {
93479375 goto link_unbound ;
93489376 }
@@ -9412,6 +9440,25 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
94129440 opline -> result .opline_num = -1 ;
94139441 }
94149442 }
9443+
9444+ compile_inner_classes :
9445+
9446+ if (inner_class_queue == NULL ) {
9447+ CG (active_class_entry ) = original_ce ;
9448+ return ;
9449+ }
9450+
9451+ HashTable * queue = inner_class_queue ;
9452+ inner_class_queue = NULL ;
9453+
9454+ ZEND_HASH_FOREACH_PTR (queue , ast ) {
9455+ zend_compile_class_decl (NULL , ast , 0 );
9456+ } ZEND_HASH_FOREACH_END ();
9457+
9458+ CG (active_class_entry ) = original_ce ;
9459+
9460+ zend_hash_destroy (queue );
9461+ FREE_HASHTABLE (queue );
94159462}
94169463/* }}} */
94179464
@@ -11682,6 +11729,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1168211729 zend_compile_use_trait (ast );
1168311730 break ;
1168411731 case ZEND_AST_CLASS :
11732+ if (CG (active_class_entry )) {
11733+ zend_defer_class_decl (ast );
11734+ break ;
11735+ }
1168511736 zend_compile_class_decl (NULL , ast , 0 );
1168611737 break ;
1168711738 case ZEND_AST_GROUP_USE :
0 commit comments