Skip to content

Commit ccb691b

Browse files
committed
allow inner classes to use \\ now
1 parent e712a4f commit ccb691b

7 files changed

+207
-2
lines changed

Zend/zend_compile.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
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; \
@@ -9188,7 +9189,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
91889189
// rename the inner class so we may reference it by name
91899190
name = zend_string_concat3(
91909191
ZSTR_VAL(CG(active_class_entry)->name), ZSTR_LEN(CG(active_class_entry)->name),
9191-
":>", 2,
9192+
"\\", 1,
91929193
ZSTR_VAL(unqualified_name), ZSTR_LEN(unqualified_name)
91939194
);
91949195

@@ -9222,7 +9223,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel)
92229223
} else {
92239224
name = zend_prefix_with_ns(unqualified_name);
92249225
ce->required_scope = NULL;
9225-
ce->lexical_scope = NULL;
9226+
ce->lexical_scope = zend_resolve_namespace(FC(current_namespace));
92269227
}
92279228
name = zend_new_interned_string(name);
92289229
lcname = zend_string_tolower(name);

Zend/zend_compile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
10621062

10631063
#define ZEND_INTERNAL_CLASS 1
10641064
#define ZEND_USER_CLASS 2
1065+
#define ZEND_NAMESPACE_CLASS 4
10651066

10661067
#define ZEND_EVAL (1<<0)
10671068
#define ZEND_INCLUDE (1<<1)

Zend/zend_execute_API.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,27 @@ ZEND_API bool zend_is_valid_class_name(zend_string *name) {
11661166
return 1;
11671167
}
11681168

1169+
static zend_string *get_namespace_from_scope(const zend_class_entry *scope) {
1170+
while (scope && scope->lexical_scope && scope->type != ZEND_NAMESPACE_CLASS) {
1171+
scope = scope->lexical_scope;
1172+
}
1173+
return scope->name;
1174+
}
1175+
1176+
static zend_string *get_scoped_name(const zend_string *ns, zend_string *name) {
1177+
// remove the matching prefix from name
1178+
name = zend_string_tolower(name);
1179+
if (ns && ZSTR_LEN(ns) && ZSTR_LEN(name) > ZSTR_LEN(ns) + 1 &&
1180+
memcmp(ZSTR_VAL(name), ZSTR_VAL(ns), ZSTR_LEN(ns)) == 0 &&
1181+
ZSTR_VAL(name)[ZSTR_LEN(ns)] == '\\') {
1182+
zend_string *ret = zend_string_init(ZSTR_VAL(name) + ZSTR_LEN(ns) + 1, ZSTR_LEN(name) - ZSTR_LEN(ns) - 1, 0);
1183+
zend_string_release(name);
1184+
return ret;
1185+
}
1186+
zend_string_release(name);
1187+
return name;
1188+
}
1189+
11691190
ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *key, uint32_t flags) /* {{{ */
11701191
{
11711192
zend_class_entry *ce = NULL;
@@ -1182,6 +1203,31 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
11821203
}
11831204
}
11841205

