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}
@@ -9014,10 +9077,9 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
90149077}
90159078/* }}} */
90169079
9017- static void zend_compile_implements (zend_ast * ast ) /* {{{ */
9080+ static void zend_compile_implements (zend_ast * ast , zend_class_entry * ce ) /* {{{ */
90189081{
90199082 zend_ast_list * list = zend_ast_get_list (ast );
9020- zend_class_entry * ce = CG (active_class_entry );
90219083 zend_class_name * interface_names ;
90229084 uint32_t i ;
90239085
@@ -9075,6 +9137,42 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_
90759137 zend_type_release (type , 0 );
90769138}
90779139
9140+ static void zend_defer_class_decl (zend_ast * ast )
9141+ {
9142+ ZEND_ASSERT (CG (active_class_entry ));
9143+
9144+ if (CG (active_op_array )-> function_name ) {
9145+ zend_error_noreturn (E_COMPILE_ERROR , "Class declarations may not be declared inside functions" );
9146+ }
9147+
9148+ if (CG (nested_class_queue ) == NULL ) {
9149+ ALLOC_HASHTABLE (CG (nested_class_queue ));
9150+ zend_hash_init (CG (nested_class_queue ), 8 , NULL , ZVAL_PTR_DTOR , 0 );
9151+ }
9152+
9153+ zend_hash_next_index_insert_ptr (CG (nested_class_queue ), ast );
9154+ }
9155+
9156+ static void zend_scan_nested_class_decl (zend_ast * ast , const zend_string * prefix )
9157+ {
9158+ const zend_ast_list * list = zend_ast_get_list (ast );
9159+ for (int i = 0 ; i < list -> children ; i ++ ) {
9160+ ast = list -> child [i ];
9161+ if (ast -> kind == ZEND_AST_CLASS ) {
9162+ const zend_ast_decl * decl = (zend_ast_decl * )ast ;
9163+ zend_string * name = zend_string_concat3 (
9164+ ZSTR_VAL (prefix ), ZSTR_LEN (prefix ),
9165+ "\\" , 1 ,
9166+ ZSTR_VAL (decl -> name ), ZSTR_LEN (decl -> name ));
9167+ zend_string * lc_name = zend_string_tolower (name );
9168+ zend_register_seen_symbol (lc_name , ZEND_SYMBOL_CLASS );
9169+ zend_string_release (lc_name );
9170+ zend_scan_nested_class_decl (decl -> child [2 ], name );
9171+ zend_string_release (name );
9172+ }
9173+ }
9174+ }
9175+
90789176static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
90799177{
90809178 zend_ast_decl * decl = (zend_ast_decl * ) ast ;
@@ -9091,10 +9189,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
90919189 if (EXPECTED ((decl -> flags & ZEND_ACC_ANON_CLASS ) == 0 )) {
90929190 zend_string * unqualified_name = decl -> name ;
90939191
9094- if (CG (active_class_entry )) {
9095- zend_error_noreturn (E_COMPILE_ERROR , "Class declarations may not be nested" );
9096- }
9097-
90989192 const char * type = "a class name" ;
90999193 if (decl -> flags & ZEND_ACC_ENUM ) {
91009194 type = "an enum name" ;
@@ -9104,7 +9198,34 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91049198 type = "a trait name" ;
91059199 }
91069200 zend_assert_valid_class_name (unqualified_name , type );
9107- name = zend_prefix_with_ns (unqualified_name );
9201+
9202+ if (CG (active_class_entry )) {
9203+ name = zend_string_concat3 (
9204+ ZSTR_VAL (CG (active_class_entry )-> name ), ZSTR_LEN (CG (active_class_entry )-> name ),
9205+ "\\" , 1 ,
9206+ ZSTR_VAL (unqualified_name ), ZSTR_LEN (unqualified_name ));
9207+
9208+ /* configure the class from the modifiers */
9209+ decl -> flags |= decl -> attr & ZEND_ACC_FINAL ;
9210+ if (decl -> attr & ZEND_ACC_ABSTRACT ) {
9211+ decl -> flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS ;
9212+ }
9213+ if (decl -> attr & ZEND_ACC_READONLY ) {
9214+ decl -> flags |= ZEND_ACC_READONLY_CLASS | ZEND_ACC_NO_DYNAMIC_PROPERTIES ;
9215+ }
9216+
9217+ int propFlags = decl -> attr & ZEND_ACC_PPP_MASK ;
9218+ decl -> attr &= ~(ZEND_ACC_PPP_MASK | ZEND_ACC_FINAL | ZEND_ACC_READONLY | ZEND_ACC_ABSTRACT );
9219+
9220+ ce -> required_scope = propFlags & (ZEND_ACC_PRIVATE | ZEND_ACC_PROTECTED ) ? CG (active_class_entry ) : NULL ;
9221+ ce -> required_scope_absolute = propFlags & ZEND_ACC_PRIVATE ? true : false;
9222+ ce -> lexical_scope = CG (active_class_entry );
9223+ } else {
9224+ name = zend_prefix_with_ns (unqualified_name );
9225+ ce -> required_scope = NULL ;
9226+ ce -> lexical_scope = zend_resolve_namespace (FC (current_namespace ));
9227+ }
9228+
91089229 name = zend_new_interned_string (name );
91099230 lcname = zend_string_tolower (name );
91109231
@@ -9122,6 +9243,8 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91229243 /* Find an anon class name that is not in use yet. */
91239244 name = NULL ;
91249245 lcname = NULL ;
9246+ ce -> required_scope = NULL ;
9247+ ce -> lexical_scope = CG (active_class_entry ) ? CG (active_class_entry ) : zend_resolve_namespace (FC (current_namespace ));
91259248 do {
91269249 zend_tmp_string_release (name );
91279250 zend_tmp_string_release (lcname );
@@ -9163,16 +9286,16 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91639286 zend_resolve_const_class_name_reference (extends_ast , "class name" );
91649287 }
91659288
9289+ if (implements_ast ) {
9290+ zend_compile_implements (implements_ast , ce );
9291+ }
9292+
91669293 CG (active_class_entry ) = ce ;
91679294
91689295 if (decl -> child [3 ]) {
91699296 zend_compile_attributes (& ce -> attributes , decl -> child [3 ], 0 , ZEND_ATTRIBUTE_TARGET_CLASS , 0 );
91709297 }
91719298
9172- if (implements_ast ) {
9173- zend_compile_implements (implements_ast );
9174- }
9175-
91769299 if (ce -> ce_flags & ZEND_ACC_ENUM ) {
91779300 if (enum_backing_type_ast != NULL ) {
91789301 zend_compile_enum_backing_type (ce , enum_backing_type_ast );
@@ -9181,6 +9304,9 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91819304 zend_enum_register_props (ce );
91829305 }
91839306
9307+ if (ce -> lexical_scope -> type == ZEND_NAMESPACE_CLASS ) {
9308+ zend_scan_nested_class_decl (stmt_ast , name );
9309+ }
91849310 zend_compile_stmt (stmt_ast );
91859311
91869312 /* Reset lineno for final opcodes and errors */
@@ -9190,8 +9316,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91909316 zend_verify_abstract_class (ce );
91919317 }
91929318
9193- CG (active_class_entry ) = original_ce ;
9194-
91959319 if (toplevel ) {
91969320 ce -> ce_flags |= ZEND_ACC_TOP_LEVEL ;
91979321 }
@@ -9212,7 +9336,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92129336 && !zend_compile_ignore_class (parent_ce , ce -> info .user .filename )) {
92139337 if (zend_try_early_bind (ce , parent_ce , lcname , NULL )) {
92149338 zend_string_release (lcname );
9215- return ;
9339+ goto compile_nested_classes ;
92169340 }
92179341 }
92189342 } else if (EXPECTED (zend_hash_add_ptr (CG (class_table ), lcname , ce ) != NULL )) {
@@ -9221,7 +9345,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92219345 zend_inheritance_check_override (ce );
92229346 ce -> ce_flags |= ZEND_ACC_LINKED ;
92239347 zend_observer_class_linked_notify (ce , lcname );
9224- return ;
9348+ goto compile_nested_classes ;
92259349 } else {
92269350 goto link_unbound ;
92279351 }
@@ -9291,6 +9415,24 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92919415 opline -> result .opline_num = -1 ;
92929416 }
92939417 }
9418+ compile_nested_classes :
9419+
9420+ if (CG (nested_class_queue ) == NULL ) {
9421+ CG (active_class_entry ) = original_ce ;
9422+ return ;
9423+ }
9424+
9425+ HashTable * queue = CG (nested_class_queue );
9426+ CG (nested_class_queue ) = NULL ;
9427+
9428+ ZEND_HASH_FOREACH_PTR (queue , ast ) {
9429+ zend_compile_class_decl (NULL , ast , true);
9430+ } ZEND_HASH_FOREACH_END ();
9431+
9432+ CG (active_class_entry ) = original_ce ;
9433+
9434+ zend_hash_destroy (queue );
9435+ FREE_HASHTABLE (queue );
92949436}
92959437/* }}} */
92969438
@@ -11581,6 +11723,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1158111723 zend_compile_use_trait (ast );
1158211724 break ;
1158311725 case ZEND_AST_CLASS :
11726+ if (CG (active_class_entry )) {
11727+ zend_defer_class_decl (ast );
11728+ break ;
11729+ }
1158411730 zend_compile_class_decl (NULL , ast , 0 );
1158511731 break ;
1158611732 case ZEND_AST_GROUP_USE :
0 commit comments