Skip to content

Commit 1126520

Browse files
committed
allow looking up classes in scopes
1 parent 26b7eb7 commit 1126520

File tree

5 files changed

+81
-28
lines changed

5 files changed

+81
-28
lines changed

Zend/zend_execute.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ ZEND_API void execute_ex(zend_execute_data *execute_data);
4949
ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value);
5050
ZEND_API bool zend_is_valid_class_name(zend_string *name);
5151
ZEND_API zend_class_entry *zend_lookup_class(zend_string *name);
52+
ZEND_API zend_class_entry *zend_lookup_class_in_scope(zend_string *name, const zend_class_entry *scope);
5253
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *lcname, uint32_t flags);
5354
ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex);
5455
ZEND_API zend_object *zend_get_this_object(zend_execute_data *ex);

Zend/zend_execute_API.c

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <stdio.h>
2222
#include <signal.h>
23+
#include <zend_namespaces.h>
2324

2425
#include "zend.h"
2526
#include "zend_compile.h"
@@ -1167,13 +1168,14 @@ ZEND_API bool zend_is_valid_class_name(zend_string *name) {
11671168
}
11681169

11691170
static zend_string *get_namespace_from_scope(const zend_class_entry *scope) {
1171+
ZEND_ASSERT(scope != NULL);
11701172
while (scope && scope->lexical_scope && scope->type != ZEND_NAMESPACE_CLASS) {
11711173
scope = scope->lexical_scope;
11721174
}
1173-
return scope->name;
1175+
return zend_string_copy(scope->name);
11741176
}
11751177

