Skip to content

Commit 23c5f68

Browse files
committed
update and fix tests
1 parent e687dae commit 23c5f68

File tree

4 files changed

+94
-23
lines changed

4 files changed

+94
-23
lines changed

Zend/zend_compile.c

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,61 @@ static zend_string *zend_resolve_const_name(zend_string *name, uint32_t type, bo
11791179
name, type, is_fully_qualified, 1, FC(imports_const));
11801180
}
11811181

1182+
static zend_string *get_namespace_from_scope(const zend_class_entry *scope) {
1183+
ZEND_ASSERT(scope != NULL);
1184+
while (scope && scope->lexical_scope && scope->type != ZEND_NAMESPACE_CLASS) {
1185+
scope = scope->lexical_scope;
1186+
}
1187+
return zend_string_copy(scope->name);
1188+
}
1189+
1190+
static zend_string *get_scoped_name(zend_string *ns, zend_string *name) {
1191+
// remove the matching prefix from name
1192+
name = zend_string_tolower(name);
1193+
if (ns && ZSTR_LEN(ns) && ZSTR_LEN(name) > ZSTR_LEN(ns) + 1 &&
1194+
memcmp(ZSTR_VAL(name), ZSTR_VAL(ns), ZSTR_LEN(ns)) == 0 &&
1195+
ZSTR_VAL(name)[ZSTR_LEN(ns)] == '\\') {
1196+
zend_string *ret = zend_string_init(ZSTR_VAL(name) + ZSTR_LEN(ns) + 1, ZSTR_LEN(name) - ZSTR_LEN(ns) - 1, 0);
1197+
zend_string_release(name);
1198+
return ret;
1199+
}
1200+
return name;
1201+
}
1202+
1203+
zend_string *zend_resolve_class_in_scope(zend_string *name, const zend_class_entry *scope) {
1204+
zend_string *ns_name = get_namespace_from_scope(scope);
1205+
zend_string *original_suffix = get_scoped_name(ns_name, name);
1206+
zend_string_release(ns_name);
1207+
1208+
const zend_class_entry *current_scope = scope;
1209+
1210+
// Traverse upwards in lexical scope, stop at namespace boundary
1211+
while (current_scope && current_scope->type != ZEND_NAMESPACE_CLASS) {
1212+
// build fully-qualified name: current_scope->name + "\\" + original_suffix
1213+
zend_string *try_name = zend_string_concat3(
1214+
ZSTR_VAL(current_scope->name), ZSTR_LEN(current_scope->name),
1215+
"\\", 1,
1216+
ZSTR_VAL(original_suffix), ZSTR_LEN(original_suffix)
1217+
);
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+
11821237
static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /* {{{ */
11831238
{
11841239
char *compound;
@@ -1237,6 +1292,13 @@ static zend_string *zend_resolve_class_name(zend_string *name, uint32_t type) /*
12371292
}
12381293
}
12391294

1295+
if (CG(active_class_entry)) {
1296+
zend_string *import_name = zend_resolve_class_in_scope(name, CG(active_class_entry));
1297+
if (import_name) {
1298+
return import_name;
1299+
}
1300+
}
1301+
12401302
/* If not fully qualified and not an alias, prepend the current namespace */
12411303
return zend_prefix_with_ns(name);
12421304
}
@@ -9139,6 +9201,27 @@ static void zend_defer_class_decl(zend_ast *ast) {
91399201
zend_hash_next_index_insert_ptr(inner_class_queue, ast);
91409202
}
91419203

9204+
static void zend_scan_nested_class_decl(zend_ast *ast) {
9205+
ZEND_ASSERT(CG(active_class_entry));
9206+
9207+
const zend_ast_list *list = zend_ast_get_list(ast);
9208+
for (int i = 0; i < list->children; i++) {
9209+
ast = list->child[i];
9210+
if (ast->kind == ZEND_AST_CLASS) {
9211+
const zend_ast_decl *decl = (zend_ast_decl *) ast;
9212+
zend_string *name = zend_string_concat3(
9213+
ZSTR_VAL(CG(active_class_entry)->name), ZSTR_LEN(CG(active_class_entry)->name),
9214+
"\\", 1,
9215+
ZSTR_VAL(decl->name), ZSTR_LEN(decl->name)
9216+
);
9217+
zend_string *lc_name = zend_string_tolower(name);
9218+
zend_register_seen_symbol(lc_name, ZEND_SYMBOL_CLASS);
9219+
zend_string_release(name);
9220+
zend_string_release(lc_name);
9221+
}
9222+
}
9223+
}
9224+
91429225
static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* {{{ */
91439226
{
91449227
zend_ast_decl *decl = (zend_ast_decl *) ast;
@@ -9287,6 +9370,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92879370
zend_enum_register_props(ce);
92889371
}
92899372

9373+
zend_scan_nested_class_decl(stmt_ast);
92909374
zend_compile_stmt(stmt_ast);
92919375

92929376
/* Reset lineno for final opcodes and errors */
@@ -11683,6 +11767,10 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1168311767
zend_compile_use_trait(ast);
1168411768
break;
1168511769
case ZEND_AST_CLASS:
11770+
if (CG(active_class_entry)) {
11771+
zend_defer_class_decl(ast);
11772+
break;
11773+
}
1168611774
zend_compile_class_decl(NULL, ast, 0);
1168711775
break;
1168811776
case ZEND_AST_GROUP_USE:
@@ -11692,10 +11780,6 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1169211780
zend_compile_use(ast);
1169311781
break;
1169411782
case ZEND_AST_CONST_DECL:
11695-
if (CG(active_class_entry)) {
11696-
zend_defer_class_decl(ast);
11697-
break;
11698-
}
1169911783
zend_compile_const_decl(ast);
1170011784
break;
1170111785
case ZEND_AST_NAMESPACE:

tests/classes/inner_classes/inheritance.phpt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
--TEST--
2-
inheritance
2+
circular inheritance
33
--FILE--
44
<?php
55

6-
7-
86
class Outer {
97
class Middle extends Outer\Other {
10-
class Inner1 extends Other {}
11-
class Inner2 extends Inner1 {}
8+
class Inner1 extends Inner2 {}
9+
class Inner2 extends Other {}
1210
}
1311
abstract class Other {}
1412
}

tests/classes/inner_classes/simple_declaration_004.phpt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,12 @@ class Outer2 extends Outer {
2727
var_dump(Outer::testSelf());
2828
var_dump(Outer2::testParent());
2929
var_dump(Outer2::testSelf());
30-
var_dump(Outer2::testSelf());
3130

3231
?>
3332
--EXPECT--
3433
object(Outer\Middle)#1 (0) {
3534
}
3635
object(Outer\Middle)#1 (0) {
3736
}
38-
object(Outer\Middle)#1 (0) {
39-
}
40-
object(Outer\Middle)#1 (0) {
37+
object(Outer2\Middle)#1 (0) {
4138
}

tests/classes/inner_classes/simple_declaration_005.phpt

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,5 @@ var_dump(Outer2::testSelf());
3030
var_dump(Outer2::testSelf());
3131

3232
?>
33-
--EXPECT--
34-
THIS IS WRONG
35-
object(Outer\Middle)#1 (0) {
36-
}
37-
object(Outer\Middle)#1 (0) {
38-
}
39-
object(Outer\Middle)#1 (0) {
40-
}
41-
object(Outer\Middle)#1 (0) {
42-
}
33+
--EXPECTF--
34+
Fatal error: Declaration of Outer2::testSelf(): Outer2\middle must be compatible with Outer::testSelf(): Outer\middle in %s on line %d

0 commit comments

Comments
 (0)