38
38
#include "zend_call_stack.h"
39
39
#include "zend_frameless_function.h"
40
40
#include "zend_property_hooks.h"
41
+ #include "zend_namespaces.h"
41
42
42
43
#define SET_NODE (target , src ) do { \
43
44
target ## _type = (src)->op_type; \
@@ -424,6 +425,7 @@ void zend_init_compiler_data_structures(void) /* {{{ */
424
425
zend_stack_init (& CG (delayed_oplines_stack ), sizeof (zend_op ));
425
426
zend_stack_init (& CG (short_circuiting_opnums ), sizeof (uint32_t ));
426
427
CG (active_class_entry ) = NULL ;
428
+ CG (nested_class_queue ) = NULL ;
427
429
CG (in_compilation ) = 0 ;
428
430
CG (skip_shebang ) = 0 ;
429
431
@@ -1178,6 +1180,60 @@ static zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bo
1178
1180
name , type , is_fully_qualified , 1 , FC (imports_const ));
1179
1181
}
1180
1182
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
+
1181
1237
static zend_string * zend_resolve_class_name (zend_string * name , uint32_t type ) /* {{{ */
1182
1238
{
1183
1239
char * compound ;
@@ -1236,6 +1292,13 @@ static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /*
1236
1292
}
1237
1293
}
1238
1294
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
+
1239
1302
/* If not fully qualified and not an alias, prepend the current namespace */
1240
1303
return zend_prefix_with_ns (name );
1241
1304
}
@@ -9016,10 +9079,9 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
9016
9079
}
9017
9080
/* }}} */
9018
9081
9019
- static void zend_compile_implements (zend_ast * ast ) /* {{{ */
9082
+ static void zend_compile_implements (zend_ast * ast , zend_class_entry * ce ) /* {{{ */
9020
9083
{
9021
9084
zend_ast_list * list = zend_ast_get_list (ast );
9022
- zend_class_entry * ce = CG (active_class_entry );
9023
9085
zend_class_name * interface_names ;
9024
9086
uint32_t i ;
9025
9087
@@ -9077,6 +9139,42 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_
9077
9139
zend_type_release (type , 0 );
9078
9140
}
9079
9141
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
+
9080
9178
static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
9081
9179
{
9082
9180
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)
9093
9191
if (EXPECTED ((decl -> flags & ZEND_ACC_ANON_CLASS ) == 0 )) {
9094
9192
zend_string * unqualified_name = decl -> name ;
9095
9193
9096
- if (CG (active_class_entry )) {
9097
- zend_error_noreturn (E_COMPILE_ERROR , "Class declarations may not be nested" );
9098
- }
9099
-
9100
9194
const char * type = "a class name" ;
9101
9195
if (decl -> flags & ZEND_ACC_ENUM ) {
9102
9196
type = "an enum name" ;
@@ -9106,7 +9200,34 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9106
9200
type = "a trait name" ;
9107
9201
}
9108
9202
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
+
9110
9231
name = zend_new_interned_string (name );
9111
9232
lcname = zend_string_tolower (name );
9112
9233
@@ -9124,6 +9245,8 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9124
9245
/* Find an anon class name that is not in use yet. */
9125
9246
name = NULL ;
9126
9247
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 ));
9127
9250
do {
9128
9251
zend_tmp_string_release (name );
9129
9252
zend_tmp_string_release (lcname );
@@ -9165,16 +9288,16 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9165
9288
zend_resolve_const_class_name_reference (extends_ast , "class name" );
9166
9289
}
9167
9290
9291
+ if (implements_ast ) {
9292
+ zend_compile_implements (implements_ast , ce );
9293
+ }
9294
+
9168
9295
CG (active_class_entry ) = ce ;
9169
9296
9170
9297
if (decl -> child [3 ]) {
9171
9298
zend_compile_attributes (& ce -> attributes , decl -> child [3 ], 0 , ZEND_ATTRIBUTE_TARGET_CLASS , 0 );
9172
9299
}
9173
9300
9174
- if (implements_ast ) {
9175
- zend_compile_implements (implements_ast );
9176
- }
9177
-
9178
9301
if (ce -> ce_flags & ZEND_ACC_ENUM ) {
9179
9302
if (enum_backing_type_ast != NULL ) {
9180
9303
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)
9183
9306
zend_enum_register_props (ce );
9184
9307
}
9185
9308
9309
+ if (ce -> lexical_scope -> type == ZEND_NAMESPACE_CLASS ) {
9310
+ zend_scan_nested_class_decl (stmt_ast , name );
9311
+ }
9186
9312
zend_compile_stmt (stmt_ast );
9187
9313
9188
9314
/* Reset lineno for final opcodes and errors */
@@ -9192,8 +9318,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9192
9318
zend_verify_abstract_class (ce );
9193
9319
}
9194
9320
9195
- CG (active_class_entry ) = original_ce ;
9196
-
9197
9321
if (toplevel ) {
9198
9322
ce -> ce_flags |= ZEND_ACC_TOP_LEVEL ;
9199
9323
}
@@ -9214,7 +9338,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9214
9338
&& !zend_compile_ignore_class (parent_ce , ce -> info .user .filename )) {
9215
9339
if (zend_try_early_bind (ce , parent_ce , lcname , NULL )) {
9216
9340
zend_string_release (lcname );
9217
- return ;
9341
+ goto compile_nested_classes ;
9218
9342
}
9219
9343
}
9220
9344
} 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)
9223
9347
zend_inheritance_check_override (ce );
9224
9348
ce -> ce_flags |= ZEND_ACC_LINKED ;
9225
9349
zend_observer_class_linked_notify (ce , lcname );
9226
- return ;
9350
+ goto compile_nested_classes ;
9227
9351
} else {
9228
9352
goto link_unbound ;
9229
9353
}
@@ -9293,6 +9417,24 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9293
9417
opline -> result .opline_num = -1 ;
9294
9418
}
9295
9419
}
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 );
9296
9438
}
9297
9439
/* }}} */
9298
9440
@@ -11583,6 +11725,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
11583
11725
zend_compile_use_trait (ast );
11584
11726
break ;
11585
11727
case ZEND_AST_CLASS :
11728
+ if (CG (active_class_entry )) {
11729
+ zend_defer_class_decl (ast );
11730
+ break ;
11731
+ }
11586
11732
zend_compile_class_decl (NULL , ast , 0 );
11587
11733
break ;
11588
11734
case ZEND_AST_GROUP_USE :
0 commit comments