1176-
static zend_string *get_scoped_name(const zend_string *ns, zend_string *name) {
1178+
static zend_string *get_scoped_name(zend_string *ns, zend_string *name) {
11771179
// remove the matching prefix from name
11781180
name = zend_string_tolower(name);
11791181
if (ns && ZSTR_LEN(ns) && ZSTR_LEN(name) > ZSTR_LEN(ns) + 1 &&
@@ -1183,10 +1185,44 @@ static zend_string *get_scoped_name(const zend_string *ns, zend_string *name) {
11831185
zend_string_release(name);
11841186
return ret;
11851187
}
1186-
zend_string_release(name);
11871188
return name;
11881189
}
11891190

1191+
zend_class_entry *zend_lookup_class_in_scope(zend_string *name, const zend_class_entry *scope) {
1192+
zend_class_entry *ce = NULL;
1193+
zend_string *ns_name = get_namespace_from_scope(scope);
1194+
zend_string *original_suffix = get_scoped_name(ns_name, name);
1195+
zend_string_release(ns_name);
1196+
1197+
const zend_class_entry *current_scope = scope;
1198+
1199+
// Traverse upwards in lexical scope, stop at namespace boundary
1200+
while (current_scope && current_scope->type != ZEND_NAMESPACE_CLASS) {
1201+
// build fully-qualified name: current_scope->name + "\\" + original_suffix
1202+
zend_string *try_name = zend_string_concat3(
1203+
ZSTR_VAL(current_scope->name), ZSTR_LEN(current_scope->name),
1204+
"\\", 1,
1205+
ZSTR_VAL(original_suffix), ZSTR_LEN(original_suffix)
1206+
);
1207+
1208+
zend_string *lc_try_name = zend_string_tolower(try_name);
1209+
zend_string_release(try_name);
1210+
1211+
ce = zend_hash_find_ptr(EG(class_table), lc_try_name);
1212+
zend_string_release(lc_try_name);
1213+
1214+
if (ce) {
1215+
zend_string_release(original_suffix);
1216+
return ce;
1217+
}
1218+
1219+
current_scope = current_scope->lexical_scope;
1220+
}
1221+
1222+
zend_string_release(original_suffix);
1223+
return NULL;
1224+
}
1225+
11901226
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */
11911227
{
11921228
zend_class_entry *ce = NULL;
@@ -1205,26 +1241,25 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
12051241

12061242
if (!zend_is_compiling()) {
12071243
const zend_class_entry *scope = zend_get_executed_scope();
1208-
if (scope && scope->lexical_scope && scope->lexical_scope->type != ZEND_NAMESPACE_CLASS) {
1209-
zend_string *ns_name = get_namespace_from_scope(scope);
1210-
zend_string *scoped_name = get_scoped_name(ns_name, name);
1211-
while (scope->type != ZEND_NAMESPACE_CLASS) {
1212-
zend_string *try_name = zend_string_concat3(ZSTR_VAL(scope->name), ZSTR_LEN(scope->name), "\\", 1, ZSTR_VAL(scoped_name), ZSTR_LEN(scoped_name));
1213-
lc_name = zend_string_tolower(try_name);
1214-
ce = zend_hash_find_ptr(EG(class_table), lc_name);
1215-
if (ce) {
1216-
zend_string_release(lc_name);
1217-
zend_string_release(scoped_name);
1218-
zend_string_release(ns_name);
1219-
zend_string_release(try_name);
1220-
return ce;
1244+
if (scope) {
1245+
ce = zend_lookup_class_in_scope(name, scope);
1246+
if (ce) {
1247+
if (ce_cache) {
1248+
SET_CE_CACHE(ce_cache, ce);
12211249
}
1222-
scope = scope->lexical_scope;
1223-
zend_string_release(lc_name);
1224-
zend_string_release(try_name);
1250+
return ce;
1251+
}
1252+
}
1253+
} else if (CG(active_class_entry)) {
1254+
const zend_class_entry *scope = CG(active_class_entry);
1255+
if (scope) {
1256+
ce = zend_lookup_class_in_scope(name, scope);
1257+
if (ce) {
1258+
if (ce_cache) {
1259+
SET_CE_CACHE(ce_cache, ce);
1260+
}
1261+
return ce;
12251262
}
1226-
zend_string_release(ns_name);
1227-
zend_string_release(scoped_name);
12281263
}
12291264
}
12301265

Zend/zend_inheritance.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,12 @@ static zend_class_entry *lookup_class_ex(
280280
return ce;
281281
}
282282

283-
ce = zend_lookup_class_ex(
284-
name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
283+
ce = zend_lookup_class_in_scope(name, scope);
284+
285+
if (!ce) {
286+
ce = zend_lookup_class_ex(
287+
name, NULL, ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
288+
}
285289

286290
if (!CG(in_compilation) || in_preload) {
287291
if (ce) {
@@ -3531,9 +3535,13 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
35313535
ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
35323536

35333537
if (ce->parent_name) {
3534-
parent = zend_fetch_class_by_name(
3535-
ce->parent_name, lc_parent_name,
3536-
ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3538+
parent = zend_lookup_class_in_scope(ce->parent_name, ce);
3539+
3540+
if (!parent) {
3541+
parent = zend_fetch_class_by_name(
3542+
ce->parent_name, lc_parent_name,
3543+
ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
3544+
}
35373545
if (!parent) {
35383546
check_unrecoverable_load_failure(ce);
35393547
return NULL;

Zend/zend_namespaces.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,12 +107,20 @@ zend_class_entry *zend_resolve_namespace(zend_string *name) {
107107
return ns;
108108
}
109109

110+
zend_class_entry *zend_lookup_namespace(zend_string *name) {
111+
zend_string *lc_name = zend_string_tolower(name);
112+
zend_class_entry *ns = zend_hash_find_ptr(&namespaces, lc_name);
113+
zend_string_release(lc_name);
114+
115+
return ns;
116+
}
117+
110118
void zend_destroy_namespaces(void) {
111119
if (global_namespace == NULL) {
112120
return;
113121
}
114122

115-
const zend_class_entry *ns = NULL;
123+
zend_class_entry *ns = NULL;
116124
ZEND_HASH_FOREACH_PTR(&namespaces, ns) {
117125
zend_string_release(ns->name);
118126
} ZEND_HASH_FOREACH_END();

Zend/zend_namespaces.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
#include "zend.h"
2424
#include "zend_compile.h"
2525

26-
zend_class_entry *zend_resolve_namespace(zend_string *name);
26+
ZEND_API zend_class_entry *zend_resolve_namespace(zend_string *name);
2727
void zend_destroy_namespaces(void);
28+
ZEND_API zend_class_entry *zend_lookup_namespace(zend_string *name);
2829

2930
#endif //ZEND_NAMESPACES_H

0 commit comments

Comments
 (0)