- issues which need to be looked into but basically it seems to work.
- Example:
<?php
class foo
{
const hey = "hello";
}
print foo::hey;
?>
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;
HashTable default_properties;
HashTable class_table;
HashTable static_members;
+ HashTable constants;
zend_function_entry *builtin_functions;
union _zend_function *constructor;
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);
*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;
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)
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;
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;
/* 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 */
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);
}
-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;
}
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);
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);
}
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:
return i_zend_is_true(op);
}
+#include "../TSRM/tsrm_strtok_r.h"
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;
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); }
| 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); }
| 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); }
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; }
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:
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;
}