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
}
@@ -9014,10 +9077,9 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
9014
9077
}
9015
9078
/* }}} */
9016
9079
9017
- static void zend_compile_implements (zend_ast * ast ) /* {{{ */
9080
+ static void zend_compile_implements (zend_ast * ast , zend_class_entry * ce ) /* {{{ */
9018
9081
{
9019
9082
zend_ast_list * list = zend_ast_get_list (ast );
9020
- zend_class_entry * ce = CG (active_class_entry );
9021
9083
zend_class_name * interface_names ;
9022
9084
uint32_t i ;
9023
9085
@@ -9075,6 +9137,42 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_
9075
9137
zend_type_release (type , 0 );
9076
9138
}
9077
9139
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
+
9078
9176
static void zend_compile_class_decl (znode * result , zend_ast * ast , bool toplevel ) /* {{{ */
9079
9177
{
9080
9178
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)
9091
9189
if (EXPECTED ((decl -> flags & ZEND_ACC_ANON_CLASS ) == 0 )) {
9092
9190
zend_string * unqualified_name = decl -> name ;
9093
9191
9094
- if (CG (active_class_entry )) {
9095
- zend_error_noreturn (E_COMPILE_ERROR , "Class declarations may not be nested" );
9096
- }
9097
-
9098
9192
const char * type = "a class name" ;
9099
9193
if (decl -> flags & ZEND_ACC_ENUM ) {
9100
9194
type = "an enum name" ;
@@ -9104,7 +9198,34 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9104
9198
type = "a trait name" ;
9105
9199
}
9106
9200
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
+
9108
9229
name = zend_new_interned_string (name );
9109
9230
lcname = zend_string_tolower (name );
9110
9231
@@ -9122,6 +9243,8 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9122
9243
/* Find an anon class name that is not in use yet. */
9123
9244
name = NULL ;
9124
9245
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 ));
9125
9248
do {
9126
9249
zend_tmp_string_release (name );
9127
9250
zend_tmp_string_release (lcname );
@@ -9163,16 +9286,16 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9163
9286
zend_resolve_const_class_name_reference (extends_ast , "class name" );
9164
9287
}
9165
9288
9289
+ if (implements_ast ) {
9290
+ zend_compile_implements (implements_ast , ce );
9291
+ }
9292
+
9166
9293
CG (active_class_entry ) = ce ;
9167
9294
9168
9295
if (decl -> child [3 ]) {
9169
9296
zend_compile_attributes (& ce -> attributes , decl -> child [3 ], 0 , ZEND_ATTRIBUTE_TARGET_CLASS , 0 );
9170
9297
}
9171
9298
9172
- if (implements_ast ) {
9173
- zend_compile_implements (implements_ast );
9174
- }
9175
-
9176
9299
if (ce -> ce_flags & ZEND_ACC_ENUM ) {
9177
9300
if (enum_backing_type_ast != NULL ) {
9178
9301
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)
9181
9304
zend_enum_register_props (ce );
9182
9305
}
9183
9306
9307
+ if (ce -> lexical_scope -> type == ZEND_NAMESPACE_CLASS ) {
9308
+ zend_scan_nested_class_decl (stmt_ast , name );
9309
+ }
9184
9310
zend_compile_stmt (stmt_ast );
9185
9311
9186
9312
/* Reset lineno for final opcodes and errors */
@@ -9190,8 +9316,6 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9190
9316
zend_verify_abstract_class (ce );
9191
9317
}
9192
9318
9193
- CG (active_class_entry ) = original_ce ;
9194
-
9195
9319
if (toplevel ) {
9196
9320
ce -> ce_flags |= ZEND_ACC_TOP_LEVEL ;
9197
9321
}
@@ -9212,7 +9336,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9212
9336
&& !zend_compile_ignore_class (parent_ce , ce -> info .user .filename )) {
9213
9337
if (zend_try_early_bind (ce , parent_ce , lcname , NULL )) {
9214
9338
zend_string_release (lcname );
9215
- return ;
9339
+ goto compile_nested_classes ;
9216
9340
}
9217
9341
}
9218
9342
} 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)
9221
9345
zend_inheritance_check_override (ce );
9222
9346
ce -> ce_flags |= ZEND_ACC_LINKED ;
9223
9347
zend_observer_class_linked_notify (ce , lcname );
9224
- return ;
9348
+ goto compile_nested_classes ;
9225
9349
} else {
9226
9350
goto link_unbound ;
9227
9351
}
@@ -9291,6 +9415,24 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
9291
9415
opline -> result .opline_num = -1 ;
9292
9416
}
9293
9417
}
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 );
9294
9436
}
9295
9437
/* }}} */
9296
9438
@@ -11581,6 +11723,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
11581
11723
zend_compile_use_trait (ast );
11582
11724
break ;
11583
11725
case ZEND_AST_CLASS :
11726
+ if (CG (active_class_entry )) {
11727
+ zend_defer_class_decl (ast );
11728
+ break ;
11729
+ }
11584
11730
zend_compile_class_decl (NULL , ast , 0 );
11585
11731
break ;
11586
11732
case ZEND_AST_GROUP_USE :
0 commit comments