1206+
if (!zend_is_compiling()) {
1207+
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;
1221+
}
1222+
scope = scope->lexical_scope;
1223+
zend_string_release(lc_name);
1224+
zend_string_release(try_name);
1225+
}
1226+
zend_string_release(ns_name);
1227+
zend_string_release(scoped_name);
1228+
}
1229+
}
1230+
11851231
if (key) {
11861232
lc_name = key;
11871233
} else {

Zend/zend_namespaces.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 2.00 of the Zend license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.zend.com/license/2_00.txt. |
11+
| If you did not receive a copy of the Zend license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Rob Landers <[email protected]> |
16+
| |
17+
+----------------------------------------------------------------------+
18+
*/
19+
20+
#include "zend_namespaces.h"
21+
22+
#include <zend_smart_str.h>
23+
24+
#include "zend_API.h"
25+
#include "zend_hash.h"
26+
27+
static zend_class_entry *global_namespace = NULL;
28+
static HashTable namespaces;
29+
30+
static zend_class_entry *create_namespace(zend_string *name) {
31+
zend_class_entry *ns = pemalloc(sizeof(zend_class_entry), 1);
32+
memset(ns, 0, sizeof(zend_class_entry));
33+
zend_initialize_class_data(ns, 1);
34+
ns->type = ZEND_NAMESPACE_CLASS;
35+
36+
zend_string *interned_name = zend_new_interned_string(zend_string_copy(name));
37+
ns->name = interned_name;
38+
39+
return ns;
40+
}
41+
42+
static zend_class_entry *insert_namespace(const zend_string *name) {
43+
zend_class_entry *ns = NULL;
44+
zend_class_entry *parent_ns = global_namespace;
45+
zend_string *part = NULL;
46+
const char *start = ZSTR_VAL(name);
47+
const char *end = start + ZSTR_LEN(name);
48+
const char *pos = start;
49+
size_t len = 0;
50+
51+
smart_str current_ns = {0};
52+
53+
while (pos <= end) {
54+
if (pos == end || *pos == '\\') {
55+
len = pos - start;
56+
part = zend_string_init(start, len, 0);
57+
58+
if (current_ns.s) {
59+
smart_str_appendc(&current_ns, '\\');
60+
}
61+
smart_str_appendl(&current_ns, ZSTR_VAL(part), ZSTR_LEN(part));
62+
smart_str_0(&current_ns);
63+
64+
zend_string *needle = zend_string_init(ZSTR_VAL(current_ns.s), ZSTR_LEN(current_ns.s), 0);
65+
ns = zend_hash_find_ptr(&namespaces, needle);
66+
67+
if (!ns) {
68+
ns = create_namespace(needle);
69+
ns->parent = parent_ns;
70+
zend_hash_add_ptr(&namespaces, current_ns.s, ns);
71+
}
72+
73+
zend_string_release(part);
74+
zend_string_release(needle);
75+
76+
parent_ns = ns;
77+
start = pos + 1;
78+
}
79+
pos++;
80+
}
81+
82+
smart_str_free(&current_ns);
83+
84+
return ns;
85+
}
86+
87+
zend_class_entry *zend_resolve_namespace(zend_string *name) {
88+
if (global_namespace == NULL) {
89+
global_namespace = create_namespace(zend_empty_string);
90+
zend_hash_init(&namespaces, 8, NULL, ZEND_CLASS_DTOR, 1);
91+
zend_hash_add_ptr(&namespaces, zend_empty_string, global_namespace);
92+
}
93+
94+
if (name == NULL || ZSTR_LEN(name) == 0) {
95+
return global_namespace;
96+
}
97+
98+
zend_string *lc_name = zend_string_tolower(name);
99+
zend_class_entry *ns = zend_hash_find_ptr(&namespaces, lc_name);
100+
101+
if (!ns) {
102+
ns = insert_namespace(lc_name);
103+
}
104+
105+
zend_string_release(lc_name);
106+
107+
return ns;
108+
}
109+
110+
void zend_destroy_namespaces() {
111+
if (global_namespace == NULL) {
112+
return;
113+
}
114+
115+
const zend_class_entry *ns = NULL;
116+
ZEND_HASH_FOREACH_PTR(&namespaces, ns) {
117+
zend_string_release(ns->name);
118+
} ZEND_HASH_FOREACH_END();
119+
120+
zend_hash_destroy(&namespaces);
121+
zend_string_release(global_namespace->name);
122+
pefree(global_namespace, 1);
123+
}

Zend/zend_namespaces.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| Zend Engine |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 2.00 of the Zend license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.zend.com/license/2_00.txt. |
11+
| If you did not receive a copy of the Zend license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Rob Landers <[email protected]> |
16+
| |
17+
+----------------------------------------------------------------------+
18+
*/
19+
20+
#ifndef ZEND_NAMESPACES_H
21+
#define ZEND_NAMESPACES_H
22+
23+
#include "zend.h"
24+
#include "zend_compile.h"
25+
26+
zend_class_entry *zend_resolve_namespace(zend_string *name);
27+
void zend_destroy_namespaces(void);
28+
29+
#endif //ZEND_NAMESPACES_H

configure.ac

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,7 @@ PHP_ADD_SOURCES([Zend], m4_normalize([
17571757
zend_opcode.c
17581758
zend_operators.c
17591759
zend_property_hooks.c
1760+
zend_namespaces.c
17601761
zend_ptr_stack.c
17611762
zend_signal.c
17621763
zend_smart_str.c

main/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
#include <sys/wait.h>
6767
#endif
6868

69+
#include <zend_namespaces.h>
70+
6971
#include "zend_compile.h"
7072
#include "zend_execute.h"
7173
#include "zend_highlight.h"
@@ -1966,6 +1968,8 @@ void php_request_shutdown(void *dummy)
19661968
zend_post_deactivate_modules();
19671969
} zend_end_try();
19681970

1971+
zend_destroy_namespaces();
1972+
19691973
/* 12. SAPI related shutdown*/
19701974
zend_try {
19711975
sapi_deactivate_module();

0 commit comments

Comments
 (0)