Skip to content

Commit a4c3b2c

Browse files
committed
Namespace patch. Big changes:
1. Nested classes are gone. 2. New syntax for namespaces: namespace foo { class X { ... } function bar { ... } var x = 1; const ZZ = 2; } 3. Namespaced symbol access: $x = new foo::X; - etc. For now, namespaces are case insensitive, just like classes. Also, there can be no global class and namespace with the same name (to avoid ambiguities in :: resolution).
1 parent 0a18a9d commit a4c3b2c

12 files changed

+399
-69
lines changed

Zend/zend.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@
2929
#include "zend_ini.h"
3030

3131
#ifdef ZTS
32-
# define GLOBAL_FUNCTION_TABLE &global_main_class.function_table
33-
# define GLOBAL_CLASS_TABLE &global_main_class.class_table
34-
# define GLOBAL_CONSTANTS_TABLE &global_main_class.constants_table
32+
# define GLOBAL_FUNCTION_TABLE &global_namespace.function_table
33+
# define GLOBAL_CLASS_TABLE &global_namespace.class_table
34+
# define GLOBAL_CONSTANTS_TABLE &global_namespace.constants_table
3535
# define GLOBAL_AUTO_GLOBALS_TABLE global_auto_globals_table
3636
#else
3737
# define GLOBAL_FUNCTION_TABLE CG(function_table)
@@ -92,6 +92,7 @@ ZEND_API int compiler_globals_id;
9292
ZEND_API int executor_globals_id;
9393
ZEND_API int alloc_globals_id;
9494
zend_class_entry global_main_class;
95+
zend_namespace global_namespace;
9596
HashTable *global_auto_globals_table;
9697
#endif
9798

