3838#include "zend_call_stack.h"
3939#include "zend_frameless_function.h"
4040#include "zend_property_hooks.h"
41+ #include "zend_namespaces.h"
4142
4243#define SET_NODE (target , src ) do { \
4344 target ## _type = (src)->op_type; \
@@ -424,6 +425,7 @@ void zend_init_compiler_data_structures(void) /* {{{ */
424425 zend_stack_init (& CG (delayed_oplines_stack ), sizeof (zend_op ));
425426 zend_stack_init (& CG (short_circuiting_opnums ), sizeof (uint32_t ));
426427 CG (active_class_entry ) = NULL ;
428+ CG (nested_class_queue ) = NULL ;
427429 CG (in_compilation ) = 0 ;
428430 CG (skip_shebang ) = 0 ;
429431
@@ -1178,6 +1180,60 @@ static zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bo
11781180 name , type , is_fully_qualified , 1 , FC (imports_const ));
11791181}
11801182
1183+ static zend_string * get_namespace_from_scope (const zend_class_entry * scope )
1184+ {
1185+ ZEND_ASSERT (scope != NULL );
1186+ while (scope && scope -> lexical_scope && scope -> type != ZEND_NAMESPACE_CLASS ) {
1187+ scope = scope -> lexical_scope ;
1188+ }
1189+ return zend_string_copy (scope -> name );
1190+ }
1191+
1192+ static zend_string * get_scoped_name (zend_string * ns , zend_string * name )
1193+ {
1194+ name = zend_string_tolower (name );
1195+ if (ns && ZSTR_LEN (ns ) && ZSTR_LEN (name ) > ZSTR_LEN (ns ) + 1 &&
1196+ memcmp (ZSTR_VAL (name ), ZSTR_VAL (ns ), ZSTR_LEN (ns )) == 0 &&
1197+ ZSTR_VAL (name )[ZSTR_LEN (ns )] == '\\' ) {
1198+ zend_string * ret = zend_string_init (ZSTR_VAL (name ) + ZSTR_LEN (ns ) + 1 , ZSTR_LEN (name ) - ZSTR_LEN (ns ) - 1 , 0 );
1199+ zend_string_release (name );
1200+ return ret ;
1201+ }
1202+ return name ;
1203+ }
1204+
1205+ zend_string * zend_resolve_class_in_scope (zend_string * name , const zend_class_entry * scope )
1206+ {
1207+ zend_string * ns_name = get_namespace_from_scope (scope );
1208+ zend_string * original_suffix = get_scoped_name (ns_name , name );
1209+ zend_string_release (ns_name );
1210+
1211+ const zend_class_entry * current_scope = scope ;
1212+
1213+ while (current_scope && current_scope -> type != ZEND_NAMESPACE_CLASS ) {
1214+ zend_string * try_name = zend_string_concat3 (
1215+ ZSTR_VAL (current_scope -> name ), ZSTR_LEN (current_scope -> name ),
1216+ "\\" , 1 ,
1217+ ZSTR_VAL (original_suffix ), ZSTR_LEN (original_suffix ));
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+
11811237static zend_string * zend_resolve_class_name (zend_string * name , uint32_t type ) /* {{{ */
11821238{
11831239 char * compound ;
@@ -1236,6 +1292,13 @@ static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /*
12361292 }
12371293 }
12381294
1295+ if (CG (active_class_entry )) {
1296+ zend_string * nested_name = zend_resolve_class_in_scope (name , CG (active_class_entry ));
1297+ if (nested_name ) {
1298+ return nested_name ;
1299+ }
1300+ }
1301+
12391302 /* If not fully qualified and not an alias, prepend the current namespace */
12401303 return zend_prefix_with_ns (name );
12411304}
@@ -9016,10 +9079,9 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
90169079}
90179080/* }}} */
90189081
9019- static void zend_compile_implements (zend_ast * ast ) /* {{{ */
9082+ static void zend_compile_implements (zend_ast * ast , zend_class_entry * ce ) /* {{{ */
90209083{
90219084 zend_ast_list * list = zend_ast_get_list (ast );
9022- zend_class_entry * ce = CG (active_class_entry );
90239085 zend_class_name * interface_names ;
90249086 uint32_t i ;
90259087
@@ -9077,6 +9139,42 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_
90779139 zend_type_release (type , 0 );
90789140}
90799141
9142+ static void zend_defer_class_decl (zend_ast * ast )
9143+ {
9144+ ZEND_ASSERT (CG (active_class_entry ));
9145+
9146+ if (CG (active_op_array )-> function_name ) {
9147+ zend_error_noreturn (E_COMPILE_ERROR , "Class declarations may not be declared inside functions" );
9148+ }
9149+
9150+ if (CG (nested_class_queue ) == NULL ) {
9151+ ALLOC_HASHTABLE (CG (nested_class_queue ));
9152+ zend_hash_init (CG (nested_class_queue ), 8 , NULL , ZVAL_PTR_DTOR , 0 );
9153+ }
9154+
9155+ zend_hash_next_index_insert_ptr (CG (nested_class_queue ), ast );
9156+ }
9157+
9158+ static void zend_scan_nested_class_decl (zend_ast * ast , const zend_string * prefix )
9159+ {
9160+ const zend_ast_list * list = zend_ast_get_list (ast );
9161+ for (int i = 0 ; i < list -> children ; i ++ ) {
9162+ ast = list -> child [i ];
9163+ if (ast -> kind == ZEND_AST_CLASS ) {
9164+ const zend_ast_decl * decl = (zend_ast_decl * )ast ;
9165+ zend_string * name = zend_string_concat3 (
9166+ ZSTR_VAL (prefix ), ZSTR_LEN (prefix ),
9167+ "\\" , 1 ,
9168+ ZSTR_VAL (decl -> name ), ZSTR_LEN (decl -> name ));
9169+ zend_string * lc_name = zend_string_tolower (name );
9170+ zend_register_seen_symbol (lc_name , ZEND_SYMBOL_CLASS );
9171+ zend_string_release (lc_name );
9172+ zend_scan_nested_class_decl (decl -> child [2 ], name );
9173+ zend_string_release (name );
9174+ }
9175+ }
9176+ }
9177+
90809178static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
90819179{
90829180 zend_ast_decl * decl = (zend_ast_decl * ) ast ;
@@ -9093,10 +9191,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
90939191 if (EXPECTED ((decl -> flags & ZEND_ACC_ANON_CLASS ) == 0 )) {
90949192 zend_string * unqualified_name = decl -> name ;
90959193
9096- if (CG (active_class_entry )) {
9097- zend_error_noreturn (E_COMPILE_ERROR , "Class declarations may not be nested" );
9098- }
9099-
91009194 const char * type = "a class name" ;
91019195 if (decl -> flags & ZEND_ACC_ENUM ) {
91029196 type = "an enum name" ;
@@ -9106,7 +9200,34 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91069200 type = "a trait name" ;
91079201 }
91089202 zend_assert_valid_class_name (unqualified_name , type );
9109- name = zend_prefix_with_ns (unqualified_name );
9203+
9204+ if (CG (active_class_entry )) {
9205+ name = zend_string_concat3 (
9206+ ZSTR_VAL (CG (active_class_entry )-> name ), ZSTR_LEN (CG (active_class_entry )-> name ),
9207+ "\\" , 1 ,
9208+ ZSTR_VAL (unqualified_name ), ZSTR_LEN (unqualified_name ));
9209+
9210+ /* configure the class from the modifiers */
9211+ decl -> flags |= decl -> attr & ZEND_ACC_FINAL ;
9212+ if (decl -> attr & ZEND_ACC_ABSTRACT ) {
9213+ decl -> flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ;
9214+ }
9215+ if (decl -> attr & ZEND_ACC_READONLY ) {
9216+ decl -> flags |= ZEND_ACC_READONLY_CLASS | ZEND_ACC_NO_DYNAMIC_PROPERTIES ;
9217+ }
9218+
9219+ int propFlags = decl -> attr & ZEND_ACC_PPP_MASK ;
9220+ decl -> attr &= ~(ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL | ZEND_ACC_READONLY | ZEND_ACC_ABSTRACT );
9221+
9222+ ce -> required_scope = propFlags & (ZEND_ACC_PRIVATE | ZEND_ACC_PROTECTED ) ? CG (active_class_entry ) : NULL ;
9223+ ce -> required_scope_absolute = propFlags & ZEND_ACC_PRIVATE ? true : false;
9224+ ce -> lexical_scope = CG (active_class_entry );
9225+ } else {
9226+ name = zend_prefix_with_ns (unqualified_name );
9227+ ce -> required_scope = NULL ;
9228+ ce -> lexical_scope = zend_resolve_namespace (FC (current_namespace ));
9229+ }
9230+
91109231 name = zend_new_interned_string (name );
91119232 lcname = zend_string_tolower (name );
91129233
@@ -9124,6 +9245,8 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91249245 /* Find an anon class name that is not in use yet. */
91259246 name = NULL ;
91269247 lcname = NULL ;
9248+ ce -> required_scope = NULL ;
9249+ ce -> lexical_scope = CG (active_class_entry ) ? CG (active_class_entry ) : zend_resolve_namespace (FC (current_namespace ));
91279250 do {
91289251 zend_tmp_string_release (name );
91299252 zend_tmp_string_release (lcname );
@@ -9165,16 +9288,16 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91659288 zend_resolve_const_class_name_reference (extends_ast , "class name" );
91669289 }
91679290
9291+ if (implements_ast ) {
9292+ zend_compile_implements (implements_ast , ce );
9293+ }
9294+
91689295 CG (active_class_entry ) = ce ;
91699296
91709297 if (decl -> child [3 ]) {
91719298 zend_compile_attributes (& ce -> attributes , decl -> child [3 ], 0 , ZEND_ATTRIBUTE_TARGET_CLASS , 0 );
91729299 }
91739300
9174- if (implements_ast ) {
9175- zend_compile_implements (implements_ast );
9176- }
9177-
91789301 if (ce -> ce_flags & ZEND_ACC_ENUM ) {
91799302 if (enum_backing_type_ast != NULL ) {
91809303 zend_compile_enum_backing_type (ce , enum_backing_type_ast );
@@ -9183,6 +9306,9 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91839306 zend_enum_register_props (ce );
91849307 }
91859308
9309+ if (ce -> lexical_scope -> type == ZEND_NAMESPACE_CLASS ) {
9310+ zend_scan_nested_class_decl (stmt_ast , name );
9311+ }
91869312 zend_compile_stmt (stmt_ast );
91879313
91889314 /* Reset lineno for final opcodes and errors */
@@ -9192,8 +9318,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91929318 zend_verify_abstract_class (ce );
91939319 }
91949320
9195- CG (active_class_entry ) = original_ce ;
9196-
91979321 if (toplevel ) {
91989322 ce -> ce_flags |= ZEND_ACC_TOP_LEVEL ;
91999323 }
@@ -9214,7 +9338,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92149338 && !zend_compile_ignore_class (parent_ce , ce -> info .user .filename )) {
92159339 if (zend_try_early_bind (ce , parent_ce , lcname , NULL )) {
92169340 zend_string_release (lcname );
9217- return ;
9341+ goto compile_nested_classes ;
92189342 }
92199343 }
92209344 } else if (EXPECTED (zend_hash_add_ptr (CG (class_table ), lcname , ce ) != NULL )) {
@@ -9223,7 +9347,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92239347 zend_inheritance_check_override (ce );
92249348 ce -> ce_flags |= ZEND_ACC_LINKED ;
92259349 zend_observer_class_linked_notify (ce , lcname );
9226- return ;
9350+ goto compile_nested_classes ;
92279351 } else {
92289352 goto link_unbound ;
92299353 }
@@ -9293,6 +9417,24 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92939417 opline -> result .opline_num = -1 ;
92949418 }
92959419 }
9420+ compile_nested_classes :
9421+
9422+ if (CG (nested_class_queue ) == NULL ) {
9423+ CG (active_class_entry ) = original_ce ;
9424+ return ;
9425+ }
9426+
9427+ HashTable * queue = CG (nested_class_queue );
9428+ CG (nested_class_queue ) = NULL ;
9429+
9430+ ZEND_HASH_FOREACH_PTR (queue , ast ) {
9431+ zend_compile_class_decl (NULL , ast , true);
9432+ } ZEND_HASH_FOREACH_END ();
9433+
9434+ CG (active_class_entry ) = original_ce ;
9435+
9436+ zend_hash_destroy (queue );
9437+ FREE_HASHTABLE (queue );
92969438}
92979439/* }}} */
92989440
@@ -11583,6 +11725,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1158311725 zend_compile_use_trait (ast );
1158411726 break ;
1158511727 case ZEND_AST_CLASS :
11728+ if (CG (active_class_entry )) {
11729+ zend_defer_class_decl (ast );
11730+ break ;
11731+ }
1158611732 zend_compile_class_decl (NULL , ast , 0 );
1158711733 break ;
1158811734 case ZEND_AST_GROUP_USE :
0 commit comments