From: Andi Gutmans Date: Fri, 30 Nov 2001 16:29:47 +0000 (+0000) Subject: - Initial support for class constants. There are still a few semantic X-Git-Tag: ChangeLog~217 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e858d27888471107a4816d62033db785fab5f2da;p=php - Initial support for class constants. There are still a few semantic - issues which need to be looked into but basically it seems to work. - Example: --- diff --git a/Zend/zend.c b/Zend/zend.c index 6ca79e954c..67b269c7cc 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -252,6 +252,7 @@ static void register_standard_class(void) zend_standard_class_def.parent = NULL; zend_hash_init_ex(&zend_standard_class_def.default_properties, 0, NULL, ZVAL_PTR_DTOR, 1, 0); zend_hash_init_ex(&zend_standard_class_def.static_members, 0, NULL, ZVAL_PTR_DTOR, 1, 0); + zend_hash_init_ex(&zend_standard_class_def.constants, 0, NULL, ZVAL_PTR_DTOR, 1, 0); zend_hash_init_ex(&zend_standard_class_def.class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0); zend_hash_init_ex(&zend_standard_class_def.function_table, 0, NULL, ZEND_FUNCTION_DTOR, 1, 0); zend_standard_class_def.constructor = NULL; diff --git a/Zend/zend.h b/Zend/zend.h index 924f541091..d835014ab9 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -285,6 +285,7 @@ struct _zend_class_entry { HashTable default_properties; HashTable class_table; HashTable static_members; + HashTable constants; zend_function_entry *builtin_functions; union _zend_function *constructor; diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 670e2e3c1f..e013d16a57 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1217,6 +1217,7 @@ ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_ class_entry->constants_updated = 0; zend_hash_init(&class_entry->default_properties, 0, NULL, ZVAL_PTR_DTOR, 1); zend_hash_init(&class_entry->static_members, 0, NULL, ZVAL_PTR_DTOR, 1); + zend_hash_init(&class_entry->constants, 0, NULL, ZVAL_PTR_DTOR, 1); zend_hash_init(&class_entry->function_table, 0, NULL, ZEND_FUNCTION_DTOR, 1); zend_hash_init(&class_entry->class_table, 10, NULL, ZEND_CLASS_DTOR, 1); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c1596ac3ef..5c6b4a9144 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -937,6 +937,25 @@ void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_ *result = opline->result; } + +void do_fetch_class_name(znode *result, znode *class_name_entry, znode *class_name TSRMLS_DC) +{ + zend_uint length; + + if (!result) { + result = class_name_entry; + } else { + *result = *class_name_entry; + } + + length = 1 + result->u.constant.value.str.len + class_name->u.constant.value.str.len; + result->u.constant.value.str.val = erealloc(result->u.constant.value.str.val, length+1); + memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len], ":", sizeof(":")-1); + memcpy(&result->u.constant.value.str.val[result->u.constant.value.str.len+1], class_name->u.constant.value.str.val, class_name->u.constant.value.str.len+1); + STR_FREE(class_name->u.constant.value.str.val); + result->u.constant.value.str.len = length; +} + void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name TSRMLS_DC) { unsigned char *ptr = NULL; @@ -1265,6 +1284,7 @@ void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce) zend_hash_merge(&ce->default_properties, &parent_ce->default_properties, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); /* STATIC_MEMBERS_FIXME */ zend_hash_merge(&ce->static_members, &parent_ce->static_members, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); + zend_hash_merge(&ce->constants, &parent_ce->constants, (void (*)(void *)) zval_add_ref, (void *) &tmp, sizeof(zval *), 0); zend_hash_merge(&ce->function_table, &parent_ce->function_table, (void (*)(void *)) function_add_ref, &tmp_zend_function, sizeof(zend_function), 0); ce->parent = parent_ce; if (!ce->handle_property_get) @@ -1372,6 +1392,7 @@ ZEND_API int do_bind_function_or_class(zend_op *opline, HashTable *function_tabl zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->default_properties); zend_hash_destroy(&ce->static_members); + zend_hash_destroy(&ce->constants); return FAILURE; } return SUCCESS; @@ -1704,6 +1725,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod zend_hash_init(&new_class_entry.class_table, 10, NULL, ZEND_CLASS_DTOR, 0); zend_hash_init(&new_class_entry.default_properties, 10, NULL, ZVAL_PTR_DTOR, 0); zend_hash_init(&new_class_entry.static_members, 10, NULL, ZVAL_PTR_DTOR, 0); + zend_hash_init(&new_class_entry.constants, 10, NULL, ZVAL_PTR_DTOR, 0); new_class_entry.constructor = NULL; @@ -1731,6 +1753,9 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod /* copy static members */ zend_hash_copy(&new_class_entry.static_members, &parent_class->static_members, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + /* copy constants */ + zend_hash_copy(&new_class_entry.constants, &parent_class->constants, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + new_class_entry.constructor = parent_class->constructor; /* copy overloaded handlers */ @@ -1808,10 +1833,16 @@ void zend_do_declare_property(znode *var_name, znode *value, int declaration_typ ALLOC_ZVAL(property); *property = value->u.constant; - if (declaration_type == T_VAR) { - zend_hash_update(&CG(active_class_entry)->default_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); - } else { - zend_hash_update(&CG(active_class_entry)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); + switch (declaration_type) { + case T_VAR: + zend_hash_update(&CG(active_class_entry)->default_properties, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); + break; + case T_STATIC: + zend_hash_update(&CG(active_class_entry)->static_members, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); + break; + case T_CONST: + zend_hash_update(&CG(active_class_entry)->constants, var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, &property, sizeof(zval *), NULL); + break; } } FREE_PNODE(var_name); @@ -1892,22 +1923,32 @@ void zend_do_end_new_object(znode *result, znode *new_token, znode *argument_lis } -void zend_do_fetch_constant(znode *result, znode *constant_name, int mode TSRMLS_DC) +void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode TSRMLS_DC) { switch (mode) { case ZEND_CT: - *result = *constant_name; + if (constant_container) { + do_fetch_class_name(NULL, constant_container, constant_name TSRMLS_CC); + *result = *constant_container; + } else { + *result = *constant_name; + } result->u.constant.type = IS_CONSTANT; break; - case ZEND_RT: { + case ZEND_RT: + { zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_FETCH_CONSTANT; opline->result.op_type = IS_TMP_VAR; opline->result.u.var = get_temporary_variable(CG(active_op_array)); - opline->op1 = *constant_name; + if (constant_container) { + opline->op1 = *constant_container; + } else { + SET_UNUSED(opline->op1); + } + opline->op2 = *constant_name; *result = opline->result; - SET_UNUSED(opline->op2); } break; } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 27266f4b7e..0c9b439dba 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -273,6 +273,7 @@ int zend_do_begin_function_call(znode *function_name TSRMLS_DC); void zend_do_begin_method_call(znode *object, znode *function_name TSRMLS_DC); void zend_do_begin_dynamic_function_call(znode *function_name TSRMLS_DC); void do_fetch_class(znode *result, znode *class_entry, znode *class_name TSRMLS_DC); +void do_fetch_class_name(znode *result, znode *class_entry, znode *class_name TSRMLS_DC); void zend_do_begin_class_member_function_call(znode *class_name, znode *function_name TSRMLS_DC); void zend_do_end_function_call(znode *function_name, znode *result, znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC); void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); @@ -316,7 +317,7 @@ void zend_do_pop_object(znode *object TSRMLS_DC); void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC); void zend_do_end_new_object(znode *result, znode *new_token, znode *argument_list TSRMLS_DC); -void zend_do_fetch_constant(znode *result, znode *constant_name, int mode TSRMLS_DC); +void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode TSRMLS_DC); void zend_do_shell_exec(znode *result, znode *cmd TSRMLS_DC); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 77f39bd0aa..cb6b569fce 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2043,12 +2043,25 @@ send_by_ref: } NEXT_OPCODE(); case ZEND_FETCH_CONSTANT: - if (!zend_get_constant(EX(opline)->op1.u.constant.value.str.val, EX(opline)->op1.u.constant.value.str.len, &EX(Ts)[EX(opline)->result.u.var].tmp_var TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - EX(opline)->op1.u.constant.value.str.val, - EX(opline)->op1.u.constant.value.str.val); - EX(Ts)[EX(opline)->result.u.var].tmp_var = EX(opline)->op1.u.constant; - zval_copy_ctor(&EX(Ts)[EX(opline)->result.u.var].tmp_var); + if (EX(opline)->op1.op_type == IS_UNUSED) { + if (!zend_get_constant(EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len, &EX(Ts)[EX(opline)->result.u.var].tmp_var TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", + EX(opline)->op2.u.constant.value.str.val, + EX(opline)->op2.u.constant.value.str.val); + EX(Ts)[EX(opline)->result.u.var].tmp_var = EX(opline)->op2.u.constant; + zval_copy_ctor(&EX(Ts)[EX(opline)->result.u.var].tmp_var); + } + } else { + zend_class_entry *ce = EX(Ts)[EX(opline)->op1.u.var].EA.class_entry; + zval **value; + + if (zend_hash_find(&ce->constants, EX(opline)->op2.u.constant.value.str.val, EX(opline)->op2.u.constant.value.str.len+1, (void **) &value) == SUCCESS) { + zval_update_constant(value, (void *) 1 TSRMLS_CC); + EX(Ts)[EX(opline)->result.u.var].tmp_var = **value; + zval_copy_ctor(&EX(Ts)[EX(opline)->result.u.var].tmp_var); + } else { + zend_error(E_ERROR, "Undefined constant. Improve this error message"); + } } NEXT_OPCODE(); case ZEND_INIT_ARRAY: diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 5cff595e15..a6790aa357 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -289,6 +289,7 @@ ZEND_API int zend_is_true(zval *op) return i_zend_is_true(op); } +#include "../TSRM/tsrm_strtok_r.h" ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) { @@ -304,19 +305,52 @@ ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC) refcount = p->refcount; - if (!zend_get_constant(p->value.str.val, p->value.str.len, &const_value TSRMLS_CC)) { - zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", - p->value.str.val, - p->value.str.val); - p->type = IS_STRING; - if (!inline_change) { - zval_copy_ctor(p); + if (strchr(p->value.str.val, ':')) { + char *cur, *temp; + char *last; + zend_class_entry *ce; + zval **value; + + last = tsrm_strtok_r(p->value.str.val, ":", &temp); + + if (zend_hash_find(EG(class_table), last, strlen(last)+1, &ce) == FAILURE) { + zend_error(E_ERROR, "Invalid class! Improve this error message"); } - } else { + + for(;;) { + cur = tsrm_strtok_r(NULL, ":", &temp); + if (!cur) { + break; + } + if (zend_hash_find(EG(class_table), last, strlen(last)+1, &ce) == FAILURE) { + zend_error(E_ERROR, "Invalid class! Improve this error message"); + } + last = cur; + } + if (zend_hash_find(&ce->constants, last, strlen(last)+1, (void **) &value) == FAILURE) { + zend_error(E_ERROR, "Invalid class! Improve this error message"); + } + const_value = **value; + zval_copy_ctor(&const_value); if (inline_change) { STR_FREE(p->value.str.val); } *p = const_value; + } else { + if (!zend_get_constant(p->value.str.val, p->value.str.len, &const_value TSRMLS_CC)) { + zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", + p->value.str.val, + p->value.str.val); + p->type = IS_STRING; + if (!inline_change) { + zval_copy_ctor(p); + } + } else { + if (inline_change) { + STR_FREE(p->value.str.val); + } + *p = const_value; + } } INIT_PZVAL(p); p->refcount = refcount; diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 31e2b997f6..6740f44111 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -387,6 +387,7 @@ class_statement_list: class_statement: class_variable_decleration ';' + | class_constant_decleration ';' | T_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 1, $3.op_type TSRMLS_CC); } '(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); } | T_OLD_FUNCTION { $1.u.opline_num = CG(zend_lineno); } is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 1, $3.op_type TSRMLS_CC); } @@ -411,6 +412,11 @@ class_decleration_type: | T_STATIC { $$.op_type = T_STATIC; } ; +class_constant_decleration: + | T_CONST ',' T_STRING '=' static_scalar { zend_do_declare_property(&$3, &$5, T_CONST TSRMLS_CC); } + | T_CONST T_STRING '=' static_scalar { zend_do_declare_property(&$2, &$4, T_CONST TSRMLS_CC); } +; + echo_expr_list: | echo_expr_list ',' expr { zend_do_echo(&$3 TSRMLS_CC); } | expr { zend_do_echo(&$1 TSRMLS_CC); } @@ -515,6 +521,11 @@ parse_class_entry: | T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } ; +parse_class_name_entry: + parse_class_name_entry T_STRING T_PAAMAYIM_NEKUDOTAYIM { do_fetch_class_name(&$$, &$1, &$2 TSRMLS_CC); } + | T_STRING T_PAAMAYIM_NEKUDOTAYIM { $$ = $1; } +; + new_class_entry: parse_class_entry static_or_variable_string { do_fetch_class(&$$, &$1, &$2 TSRMLS_CC); } | static_or_variable_string { do_fetch_class(&$$, NULL, &$1 TSRMLS_CC); } @@ -550,17 +561,18 @@ common_scalar: static_scalar: /* compile-time evaluated scalars */ common_scalar { $$ = $1; } - | T_STRING { zend_do_fetch_constant(&$$, &$1, ZEND_CT TSRMLS_CC); } + | T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT TSRMLS_CC); } | '+' static_scalar { $$ = $1; } | '-' static_scalar { zval minus_one; minus_one.type = IS_LONG; minus_one.value.lval = -1; mul_function(&$2.u.constant, &$2.u.constant, &minus_one TSRMLS_CC); $$ = $2; } | T_ARRAY '(' static_array_pair_list ')' { $$ = $3; $$.u.constant.type = IS_CONSTANT_ARRAY; } + | parse_class_name_entry T_STRING { zend_do_fetch_constant(&$$, &$1, &$2, ZEND_CT TSRMLS_CC); } ; scalar: - T_STRING { zend_do_fetch_constant(&$$, &$1, ZEND_RT TSRMLS_CC); } + T_STRING { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT TSRMLS_CC); } | T_STRING_VARNAME { $$ = $1; } - | parse_class_entry T_STRING + | parse_class_entry T_STRING { zend_do_fetch_constant(&$$, &$1, &$2, ZEND_RT TSRMLS_CC); } | common_scalar { $$ = $1; } | '"' encaps_list '"' { $$ = $2; } | '\'' encaps_list '\'' { $$ = $2; } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 6d16b719b3..9d9b924632 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -118,6 +118,7 @@ ZEND_API void destroy_zend_class(zend_class_entry *ce) zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->default_properties); zend_hash_destroy(&ce->static_members); + zend_hash_destroy(&ce->constants); zend_hash_destroy(&ce->class_table); break; case ZEND_INTERNAL_CLASS: @@ -126,6 +127,7 @@ ZEND_API void destroy_zend_class(zend_class_entry *ce) zend_hash_destroy(&ce->function_table); zend_hash_destroy(&ce->default_properties); zend_hash_destroy(&ce->static_members); + zend_hash_destroy(&ce->constants); zend_hash_destroy(&ce->class_table); break; }