@@ -401,11 +402,11 @@ static void compiler_globals_ctor(zend_compiler_globals *compiler_globals TSRMLS
401402

402403
compiler_globals->compiled_filename = NULL;
403404

404-
compiler_globals->function_table = &compiler_globals->main_class.function_table;
405+
compiler_globals->function_table = &compiler_globals->global_namespace.function_table;
405406
zend_hash_init_ex(compiler_globals->function_table, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);
406407
zend_hash_copy(compiler_globals->function_table, GLOBAL_FUNCTION_TABLE, NULL, &tmp_func, sizeof(zend_function));
407408

408-
compiler_globals->class_table = &compiler_globals->main_class.class_table;
409+
compiler_globals->class_table = &compiler_globals->global_namespace.class_table;
409410
zend_hash_init_ex(compiler_globals->class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
410411
zend_hash_copy(compiler_globals->class_table, GLOBAL_CLASS_TABLE, (copy_ctor_func_t) zend_class_add_ref, &tmp_class, sizeof(zend_class_entry *));
411412

@@ -551,8 +552,9 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions, i
551552
zend_version_info_length = sizeof(ZEND_CORE_VERSION_INFO)-1;
552553

553554
#ifndef ZTS
554-
GLOBAL_FUNCTION_TABLE = &compiler_globals.main_class.function_table;
555-
GLOBAL_CLASS_TABLE = &compiler_globals.main_class.class_table;
555+
GLOBAL_FUNCTION_TABLE = &compiler_globals.global_namespace.function_table;
556+
GLOBAL_CLASS_TABLE = &compiler_globals.global_namespace.class_table;
557+
compiler_globals.global_namespace.static_members = NULL;
556558
#endif
557559
GLOBAL_AUTO_GLOBALS_TABLE = (HashTable *) malloc(sizeof(HashTable));
558560
zend_hash_init_ex(GLOBAL_FUNCTION_TABLE, 100, NULL, ZEND_FUNCTION_DTOR, 1, 0);

Zend/zend.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,18 @@ struct _zval_struct {
262262
zend_uchar is_ref;
263263
};
264264

265+
struct _zend_op_array;
265266

267+
/* typedef struct _zend_namespace {
268+
char *name;
269+
zend_uint name_length;
270+
HashTable function_table;
271+
HashTable class_table;
272+
HashTable constants_table;
273+
HashTable *global_variables;
274+
struct _zend_op_array *op_array;
275+
} zend_namespace;
276+
*/
266277

267278
typedef struct _zend_function_entry {
268279
char *fname;
@@ -308,6 +319,7 @@ struct _zend_class_entry {
308319
HashTable *static_members;
309320
HashTable constants_table;
310321
zend_function_entry *builtin_functions;
322+
struct _zend_class_entry *namespace;
311323

312324
union _zend_function *constructor;
313325
union _zend_function *destructor;
@@ -316,6 +328,7 @@ struct _zend_class_entry {
316328
union _zend_function *__set;
317329
union _zend_function *__call;
318330

331+
319332
/* handlers */
320333
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
321334

@@ -327,6 +340,7 @@ struct _zend_class_entry {
327340
#endif
328341
};
329342

343+
typedef struct _zend_class_entry zend_namespace; /* namespace is the same as class */
330344

331345
typedef struct _zend_utility_functions {
332346
void (*error_function)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args);

Zend/zend_compile.c

Lines changed: 128 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void zend_init_compiler_data_structures(TSRMLS_D)
7474
zend_stack_init(&CG(object_stack));
7575
zend_stack_init(&CG(declare_stack));
7676
CG(active_class_entry) = NULL;
77-
CG(active_ce_parent_class_name).value.str.val = NULL;
77+
CG(active_namespace) = &CG(global_namespace);
7878
zend_llist_init(&CG(list_llist), sizeof(list_llist_element), NULL, 0);
7979
zend_llist_init(&CG(dimension_llist), sizeof(int), NULL, 0);
8080
zend_stack_init(&CG(list_stack));
@@ -937,6 +937,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
937937
op_array.fn_flags = fn_flags;
938938

939939
op_array.scope = CG(active_class_entry);
940+
op_array.namespace = CG(active_namespace);
940941

941942
if (is_method) {
942943
char *short_class_name = CG(active_class_entry)->name;
@@ -1150,7 +1151,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC)
11501151
}
11511152

11521153

1153-
void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_DC)
1154+
void do_fetch_class(znode *result, znode *namespace_name, znode *class_name TSRMLS_DC)
11541155
{
11551156
long fetch_class_op_number;
11561157
zend_op *opline;
@@ -1159,8 +1160,9 @@ void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_
11591160
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
11601161

11611162
opline->opcode = ZEND_FETCH_CLASS;
1162-
if (class_entry) {
1163-
opline->op1 = *class_entry;
1163+
if (namespace_name) {
1164+
zend_str_tolower(namespace_name->u.constant.value.str.val, namespace_name->u.constant.value.str.len);
1165+
opline->op1 = *namespace_name;
11641166
} else {
11651167
SET_UNUSED(opline->op1);
11661168
CG(catch_begin) = fetch_class_op_number;
@@ -1675,6 +1677,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze
16751677
zend_initialize_class_data(new_class_entry, 1);
16761678

16771679
zend_str_tolower(new_class_entry->name, new_class_entry->name_length);
1680+
16781681
if (zend_hash_update(class_table, new_class_entry->name, name_length+1, &new_class_entry, sizeof(zend_class_entry *), NULL) == FAILURE) {
16791682
zend_error(E_COMPILE_ERROR, "Can't create class. Fatal error, please report!");
16801683
}
@@ -1715,7 +1718,7 @@ static int create_nested_class(HashTable *class_table, char *path, zend_class_en
17151718
new_ce->refcount++;
17161719
if (zend_hash_add(&ce->class_table, last, strlen(last)+1, &new_ce, sizeof(zend_class_entry *), NULL) == FAILURE) {
17171720
new_ce->refcount--;
1718-
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", last);
1721+
zend_error(E_COMPILE_ERROR, "Cannot redeclare class '%s' - class or namespace with this name already exist.", last);
17191722
return FAILURE;
17201723
}
17211724
return SUCCESS;
@@ -1726,7 +1729,7 @@ ZEND_API int do_bind_function(zend_op *opline, HashTable *function_table, HashTa
17261729
zend_function *function;
17271730

17281731
if (opline->opcode != ZEND_DECLARE_FUNCTION) {
1729-
zend_error(E_ERROR, "Internal compiler error. Please report!");
1732+
zend_error(E_COMPILE_ERROR, "Internal compiler error. Please report!");
17301733
}
17311734

17321735
zend_hash_find(function_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void *) &function);
@@ -1758,7 +1761,7 @@ ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable
17581761
zend_class_entry *ce, **pce;
17591762

17601763
if (zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce)==FAILURE) {
1761-
zend_error(E_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
1764+
zend_error(E_COMPILE_ERROR, "Internal Zend error - Missing class information for %s", opline->op1.u.constant.value.str.val);
17621765
return FAILURE;
17631766
} else {
17641767
ce = *pce;
@@ -1769,7 +1772,7 @@ ZEND_API int do_bind_class(zend_op *opline, HashTable *function_table, HashTable
17691772
ce->refcount++;
17701773
if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, &ce, sizeof(zend_class_entry *), NULL)==FAILURE) {
17711774
ce->refcount--;
1772-
zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
1775+
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
17731776
return FAILURE;
17741777
} else {
17751778
return SUCCESS;
@@ -1784,7 +1787,7 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table,
17841787
found_ce = zend_hash_find(class_table, opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, (void **) &pce);
17851788

17861789
if (found_ce == FAILURE) {
1787-
zend_error(E_ERROR, "Cannot redeclare class %s", (*pce)->name);
1790+
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", (*pce)->name);
17881791
return FAILURE;
17891792
} else {
17901793
ce = *pce;
@@ -1800,7 +1803,7 @@ ZEND_API int do_bind_inherited_class(zend_op *opline, HashTable *function_table,
18001803

18011804
/* Register the derived class */
18021805
if (zend_hash_add(class_table, opline->op2.u.constant.value.str.val, opline->op2.u.constant.value.str.len+1, pce, sizeof(zend_class_entry *), NULL)==FAILURE) {
1803-
zend_error(E_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
1806+
zend_error(E_COMPILE_ERROR, "Cannot redeclare class %s", opline->op2.u.constant.value.str.val);
18041807
ce->refcount--;
18051808
zend_hash_destroy(&ce->function_table);
18061809
zend_hash_destroy(&ce->default_properties);
@@ -2114,7 +2117,6 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
21142117
int doing_inheritance = 0;
21152118
zend_class_entry *new_class_entry = emalloc(sizeof(zend_class_entry));
21162119

2117-
class_token->u.previously_active_class_entry = CG(active_class_entry);
21182120
if (!(strcmp(class_name->u.constant.value.str.val, "main") && strcmp(class_name->u.constant.value.str.val, "self") &&
21192121
strcmp(class_name->u.constant.value.str.val, "parent"))) {
21202122
zend_error(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", class_name->u.constant.value.str.val);
@@ -2148,7 +2150,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
21482150
opline->op2.op_type = IS_CONST;
21492151
opline->op2.u.constant.type = IS_STRING;
21502152
opline->op2.u.constant.refcount = 1;
2151-
2153+
21522154
if (doing_inheritance) {
21532155
opline->extended_value = parent_class_name->u.var;
21542156
opline->opcode = ZEND_DECLARE_INHERITED_CLASS;
@@ -2158,7 +2160,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
21582160

21592161
opline->op2.u.constant.value.str.val = estrndup(new_class_entry->name, new_class_entry->name_length);
21602162
opline->op2.u.constant.value.str.len = new_class_entry->name_length;
2161-
2163+
21622164
zend_hash_update(CG(class_table), opline->op1.u.constant.value.str.val, opline->op1.u.constant.value.str.len, &new_class_entry, sizeof(zend_class_entry *), NULL);
21632165
CG(active_class_entry) = new_class_entry;
21642166
}
@@ -2167,11 +2169,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
21672169
void zend_do_end_class_declaration(znode *class_token TSRMLS_DC)
21682170
{
21692171
do_inherit_parent_constructor(CG(active_class_entry));
2170-
CG(active_class_entry) = class_token->u.previously_active_class_entry;
2171-
if (CG(active_ce_parent_class_name).value.str.val) {
2172-
efree(CG(active_ce_parent_class_name).value.str.val);
2173-
CG(active_ce_parent_class_name).value.str.val = NULL;
2174-
}
2172+
CG(active_class_entry) = NULL;
21752173
}
21762174

21772175
void mangle_property_name(char **dest, int *dest_length, char *src1, int src1_length, char *src2, int src2_length)
@@ -3180,6 +3178,116 @@ void zend_destroy_property_info(zend_property_info *property_info)
31803178
efree(property_info->name);
31813179
}
31823180

3181+
void zend_init_namespace(zend_namespace *ns TSRMLS_DC)
3182+
{
3183+
zend_hash_init(&ns->function_table, 10, NULL, ZEND_FUNCTION_DTOR, 0);
3184+
zend_hash_init(&ns->class_table, 10, NULL, ZEND_CLASS_DTOR, 0);
3185+
zend_hash_init(&ns->constants_table, 10, NULL, ZVAL_PTR_DTOR, 0);
3186+
ALLOC_HASHTABLE(ns->static_members);
3187+
zend_hash_init(ns->static_members, 0, NULL, ZVAL_PTR_DTOR, 0);
3188+
ns->constructor = NULL;
3189+
ns->type = ZEND_NAMESPACE;
3190+
}
3191+
3192+
void zend_do_begin_namespace(znode *ns_token, znode *ns_name TSRMLS_DC)
3193+
{
3194+
zend_namespace *ns = emalloc(sizeof(zend_namespace));
3195+
zend_op *opline;
3196+
3197+
zend_str_tolower(ns_name->u.constant.value.str.val, ns_name->u.constant.value.str.len);
3198+
ns->name = ns_name->u.constant.value.str.val;
3199+
ns->name_length = ns_name->u.constant.value.str.len;
3200+
3201+
if(zend_hash_add(&CG(global_namespace).class_table, ns->name, ns->name_length+1, (void **)&ns, sizeof(zend_namespace *), NULL) != SUCCESS) {
3202+
efree(ns);
3203+
zend_error(E_COMPILE_ERROR, "Cannot redefine namespace '%s' - class or namespace with this name already defined", ns->name);
3204+
}
3205+
3206+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
3207+
3208+
opline->opcode = ZEND_DECLARE_NAMESPACE;
3209+
opline->op1.op_type = IS_CONST;
3210+
opline->op1.u.constant.type = IS_STRING;
3211+
opline->op1.u.constant.value.str.val = estrndup(ns->name, ns->name_length);
3212+
opline->op1.u.constant.value.str.len = ns->name_length;
3213+
opline->op1.u.constant.refcount = 1;
3214+
SET_UNUSED(opline->op2);
3215+
3216+
zend_init_namespace(ns TSRMLS_CC);
3217+
3218+
ns->constructor = emalloc(sizeof(zend_op_array));
3219+
init_op_array((zend_op_array *)ns->constructor, ZEND_USER_FUNCTION, INITIAL_OP_ARRAY_SIZE TSRMLS_CC);
3220+
ns->constructor->op_array.namespace = CG(active_namespace);
3221+
3222+
ns_token->u.op_array = CG(active_op_array);
3223+
3224+
CG(active_op_array) = &ns->constructor->op_array;
3225+
CG(active_namespace) = ns;
3226+
3227+
/* new symbol tables */
3228+
CG(class_table) = &ns->class_table;
3229+
CG(function_table) = &ns->function_table;
3230+
3231+
fprintf(stderr, "Start namespace '%s'\n", ns->name);
3232+
}
3233+
3234+
void zend_do_end_namespace(znode *ns_token TSRMLS_DC)
3235+
{
3236+
zend_namespace *ns = CG(active_op_array)->namespace;
3237+
int handle = CG(handle_op_arrays);
3238+
3239+
3240+
zend_do_return(NULL, 0 TSRMLS_CC);
3241+
CG(handle_op_arrays) = 0;
3242+
pass_two(CG(active_op_array) TSRMLS_CC);
3243+
CG(handle_op_arrays) = handle;
3244+
3245+
CG(active_op_array)->namespace = CG(active_namespace);
3246+
3247+
CG(active_namespace) = ns;
3248+
CG(active_op_array) = ns_token->u.op_array;
3249+
/* restore symbol tables */
3250+
CG(class_table) = &CG(active_namespace)->class_table;
3251+
CG(function_table) = &CG(active_namespace)->function_table;
3252+
3253+
fprintf(stderr, "End namespace\n");
3254+
}
3255+
3256+
void zend_do_declare_namespace_var(znode *var_name, znode *value TSRMLS_DC)
3257+
{
3258+
zval *var;
3259+
3260+
ALLOC_ZVAL(var);
3261+
3262+
if (value) {
3263+
*var = value->u.constant;
3264+
} else {
3265+
INIT_PZVAL(var);
3266+
var->type = IS_NULL;
3267+
}
3268+
3269+
zend_hash_update(CG(active_namespace)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &var, sizeof(zval *), NULL);
3270+
3271+
FREE_PNODE(var_name);
3272+
}
3273+
3274+
void zend_do_declare_namespace_constant(znode *var_name, znode *value TSRMLS_DC)
3275+
{
3276+
zval *var;
3277+
3278+
ALLOC_ZVAL(var);
3279+
3280+
if (value) {
3281+
*var = value->u.constant;
3282+
} else {
3283+
INIT_PZVAL(var);
3284+
var->type = IS_NULL;
3285+
}
3286+
3287+
zend_hash_update(&CG(active_namespace)->constants_table, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &var, sizeof(zval *), NULL);
3288+
3289+
FREE_PNODE(var_name);
3290+
}
31833291

31843292
void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers)
31853293
{
@@ -3211,6 +3319,8 @@ void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify_handlers
32113319
ce->__call = NULL;
32123320
ce->create_object = NULL;
32133321
}
3322+
3323+
ce->namespace = CG(active_namespace);
32143324
}
32153325

32163326
/*

0 commit comments

Comments
 (0)