summaryrefslogtreecommitdiff
path: root/Zend/zend_compile.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_compile.c')
-rw-r--r--Zend/zend_compile.c2133
1 files changed, 278 insertions, 1855 deletions
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index a5a32298d5..91bfbfeebb 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -30,6 +30,7 @@
#include "zend_virtual_cwd.h"
#include "zend_multibyte.h"
#include "zend_language_scanner.h"
+#include "zend_inheritance.h"
#define CONSTANT_EX(op_array, op) \
(op_array)->literals[op]
@@ -76,29 +77,6 @@ ZEND_API zend_compiler_globals compiler_globals;
ZEND_API zend_executor_globals executor_globals;
#endif
-static zend_property_info *zend_duplicate_property_info(zend_property_info *property_info TSRMLS_DC) /* {{{ */
-{
- zend_property_info* new_property_info;
-
- new_property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
- memcpy(new_property_info, property_info, sizeof(zend_property_info));
- zend_string_addref(new_property_info->name);
- if (new_property_info->doc_comment) {
- zend_string_addref(new_property_info->doc_comment);
- }
- return new_property_info;
-}
-/* }}} */
-
-static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
-{
- zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
- memcpy(new_property_info, property_info, sizeof(zend_property_info));
- zend_string_addref(new_property_info->name);
- return new_property_info;
-}
-/* }}} */
-
static void zend_destroy_property_info(zval *zv) /* {{{ */
{
zend_property_info *property_info = Z_PTR_P(zv);
@@ -137,21 +115,33 @@ static zend_string *zend_build_runtime_definition_key(zend_string *name, unsigne
{
zend_string *result;
char char_pos_buf[32];
- size_t char_pos_len = zend_sprintf(char_pos_buf, "%p", lex_pos);
+ size_t filename_len, char_pos_len = zend_sprintf(char_pos_buf, "%p", lex_pos);
const char *filename;
if (CG(active_op_array)->filename) {
filename = CG(active_op_array)->filename->val;
+ filename_len = CG(active_op_array)->filename->len;
} else {
filename = "-";
+ filename_len = sizeof("-") - 1;
}
-
/* NULL, name length, filename length, last accepting char position length */
- result = zend_string_alloc(1 + name->len + strlen(filename) + char_pos_len, 0);
+ result = zend_string_alloc(1 + name->len + filename_len + char_pos_len, 0);
+ sprintf(result->val, "%c%s%s%s", '\0', name->val, filename, char_pos_buf);
+ return zend_new_interned_string(result TSRMLS_CC);
+}
+/* }}} */
- result->val[0] = '\0';
- sprintf(result->val + 1, "%s%s%s", name->val, filename, char_pos_buf);
- return result;
+static zend_bool zend_get_unqualified_name(const zend_string *name, const char **result, size_t *result_len) /* {{{ */
+{
+ const char *ns_separator = zend_memrchr(name->val, '\\', name->len);
+ if (ns_separator != NULL) {
+ *result = ns_separator + 1;
+ *result_len = name->val + name->len - *result;
+ return 1;
+ }
+
+ return 0;
}
/* }}} */
@@ -342,82 +332,63 @@ int zend_add_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) /* {{{ */
}
/* }}} */
-static int zend_add_func_name_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) /* {{{ */
+static inline int zend_add_literal_string(zend_op_array *op_array, zend_string **str TSRMLS_DC) /* {{{ */
{
int ret;
- zend_string *lc_name;
- zval c;
-
- if (op_array->last_literal > 0 &&
- &op_array->literals[op_array->last_literal - 1] == zv &&
- Z_CACHE_SLOT(op_array->literals[op_array->last_literal - 1]) == -1) {
- /* we already have function name as last literal (do nothing) */
- ret = op_array->last_literal - 1;
- } else {
- ret = zend_add_literal(op_array, zv TSRMLS_CC);
- }
+ zval zv;
+ ZVAL_STR(&zv, *str);
+ ret = zend_add_literal(op_array, &zv TSRMLS_CC);
+ *str = Z_STR(zv);
+ return ret;
+}
- lc_name = zend_string_alloc(Z_STRLEN_P(zv), 0);
- zend_str_tolower_copy(lc_name->val, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
- ZVAL_NEW_STR(&c, lc_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
+static int zend_add_func_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */
+{
+ /* Original name */
+ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC);
+
+ /* Lowercased name */
+ zend_string *lc_name = zend_string_alloc(name->len, 0);
+ zend_str_tolower_copy(lc_name->val, name->val, name->len);
+ zend_add_literal_string(op_array, &lc_name TSRMLS_CC);
return ret;
}
/* }}} */
-static int zend_add_ns_func_name_literal(zend_op_array *op_array, zval *zv TSRMLS_DC) /* {{{ */
+static int zend_add_ns_func_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */
{
- int ret;
- zend_string *lc_name;
- const char *ns_separator;
- int lc_len;
- zval c;
-
- if (op_array->last_literal > 0 &&
- &op_array->literals[op_array->last_literal - 1] == zv &&
- Z_CACHE_SLOT(op_array->literals[op_array->last_literal - 1]) == -1) {
- /* we already have function name as last literal (do nothing) */
- ret = op_array->last_literal - 1;
- } else {
- ret = zend_add_literal(op_array, zv TSRMLS_CC);
- }
+ const char *unqualified_name;
+ size_t unqualified_name_len;
- lc_name = zend_string_alloc(Z_STRLEN_P(zv), 0);
- zend_str_tolower_copy(lc_name->val, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
- ZVAL_NEW_STR(&c, lc_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
+ /* Original name */
+ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC);
- ns_separator = (const char*)zend_memrchr(Z_STRVAL_P(zv), '\\', Z_STRLEN_P(zv));
+ /* Lowercased name */
+ zend_string *lc_name = zend_string_alloc(name->len, 0);
+ zend_str_tolower_copy(lc_name->val, name->val, name->len);
+ zend_add_literal_string(op_array, &lc_name TSRMLS_CC);
- if (ns_separator != NULL) {
- ns_separator += 1;
- lc_len = Z_STRLEN_P(zv) - (ns_separator - Z_STRVAL_P(zv));
- lc_name = zend_string_alloc(lc_len, 0);
- zend_str_tolower_copy(lc_name->val, ns_separator, lc_len);
- ZVAL_NEW_STR(&c, lc_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
+ /* Lowercased unqualfied name */
+ if (zend_get_unqualified_name(name, &unqualified_name, &unqualified_name_len)) {
+ lc_name = zend_string_alloc(unqualified_name_len, 0);
+ zend_str_tolower_copy(lc_name->val, unqualified_name, unqualified_name_len);
+ zend_add_literal_string(op_array, &lc_name TSRMLS_CC);
}
return ret;
}
/* }}} */
-static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */ {
- int ret;
- zend_string *lc_name;
-
- zval zv;
- ZVAL_STR(&zv, name);
-
- ret = zend_add_literal(op_array, &zv TSRMLS_CC);
- name = Z_STR(zv); /* Load new name string in case it was interned */
+static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *name TSRMLS_DC) /* {{{ */
+{
+ /* Original name */
+ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC);
- lc_name = zend_string_alloc(name->len, 0);
+ /* Lowercased name */
+ zend_string *lc_name = zend_string_alloc(name->len, 0);
zend_str_tolower_copy(lc_name->val, name->val, name->len);
-
- ZVAL_NEW_STR(&zv, lc_name);
- zend_add_literal(CG(active_op_array), &zv TSRMLS_CC);
+ zend_add_literal_string(op_array, &lc_name TSRMLS_CC);
zend_alloc_cache_slot(ret TSRMLS_CC);
@@ -425,72 +396,44 @@ static int zend_add_class_name_literal(zend_op_array *op_array, zend_string *nam
}
/* }}} */
-static int zend_add_const_name_literal(zend_op_array *op_array, zval *zv, int unqualified TSRMLS_DC) /* {{{ */
+static int zend_add_const_name_literal(zend_op_array *op_array, zend_string *name, zend_bool unqualified TSRMLS_DC) /* {{{ */
{
- int ret;
- char *name;
zend_string *tmp_name;
- const char *ns_separator;
- int name_len, ns_len;
- zval c;
-
- if (op_array->last_literal > 0 &&
- &op_array->literals[op_array->last_literal - 1] == zv &&
- Z_CACHE_SLOT(op_array->literals[op_array->last_literal - 1]) == -1) {
- /* we already have function name as last literal (do nothing) */
- ret = op_array->last_literal - 1;
- } else {
- ret = zend_add_literal(op_array, zv TSRMLS_CC);
- }
- /* skip leading '\\' */
- if (Z_STRVAL_P(zv)[0] == '\\') {
- name_len = Z_STRLEN_P(zv) - 1;
- name = Z_STRVAL_P(zv) + 1;
- } else {
- name_len = Z_STRLEN_P(zv);
- name = Z_STRVAL_P(zv);
- }
- ns_separator = zend_memrchr(name, '\\', name_len);
- if (ns_separator) {
- ns_len = ns_separator - name;
- } else {
- ns_len = 0;
- }
+ int ret = zend_add_literal_string(op_array, &name TSRMLS_CC);
+
+ size_t ns_len = 0, after_ns_len = name->len;
+ const char *after_ns = zend_memrchr(name->val, '\\', name->len);
+ if (after_ns) {
+ after_ns += 1;
+ ns_len = after_ns - name->val - 1;
+ after_ns_len = name->len - ns_len - 1;
- if (ns_len) {
/* lowercased namespace name & original constant name */
- tmp_name = zend_string_init(name, name_len, 0);
+ tmp_name = zend_string_init(name->val, name->len, 0);
zend_str_tolower(tmp_name->val, ns_len);
- ZVAL_NEW_STR(&c, tmp_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
+ zend_add_literal_string(op_array, &tmp_name TSRMLS_CC);
/* lowercased namespace name & lowercased constant name */
- tmp_name = zend_string_alloc(name_len, 0);
- zend_str_tolower_copy(tmp_name->val, name, name_len);
- ZVAL_NEW_STR(&c, tmp_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
- }
+ tmp_name = zend_string_alloc(name->len, 0);
+ zend_str_tolower_copy(tmp_name->val, name->val, name->len);
+ zend_add_literal_string(op_array, &tmp_name TSRMLS_CC);
- if (ns_len) {
if (!unqualified) {
return ret;
}
- ns_len++;
- name += ns_len;
- name_len -= ns_len;
+ } else {
+ after_ns = name->val;
}
- /* original constant name */
- tmp_name = zend_string_init(name, name_len, 0);
- ZVAL_NEW_STR(&c, tmp_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
+ /* original unqualified constant name */
+ tmp_name = zend_string_init(after_ns, after_ns_len, 0);
+ zend_add_literal_string(op_array, &tmp_name TSRMLS_CC);
- /* lowercased constant name */
- tmp_name = zend_string_alloc(name_len, 0);
- zend_str_tolower_copy(tmp_name->val, name, name_len);
- ZVAL_NEW_STR(&c, tmp_name);
- zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
+ /* lowercased unqualified constant name */
+ tmp_name = zend_string_alloc(after_ns_len, 0);
+ zend_str_tolower_copy(tmp_name->val, after_ns, after_ns_len);
+ zend_add_literal_string(op_array, &tmp_name TSRMLS_CC);
return ret;
}
@@ -559,8 +502,7 @@ void zend_do_free(znode *op1 TSRMLS_DC) /* {{{ */
&& opline->result.var == op1->u.op.var) {
if (opline->opcode == ZEND_FETCH_R ||
opline->opcode == ZEND_FETCH_DIM_R ||
- opline->opcode == ZEND_FETCH_OBJ_R ||
- opline->opcode == ZEND_QM_ASSIGN_VAR) {
+ opline->opcode == ZEND_FETCH_OBJ_R) {
/* It's very rare and useless case. It's better to use
additional FREE opcode and simplify the FETCH handlers
their selves */
@@ -653,12 +595,16 @@ zend_string *zend_prefix_with_ns(zend_string *name TSRMLS_DC) {
}
}
-void *zend_hash_find_ptr_lc(HashTable *ht, char *str, size_t len) {
+void *zend_hash_find_ptr_lc(HashTable *ht, const char *str, size_t len) {
void *result;
- zend_string *lcname = zend_string_alloc(len, 0);
+ zend_string *lcname;
+ ALLOCA_FLAG(use_heap);
+
+ STR_ALLOCA_ALLOC(lcname, len, use_heap);
zend_str_tolower_copy(lcname->val, str, len);
result = zend_hash_find_ptr(ht, lcname);
- zend_string_free(lcname);
+ STR_ALLOCA_FREE(lcname, use_heap);
+
return result;
}
@@ -882,7 +828,7 @@ static int generate_free_loop_var(znode *var TSRMLS_DC) /* {{{ */
{
zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
- opline->opcode = var->op_type == IS_TMP_VAR ? ZEND_FREE : ZEND_SWITCH_FREE;
+ opline->opcode = ZEND_FREE;
SET_NODE(opline->op1, var);
SET_UNUSED(opline->op2);
}
@@ -932,1527 +878,6 @@ ZEND_API void function_add_ref(zend_function *function) /* {{{ */
}
/* }}} */
-static void do_inherit_parent_constructor(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
- zend_function *function, *new_function;
-
- if (!ce->parent) {
- return;
- }
-
- /* You cannot change create_object */
- ce->create_object = ce->parent->create_object;
-
- /* Inherit special functions if needed */
- if (!ce->get_iterator) {
- ce->get_iterator = ce->parent->get_iterator;
- }
- if (!ce->iterator_funcs.funcs) {
- ce->iterator_funcs.funcs = ce->parent->iterator_funcs.funcs;
- }
- if (!ce->__get) {
- ce->__get = ce->parent->__get;
- }
- if (!ce->__set) {
- ce->__set = ce->parent->__set;
- }
- if (!ce->__unset) {
- ce->__unset = ce->parent->__unset;
- }
- if (!ce->__isset) {
- ce->__isset = ce->parent->__isset;
- }
- if (!ce->__call) {
- ce->__call = ce->parent->__call;
- }
- if (!ce->__callstatic) {
- ce->__callstatic = ce->parent->__callstatic;
- }
- if (!ce->__tostring) {
- ce->__tostring = ce->parent->__tostring;
- }
- if (!ce->clone) {
- ce->clone = ce->parent->clone;
- }
- if(!ce->serialize) {
- ce->serialize = ce->parent->serialize;
- }
- if(!ce->unserialize) {
- ce->unserialize = ce->parent->unserialize;
- }
- if (!ce->destructor) {
- ce->destructor = ce->parent->destructor;
- }
- if (!ce->__debugInfo) {
- ce->__debugInfo = ce->parent->__debugInfo;
- }
- if (ce->constructor) {
- if (ce->parent->constructor && ce->parent->constructor->common.fn_flags & ZEND_ACC_FINAL) {
- zend_error(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
- ce->parent->name->val, ce->parent->constructor->common.function_name->val,
- ce->name->val, ce->constructor->common.function_name->val
- );
- }
- return;
- }
-
- if ((function = zend_hash_str_find_ptr(&ce->parent->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1)) != NULL) {
- /* inherit parent's constructor */
- if (function->type == ZEND_INTERNAL_FUNCTION) {
- new_function = pemalloc(sizeof(zend_internal_function), 1);
- memcpy(new_function, function, sizeof(zend_internal_function));
- } else {
- new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
- memcpy(new_function, function, sizeof(zend_op_array));
- }
- zend_hash_str_update_ptr(&ce->function_table, ZEND_CONSTRUCTOR_FUNC_NAME, sizeof(ZEND_CONSTRUCTOR_FUNC_NAME)-1, new_function);
- function_add_ref(new_function);
- } else {
- /* Don't inherit the old style constructor if we already have the new style constructor */
- zend_string *lc_class_name;
- zend_string *lc_parent_class_name;
-
- lc_class_name = zend_string_alloc(ce->name->len, 0);
- zend_str_tolower_copy(lc_class_name->val, ce->name->val, ce->name->len);
- if (!zend_hash_exists(&ce->function_table, lc_class_name)) {
- lc_parent_class_name = zend_string_alloc(ce->parent->name->len, 0);
- zend_str_tolower_copy(lc_parent_class_name->val, ce->parent->name->val, ce->parent->name->len);
- if (!zend_hash_exists(&ce->function_table, lc_parent_class_name) &&
- (function = zend_hash_find_ptr(&ce->parent->function_table, lc_parent_class_name)) != NULL) {
- if (function->common.fn_flags & ZEND_ACC_CTOR) {
- /* inherit parent's constructor */
- new_function = pemalloc(sizeof(zend_function), function->type == ZEND_INTERNAL_FUNCTION);
- memcpy(new_function, function, sizeof(zend_function));
- zend_hash_update_ptr(&ce->function_table, lc_parent_class_name, new_function);
- function_add_ref(new_function);
- }
- }
- zend_string_release(lc_parent_class_name);
- }
- zend_string_free(lc_class_name);
- }
- ce->constructor = ce->parent->constructor;
-}
-/* }}} */
-
-char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
-{
- if (fn_flags & ZEND_ACC_PRIVATE) {
- return "private";
- }
- if (fn_flags & ZEND_ACC_PROTECTED) {
- return "protected";
- }
- if (fn_flags & ZEND_ACC_PUBLIC) {
- return "public";
- }
- return "";
-}
-/* }}} */
-
-static zend_function *do_inherit_method(zend_function *old_function TSRMLS_DC) /* {{{ */
-{
- zend_function *new_function;
-
- if (old_function->type == ZEND_INTERNAL_FUNCTION) {
- new_function = pemalloc(sizeof(zend_internal_function), 1);
- memcpy(new_function, old_function, sizeof(zend_internal_function));
- } else {
- new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
- memcpy(new_function, old_function, sizeof(zend_op_array));
- }
- /* The class entry of the derived function intentionally remains the same
- * as that of the parent class. That allows us to know in which context
- * we're running, and handle private method calls properly.
- */
- function_add_ref(new_function);
- return new_function;
-}
-/* }}} */
-
-static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
-{
- uint32_t i, num_args;
-
- /* If it's a user function then arg_info == NULL means we don't have any parameters but
- * we still need to do the arg number checks. We are only willing to ignore this for internal
- * functions because extensions don't always define arg_info.
- */
- if (!proto || (!proto->common.arg_info && proto->common.type != ZEND_USER_FUNCTION)) {
- return 1;
- }
-
- /* Checks for constructors only if they are declared in an interface,
- * or explicitly marked as abstract
- */
- if ((fe->common.fn_flags & ZEND_ACC_CTOR)
- && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
- && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)) {
- return 1;
- }
-
- /* If both methods are private do not enforce a signature */
- if ((fe->common.fn_flags & ZEND_ACC_PRIVATE) && (proto->common.fn_flags & ZEND_ACC_PRIVATE)) {
- return 1;
- }
-
- /* check number of arguments */
- if (proto->common.required_num_args < fe->common.required_num_args
- || proto->common.num_args > fe->common.num_args) {
- return 0;
- }
-
- /* by-ref constraints on return values are covariant */
- if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
- && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
- return 0;
- }
-
- if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
- && !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
- return 0;
- }
-
- /* For variadic functions any additional (optional) arguments that were added must be
- * checked against the signature of the variadic argument, so in this case we have to
- * go through all the parameters of the function and not just those present in the
- * prototype. */
- num_args = proto->common.num_args;
- if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
- && fe->common.num_args > proto->common.num_args) {
- num_args = fe->common.num_args;
- }
-
- for (i = 0; i < num_args; i++) {
- zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
-
- zend_arg_info *proto_arg_info;
- if (i < proto->common.num_args) {
- proto_arg_info = &proto->common.arg_info[i];
- } else {
- proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
- }
-
- if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
- /* Only one has a type hint and the other one doesn't */
- return 0;
- }
-
- if (fe_arg_info->class_name) {
- zend_string *fe_class_name, *proto_class_name;
-
- if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
- fe_class_name = zend_string_copy(proto->common.scope->name);
- } else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
- fe_class_name = zend_string_copy(fe->common.scope->name);
- } else {
- fe_class_name = zend_string_init(
- fe_arg_info->class_name,
- fe_arg_info->class_name_len, 0);
- }
-
- if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
- proto_class_name = zend_string_copy(proto->common.scope->parent->name);
- } else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
- proto_class_name = zend_string_copy(proto->common.scope->name);
- } else {
- proto_class_name = zend_string_init(
- proto_arg_info->class_name,
- proto_arg_info->class_name_len, 0);
- }
-
- if (strcasecmp(fe_class_name->val, proto_class_name->val)!=0) {
- const char *colon;
-
- if (fe->common.type != ZEND_USER_FUNCTION) {
- zend_string_release(proto_class_name);
- zend_string_release(fe_class_name);
- return 0;
- } else if (strchr(proto_class_name->val, '\\') != NULL ||
- (colon = zend_memrchr(fe_class_name->val, '\\', fe_class_name->len)) == NULL ||
- strcasecmp(colon+1, proto_class_name->val) != 0) {
- zend_class_entry *fe_ce, *proto_ce;
-
- fe_ce = zend_lookup_class(fe_class_name TSRMLS_CC);
- proto_ce = zend_lookup_class(proto_class_name TSRMLS_CC);
-
- /* Check for class alias */
- if (!fe_ce || !proto_ce ||
- fe_ce->type == ZEND_INTERNAL_CLASS ||
- proto_ce->type == ZEND_INTERNAL_CLASS ||
- fe_ce != proto_ce) {
- zend_string_release(proto_class_name);
- zend_string_release(fe_class_name);
- return 0;
- }
- }
- }
- zend_string_release(proto_class_name);
- zend_string_release(fe_class_name);
- }
- if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
- /* Incompatible type hint */
- return 0;
- }
-
- /* by-ref constraints on arguments are invariant */
- if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
- return 0;
- }
- }
-
- return 1;
-}
-/* }}} */
-
-#define REALLOC_BUF_IF_EXCEED(buf, offset, length, size) \
- if (UNEXPECTED(offset - buf + size >= length)) { \
- length += size + 1; \
- buf = erealloc(buf, length); \
- }
-
-static char *zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
-{
- char *offset, *buf;
- uint32_t length = 1024;
-
- offset = buf = (char *)emalloc(length * sizeof(char));
- if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
- *(offset++) = '&';
- *(offset++) = ' ';
- }
-
- if (fptr->common.scope) {
- memcpy(offset, fptr->common.scope->name->val, fptr->common.scope->name->len);
- offset += fptr->common.scope->name->len;
- *(offset++) = ':';
- *(offset++) = ':';
- }
-
- {
- size_t name_len = fptr->common.function_name->len;
- REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
- memcpy(offset, fptr->common.function_name->val, name_len);
- offset += name_len;
- }
-
- *(offset++) = '(';
- if (fptr->common.arg_info) {
- uint32_t i, required;
- zend_arg_info *arg_info = fptr->common.arg_info;
-
- required = fptr->common.required_num_args;
- for (i = 0; i < fptr->common.num_args;) {
- if (arg_info->class_name) {
- const char *class_name;
- uint32_t class_name_len;
- if (!strcasecmp(arg_info->class_name, "self") && fptr->common.scope ) {
- class_name = fptr->common.scope->name->val;
- class_name_len = fptr->common.scope->name->len;
- } else if (!strcasecmp(arg_info->class_name, "parent") && fptr->common.scope->parent) {
- class_name = fptr->common.scope->parent->name->val;
- class_name_len = fptr->common.scope->parent->name->len;
- } else {
- class_name = arg_info->class_name;
- class_name_len = arg_info->class_name_len;
- }
- REALLOC_BUF_IF_EXCEED(buf, offset, length, class_name_len);
- memcpy(offset, class_name, class_name_len);
- offset += class_name_len;
- *(offset++) = ' ';
- } else if (arg_info->type_hint) {
- uint32_t type_name_len;
- char *type_name = zend_get_type_by_const(arg_info->type_hint);
- type_name_len = strlen(type_name);
- REALLOC_BUF_IF_EXCEED(buf, offset, length, type_name_len);
- memcpy(offset, type_name, type_name_len);
- offset += type_name_len;
- *(offset++) = ' ';
- }
-
- if (arg_info->pass_by_reference) {
- *(offset++) = '&';
- }
-
- if (arg_info->is_variadic) {
- *(offset++) = '.';
- *(offset++) = '.';
- *(offset++) = '.';
- }
-
- *(offset++) = '$';
-
- if (arg_info->name) {
- REALLOC_BUF_IF_EXCEED(buf, offset, length, arg_info->name_len);
- memcpy(offset, arg_info->name, arg_info->name_len);
- offset += arg_info->name_len;
- } else {
- uint32_t idx = i;
- memcpy(offset, "param", 5);
- offset += 5;
- do {
- *(offset++) = (char) (idx % 10) + '0';
- idx /= 10;
- } while (idx > 0);
- }
- if (i >= required && !arg_info->is_variadic) {
- *(offset++) = ' ';
- *(offset++) = '=';
- *(offset++) = ' ';
- if (fptr->type == ZEND_USER_FUNCTION) {
- zend_op *precv = NULL;
- {
- uint32_t idx = i;
- zend_op *op = ((zend_op_array *)fptr)->opcodes;
- zend_op *end = op + ((zend_op_array *)fptr)->last;
-
- ++idx;
- while (op < end) {
- if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
- && op->op1.num == (zend_ulong)idx)
- {
- precv = op;
- }
- ++op;
- }
- }
- if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
- zval *zv = precv->op2.zv;
-
- if (Z_TYPE_P(zv) == IS_CONSTANT) {
- REALLOC_BUF_IF_EXCEED(buf, offset, length, Z_STRLEN_P(zv));
- memcpy(offset, Z_STRVAL_P(zv), Z_STRLEN_P(zv));
- offset += Z_STRLEN_P(zv);
- } else if (Z_TYPE_P(zv) == IS_FALSE) {
- memcpy(offset, "false", 5);
- offset += 5;
- } else if (Z_TYPE_P(zv) == IS_TRUE) {
- memcpy(offset, "true", 4);
- offset += 4;
- } else if (Z_TYPE_P(zv) == IS_NULL) {
- memcpy(offset, "NULL", 4);
- offset += 4;
- } else if (Z_TYPE_P(zv) == IS_STRING) {
- *(offset++) = '\'';
- REALLOC_BUF_IF_EXCEED(buf, offset, length, MIN(Z_STRLEN_P(zv), 10));
- memcpy(offset, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
- offset += MIN(Z_STRLEN_P(zv), 10);
- if (Z_STRLEN_P(zv) > 10) {
- *(offset++) = '.';
- *(offset++) = '.';
- *(offset++) = '.';
- }
- *(offset++) = '\'';
- } else if (Z_TYPE_P(zv) == IS_ARRAY) {
- memcpy(offset, "Array", 5);
- offset += 5;
- } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
- memcpy(offset, "<expression>", 12);
- offset += 12;
- } else {
- zend_string *str = zval_get_string(zv);
- REALLOC_BUF_IF_EXCEED(buf, offset, length, str->len);
- memcpy(offset, str->val, str->len);
- offset += str->len;
- zend_string_release(str);
- }
- }
- } else {
- memcpy(offset, "NULL", 4);
- offset += 4;
- }
- }
-
- if (++i < fptr->common.num_args) {
- *(offset++) = ',';
- *(offset++) = ' ';
- }
- arg_info++;
- REALLOC_BUF_IF_EXCEED(buf, offset, length, 32);
- }
- }
- *(offset++) = ')';
- *offset = '\0';
-
- return buf;
-}
-/* }}} */
-
-static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
-{
- uint32_t child_flags;
- uint32_t parent_flags = parent->common.fn_flags;
-
- if ((parent->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
- && parent->common.fn_flags & ZEND_ACC_ABSTRACT
- && parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
- && child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
- parent->common.scope->name->val,
- child->common.function_name->val,
- child->common.prototype ? child->common.prototype->common.scope->name->val : child->common.scope->name->val);
- }
-
- if (parent_flags & ZEND_ACC_FINAL) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot override final method %s::%s()", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val);
- }
-
- child_flags = child->common.fn_flags;
- /* You cannot change from static to non static and vice versa.
- */
- if ((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC)) {
- if (child->common.fn_flags & ZEND_ACC_STATIC) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non static method %s::%s() static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
- } else {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot make static method %s::%s() non static in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
- }
- }
-
- /* Disallow making an inherited method abstract. */
- if ((child_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_ABSTRACT)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot make non abstract method %s::%s() abstract in class %s", ZEND_FN_SCOPE_NAME(parent), child->common.function_name->val, ZEND_FN_SCOPE_NAME(child));
- }
-
- if (parent_flags & ZEND_ACC_CHANGED) {
- child->common.fn_flags |= ZEND_ACC_CHANGED;
- } else {
- /* Prevent derived classes from restricting access that was available in parent classes
- */
- if ((child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s() must be %s (as in class %s)%s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
- } else if (((child_flags & ZEND_ACC_PPP_MASK) < (parent_flags & ZEND_ACC_PPP_MASK))
- && ((parent_flags & ZEND_ACC_PPP_MASK) & ZEND_ACC_PRIVATE)) {
- child->common.fn_flags |= ZEND_ACC_CHANGED;
- }
- }
-
- if (parent_flags & ZEND_ACC_PRIVATE) {
- child->common.prototype = NULL;
- } else if (parent_flags & ZEND_ACC_ABSTRACT) {
- child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
- child->common.prototype = parent;
- } else if (!(parent->common.fn_flags & ZEND_ACC_CTOR) || (parent->common.prototype && (parent->common.prototype->common.scope->ce_flags & ZEND_ACC_INTERFACE))) {
- /* ctors only have a prototype if it comes from an interface */
- child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;
- }
-
- if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
- if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, zend_get_function_declaration(child->common.prototype TSRMLS_CC));
- }
- } else if (EG(error_reporting) & E_STRICT || Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
- if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
- char *method_prototype = zend_get_function_declaration(parent TSRMLS_CC);
- zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name->val, method_prototype);
- efree(method_prototype);
- }
- }
-}
-/* }}} */
-
-static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_function *parent, zend_string *key, zend_class_entry *child_ce) /* {{{ */
-{
- uint32_t parent_flags = parent->common.fn_flags;
- zend_function *child;
- TSRMLS_FETCH();
-
- if ((child = zend_hash_find_ptr(child_function_table, key)) == NULL) {
- if (parent_flags & (ZEND_ACC_ABSTRACT)) {
- child_ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
- }
- return 1; /* method doesn't exist in child, copy from parent */
- }
-
- do_inheritance_check_on_method(child, parent TSRMLS_CC);
-
- return 0;
-}
-/* }}} */
-
-static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_property_info *parent_info, zend_string *key, zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
- zend_property_info *child_info;
- zend_class_entry *parent_ce = ce->parent;
-
- if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_SHADOW)) {
- if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
- child_info->flags |= ZEND_ACC_CHANGED;
- } else {
- if(ce->type & ZEND_INTERNAL_CLASS) {
- child_info = zend_duplicate_property_info_internal(parent_info);
- } else {
- child_info = zend_duplicate_property_info(parent_info TSRMLS_CC);
- }
- zend_hash_update_ptr(&ce->properties_info, key, child_info);
- child_info->flags &= ~ZEND_ACC_PRIVATE; /* it's not private anymore */
- child_info->flags |= ZEND_ACC_SHADOW; /* but it's a shadow of private */
- }
- return 0; /* don't copy access information to child */
- }
-
- if ((child_info = zend_hash_find_ptr(&ce->properties_info, key)) != NULL) {
- if ((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
- (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name->val, key->val,
- (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name->val, key->val);
-
- }
-
- if(parent_info->flags & ZEND_ACC_CHANGED) {
- child_info->flags |= ZEND_ACC_CHANGED;
- }
-
- if ((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ce->name->val, key->val, zend_visibility_string(parent_info->flags), parent_ce->name->val, (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
- } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
- zval_ptr_dtor(&(ce->default_properties_table[parent_info->offset]));
- ce->default_properties_table[parent_info->offset] = ce->default_properties_table[child_info->offset];
- ZVAL_UNDEF(&ce->default_properties_table[child_info->offset]);
- child_info->offset = parent_info->offset;
- }
- return 0; /* Don't copy from parent */
- } else {
- return 1; /* Copy from parent */
- }
-}
-/* }}} */
-
-static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
- if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce TSRMLS_CC) == FAILURE) {
- zend_error(E_CORE_ERROR, "Class %s could not implement interface %s", ce->name->val, iface->name->val);
- }
- if (ce == iface) {
- zend_error(E_ERROR, "Interface %s cannot implement itself", ce->name->val);
- }
-}
-/* }}} */
-
-ZEND_API void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
- /* expects interface to be contained in ce's interface list already */
- uint32_t i, ce_num, if_num = iface->num_interfaces;
- zend_class_entry *entry;
-
- if (if_num==0) {
- return;
- }
- ce_num = ce->num_interfaces;
-
- if (ce->type == ZEND_INTERNAL_CLASS) {
- ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
- } else {
- ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
- }
-
- /* Inherit the interfaces, only if they're not already inherited by the class */
- while (if_num--) {
- entry = iface->interfaces[if_num];
- for (i = 0; i < ce_num; i++) {
- if (ce->interfaces[i] == entry) {
- break;
- }
- }
- if (i == ce_num) {
- ce->interfaces[ce->num_interfaces++] = entry;
- }
- }
-
- /* and now call the implementing handlers */
- while (ce_num < ce->num_interfaces) {
- do_implement_interface(ce, ce->interfaces[ce_num++] TSRMLS_CC);
- }
-}
-/* }}} */
-
-#ifdef ZTS
-# define zval_property_ctor(parent_ce, ce) \
- (((parent_ce)->type != (ce)->type) ? ZVAL_COPY_CTOR : zval_add_ref)
-#else
-# define zval_property_ctor(parent_ce, ce) \
- zval_add_ref
-#endif
-
-static void do_inherit_class_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
-{
- if (!Z_ISREF_P(zv)) {
- if (parent_ce->type == ZEND_INTERNAL_CLASS) {
- ZVAL_NEW_PERSISTENT_REF(zv, zv);
- } else {
- ZVAL_NEW_REF(zv, zv);
- }
- }
- if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- if (zend_hash_add(&ce->constants_table, name, zv)) {
- Z_ADDREF_P(zv);
- }
-}
-/* }}} */
-
-ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent_ce TSRMLS_DC) /* {{{ */
-{
- zend_property_info *property_info;
- zend_function *func;
- zend_string *key;
- zval *zv;
-
- if ((ce->ce_flags & ZEND_ACC_INTERFACE)
- && !(parent_ce->ce_flags & ZEND_ACC_INTERFACE)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ce->name->val, parent_ce->name->val);
- }
- if (parent_ce->ce_flags & ZEND_ACC_FINAL_CLASS) {
- zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ce->name->val, parent_ce->name->val);
- }
-
- ce->parent = parent_ce;
- /* Copy serialize/unserialize callbacks */
- if (!ce->serialize) {
- ce->serialize = parent_ce->serialize;
- }
- if (!ce->unserialize) {
- ce->unserialize = parent_ce->unserialize;
- }
-
- /* Inherit interfaces */
- zend_do_inherit_interfaces(ce, parent_ce TSRMLS_CC);
-
- /* Inherit properties */
- if (parent_ce->default_properties_count) {
- int i = ce->default_properties_count + parent_ce->default_properties_count;
-
- ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
- if (ce->default_properties_count) {
- while (i-- > parent_ce->default_properties_count) {
- ce->default_properties_table[i] = ce->default_properties_table[i - parent_ce->default_properties_count];
- }
- }
- for (i = 0; i < parent_ce->default_properties_count; i++) {
-#ifdef ZTS
- if (parent_ce->type != ce->type) {
- ZVAL_DUP(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
- if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- continue;
- }
-#endif
-
- ZVAL_COPY(&ce->default_properties_table[i], &parent_ce->default_properties_table[i]);
- if (Z_OPT_CONSTANT(ce->default_properties_table[i])) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- }
- ce->default_properties_count += parent_ce->default_properties_count;
- }
-
- if (parent_ce->type != ce->type) {
- /* User class extends internal class */
- zend_update_class_constants(parent_ce TSRMLS_CC);
- if (parent_ce->default_static_members_count) {
- int i = ce->default_static_members_count + parent_ce->default_static_members_count;
-
- ce->default_static_members_table = erealloc(ce->default_static_members_table, sizeof(zval) * i);
- if (ce->default_static_members_count) {
- while (i-- > parent_ce->default_static_members_count) {
- ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
- }
- }
- for (i = 0; i < parent_ce->default_static_members_count; i++) {
- ZVAL_MAKE_REF(&CE_STATIC_MEMBERS(parent_ce)[i]);
- ce->default_static_members_table[i] = CE_STATIC_MEMBERS(parent_ce)[i];
- Z_ADDREF(ce->default_static_members_table[i]);
- if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- }
- ce->default_static_members_count += parent_ce->default_static_members_count;
- ce->static_members_table = ce->default_static_members_table;
- }
- } else {
- if (parent_ce->default_static_members_count) {
- int i = ce->default_static_members_count + parent_ce->default_static_members_count;
-
- ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * i, ce->type == ZEND_INTERNAL_CLASS);
- if (ce->default_static_members_count) {
- while (i-- > parent_ce->default_static_members_count) {
- ce->default_static_members_table[i] = ce->default_static_members_table[i - parent_ce->default_static_members_count];
- }
- }
- for (i = 0; i < parent_ce->default_static_members_count; i++) {
- ZVAL_MAKE_REF(&parent_ce->default_static_members_table[i]);
- ce->default_static_members_table[i] = parent_ce->default_static_members_table[i];
- Z_ADDREF(ce->default_static_members_table[i]);
- if (Z_CONSTANT_P(Z_REFVAL(ce->default_static_members_table[i]))) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- }
- ce->default_static_members_count += parent_ce->default_static_members_count;
- if (ce->type == ZEND_USER_CLASS) {
- ce->static_members_table = ce->default_static_members_table;
- }
- }
- }
-
- ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
- if (property_info->ce == ce) {
- if (property_info->flags & ZEND_ACC_STATIC) {
- property_info->offset += parent_ce->default_static_members_count;
- } else {
- property_info->offset += parent_ce->default_properties_count;
- }
- }
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
- if (do_inherit_property_access_check(&ce->properties_info, property_info, key, ce TSRMLS_CC)) {
- if (ce->type & ZEND_INTERNAL_CLASS) {
- property_info = zend_duplicate_property_info_internal(property_info);
- } else {
- property_info = zend_duplicate_property_info(property_info TSRMLS_CC);
- }
- zend_hash_add_new_ptr(&ce->properties_info, key, property_info);
- }
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_VAL(&parent_ce->constants_table, key, zv) {
- do_inherit_class_constant(key, zv, ce, parent_ce TSRMLS_CC);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
- if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
- zend_function *new_func = do_inherit_method(func TSRMLS_CC);
- zend_hash_add_new_ptr(&ce->function_table, key, new_func);
- }
- } ZEND_HASH_FOREACH_END();
-
- do_inherit_parent_constructor(ce TSRMLS_CC);
-
- if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS && ce->type == ZEND_INTERNAL_CLASS) {
- ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
- } else if (!(ce->ce_flags & (ZEND_ACC_IMPLEMENT_INTERFACES|ZEND_ACC_IMPLEMENT_TRAITS))) {
- /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */
- zend_verify_abstract_class(ce TSRMLS_CC);
- }
- ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS;
-}
-/* }}} */
-
-static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zval *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
-{
- zval *old_constant;
-
- if ((old_constant = zend_hash_find(child_constants_table, name)) != NULL) {
- if (!Z_ISREF_P(old_constant) ||
- !Z_ISREF_P(parent_constant) ||
- Z_REFVAL_P(old_constant) != Z_REFVAL_P(parent_constant)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", name->val, iface->name->val);
- }
- return 0;
- }
- return 1;
-}
-/* }}} */
-
-static void do_inherit_iface_constant(zend_string *name, zval *zv, zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
- if (do_inherit_constant_check(&ce->constants_table, zv, name, iface)) {
- ZVAL_MAKE_REF(zv);
- Z_ADDREF_P(zv);
- if (Z_CONSTANT_P(Z_REFVAL_P(zv))) {
- ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
- }
- zend_hash_update(&ce->constants_table, name, zv);
- }
-}
-/* }}} */
-
-ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) /* {{{ */
-{
- uint32_t i, ignore = 0;
- uint32_t current_iface_num = ce->num_interfaces;
- uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
- zend_function *func;
- zend_string *key;
- zval *zv;
-
- for (i = 0; i < ce->num_interfaces; i++) {
- if (ce->interfaces[i] == NULL) {
- memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
- i--;
- } else if (ce->interfaces[i] == iface) {
- if (i < parent_iface_num) {
- ignore = 1;
- } else {
- zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name->val, iface->name->val);
- }
- }
- }
- if (ignore) {
- /* Check for attempt to redeclare interface constants */
- ZEND_HASH_FOREACH_STR_KEY_VAL(&ce->constants_table, key, zv) {
- do_inherit_constant_check(&iface->constants_table, zv, key, iface);
- } ZEND_HASH_FOREACH_END();
- } else {
- if (ce->num_interfaces >= current_iface_num) {
- if (ce->type == ZEND_INTERNAL_CLASS) {
- ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
- } else {
- ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
- }
- }
- ce->interfaces[ce->num_interfaces++] = iface;
-
- ZEND_HASH_FOREACH_STR_KEY_VAL(&iface->constants_table, key, zv) {
- do_inherit_iface_constant(key, zv, ce, iface TSRMLS_CC);
- } ZEND_HASH_FOREACH_END();
-
- ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
- if (do_inherit_method_check(&ce->function_table, func, key, ce)) {
- zend_function *new_func = do_inherit_method(func TSRMLS_CC);
- zend_hash_add_new_ptr(&ce->function_table, key, new_func);
- }
- } ZEND_HASH_FOREACH_END();
-
- do_implement_interface(ce, iface TSRMLS_CC);
- zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
- }
-}
-/* }}} */
-
-ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
-{
- uint32_t i, ignore = 0;
- uint32_t current_trait_num = ce->num_traits;
- uint32_t parent_trait_num = ce->parent ? ce->parent->num_traits : 0;
-
- for (i = 0; i < ce->num_traits; i++) {
- if (ce->traits[i] == NULL) {
- memmove(ce->traits + i, ce->traits + i + 1, sizeof(zend_class_entry*) * (--ce->num_traits - i));
- i--;
- } else if (ce->traits[i] == trait) {
- if (i < parent_trait_num) {
- ignore = 1;
- }
- }
- }
- if (!ignore) {
- if (ce->num_traits >= current_trait_num) {
- if (ce->type == ZEND_INTERNAL_CLASS) {
- ce->traits = (zend_class_entry **) realloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
- } else {
- ce->traits = (zend_class_entry **) erealloc(ce->traits, sizeof(zend_class_entry *) * (++current_trait_num));
- }
- }
- ce->traits[ce->num_traits++] = trait;
- }
-}
-/* }}} */
-
-static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */
-{
- uint32_t fn_flags = fn->common.scope->ce_flags;
- uint32_t other_flags = other_fn->common.scope->ce_flags;
-
- return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
- && ((other_fn->common.scope->ce_flags & ZEND_ACC_INTERFACE) || zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC))
- && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
- (other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
-}
-/* }}} */
-
-static void zend_add_magic_methods(zend_class_entry* ce, zend_string* mname, zend_function* fe TSRMLS_DC) /* {{{ */
-{
- if (!strncmp(mname->val, ZEND_CLONE_FUNC_NAME, mname->len)) {
- ce->clone = fe; fe->common.fn_flags |= ZEND_ACC_CLONE;
- } else if (!strncmp(mname->val, ZEND_CONSTRUCTOR_FUNC_NAME, mname->len)) {
- if (ce->constructor) {
- zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
- }
- ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
- } else if (!strncmp(mname->val, ZEND_DESTRUCTOR_FUNC_NAME, mname->len)) {
- ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
- } else if (!strncmp(mname->val, ZEND_GET_FUNC_NAME, mname->len)) {
- ce->__get = fe;
- } else if (!strncmp(mname->val, ZEND_SET_FUNC_NAME, mname->len)) {
- ce->__set = fe;
- } else if (!strncmp(mname->val, ZEND_CALL_FUNC_NAME, mname->len)) {
- ce->__call = fe;
- } else if (!strncmp(mname->val, ZEND_UNSET_FUNC_NAME, mname->len)) {
- ce->__unset = fe;
- } else if (!strncmp(mname->val, ZEND_ISSET_FUNC_NAME, mname->len)) {
- ce->__isset = fe;
- } else if (!strncmp(mname->val, ZEND_CALLSTATIC_FUNC_NAME, mname->len)) {
- ce->__callstatic = fe;
- } else if (!strncmp(mname->val, ZEND_TOSTRING_FUNC_NAME, mname->len)) {
- ce->__tostring = fe;
- } else if (!strncmp(mname->val, ZEND_DEBUGINFO_FUNC_NAME, mname->len)) {
- ce->__debugInfo = fe;
- } else if (ce->name->len == mname->len) {
- zend_string *lowercase_name = zend_string_alloc(ce->name->len, 0);
- zend_str_tolower_copy(lowercase_name->val, ce->name->val, ce->name->len);
- lowercase_name = zend_new_interned_string(lowercase_name TSRMLS_CC);
- if (!memcmp(mname->val, lowercase_name->val, mname->len)) {
- if (ce->constructor) {
- zend_error_noreturn(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name->val);
- }
- ce->constructor = fe;
- fe->common.fn_flags |= ZEND_ACC_CTOR;
- }
- zend_string_release(lowercase_name);
- }
-}
-/* }}} */
-
-static void zend_add_trait_method(zend_class_entry *ce, const char *name, zend_string *key, zend_function *fn, HashTable **overriden TSRMLS_DC) /* {{{ */
-{
- zend_function *existing_fn = NULL;
- zend_function *new_fn;
-
- if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
- if (existing_fn->common.scope == ce) {
- /* members from the current class override trait methods */
- /* use temporary *overriden HashTable to detect hidden conflict */
- if (*overriden) {
- if ((existing_fn = zend_hash_find_ptr(*overriden, key)) != NULL) {
- if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
- /* Make sure the trait method is compatible with previosly declared abstract method */
- if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
- zend_get_function_declaration(fn TSRMLS_CC),
- zend_get_function_declaration(existing_fn TSRMLS_CC));
- }
- } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
- /* Make sure the abstract declaration is compatible with previous declaration */
- if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
- zend_get_function_declaration(fn TSRMLS_CC),
- zend_get_function_declaration(existing_fn TSRMLS_CC));
- }
- return;
- }
- }
- } else {
- ALLOC_HASHTABLE(*overriden);
- zend_hash_init_ex(*overriden, 8, NULL, ptr_dtor, 0, 0);
- }
- fn = zend_hash_update_mem(*overriden, key, fn, sizeof(zend_function));
- return;
- } else if (existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
- /* Make sure the trait method is compatible with previosly declared abstract method */
- if (!zend_traits_method_compatibility_check(fn, existing_fn TSRMLS_CC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
- zend_get_function_declaration(fn TSRMLS_CC),
- zend_get_function_declaration(existing_fn TSRMLS_CC));
- }
- } else if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
- /* Make sure the abstract declaration is compatible with previous declaration */
- if (!zend_traits_method_compatibility_check(existing_fn, fn TSRMLS_CC)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s",
- zend_get_function_declaration(fn TSRMLS_CC),
- zend_get_function_declaration(existing_fn TSRMLS_CC));
- }
- return;
- } else if ((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
- /* two traits can't define the same non-abstract method */
-#if 1
- zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s has not been applied, because there are collisions with other trait methods on %s",
- name, ce->name->val);
-#else /* TODO: better error message */
- zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
- fn->common.scope->name->val, fn->common.function_name->val,
- ce->name->val, name,
- existing_fn->common.scope->name->val, existing_fn->common.function_name->val);
-#endif
- } else {
- /* inherited members are overridden by members inserted by traits */
- /* check whether the trait method fulfills the inheritance requirements */
- do_inheritance_check_on_method(fn, existing_fn TSRMLS_CC);
- }
- }
-
- function_add_ref(fn);
- new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
- memcpy(new_fn, fn, sizeof(zend_op_array));
- fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
- zend_add_magic_methods(ce, key, fn TSRMLS_CC);
-}
-/* }}} */
-
-static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
-{
- if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
-
- fn->common.scope = ce;
-
- if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
- ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
- }
- if (fn->op_array.static_variables) {
- ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
- }
- }
-}
-/* }}} */
-
-static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table TSRMLS_DC) /* {{{ */
-{
- zend_trait_alias *alias, **alias_ptr;
- zend_string *lcname;
- zend_function fn_copy;
-
- /* apply aliases which are qualified with a class name, there should not be any ambiguity */
- if (ce->trait_aliases) {
- alias_ptr = ce->trait_aliases;
- alias = *alias_ptr;
- while (alias) {
- /* Scope unset or equal to the function we compare to, and the alias applies to fn */
- if (alias->alias != NULL
- && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
- && alias->trait_method->method_name->len == fnname->len
- && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
- fn_copy = *fn;
-
- /* if it is 0, no modifieres has been changed */
- if (alias->modifiers) {
- fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
- }
-
- lcname = zend_string_alloc(alias->alias->len, 0);
- zend_str_tolower_copy(lcname->val, alias->alias->val, alias->alias->len);
- zend_add_trait_method(ce, alias->alias->val, lcname, &fn_copy, overriden TSRMLS_CC);
- zend_string_release(lcname);
-
- /* Record the trait from which this alias was resolved. */
- if (!alias->trait_method->ce) {
- alias->trait_method->ce = fn->common.scope;
- }
- }
- alias_ptr++;
- alias = *alias_ptr;
- }
- }
-
- if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
- /* is not in hashtable, thus, function is not to be excluded */
- fn_copy = *fn;
-
- /* apply aliases which have not alias name, just setting visibility */
- if (ce->trait_aliases) {
- alias_ptr = ce->trait_aliases;
- alias = *alias_ptr;
- while (alias) {
- /* Scope unset or equal to the function we compare to, and the alias applies to fn */
- if (alias->alias == NULL && alias->modifiers != 0
- && (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
- && (alias->trait_method->method_name->len == fnname->len)
- && (zend_binary_strcasecmp(alias->trait_method->method_name->val, alias->trait_method->method_name->len, fnname->val, fnname->len) == 0)) {
-
- fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
-
- /** Record the trait from which this alias was resolved. */
- if (!alias->trait_method->ce) {
- alias->trait_method->ce = fn->common.scope;
- }
- }
- alias_ptr++;
- alias = *alias_ptr;
- }
- }
-
- zend_add_trait_method(ce, fn->common.function_name->val, fnname, &fn_copy, overriden TSRMLS_CC);
- }
-
- return ZEND_HASH_APPLY_KEEP;
-}
-/* }}} */
-
-static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait TSRMLS_DC) /* {{{ */
-{
- uint32_t i;
-
- if ((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT) {
- zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", trait->name->val);
- }
-
- for (i = 0; i < ce->num_traits; i++) {
- if (ce->traits[i] == trait) {
- return;
- }
- }
- zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", trait->name->val, ce->name->val);
-}
-/* }}} */
-
-static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
- size_t i, j = 0;
- zend_trait_precedence *cur_precedence;
- zend_trait_method_reference *cur_method_ref;
- zend_string *lcname;
- zend_bool method_exists;
-
- /* resolve class references */
- if (ce->trait_precedences) {
- i = 0;
- while ((cur_precedence = ce->trait_precedences[i])) {
- /** Resolve classes for all precedence operations. */
- if (cur_precedence->exclude_from_classes) {
- cur_method_ref = cur_precedence->trait_method;
- if (!(cur_precedence->trait_method->ce = zend_fetch_class(cur_method_ref->class_name,
- ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
- zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
- }
- zend_check_trait_usage(ce, cur_precedence->trait_method->ce TSRMLS_CC);
-
- /** Ensure that the prefered method is actually available. */
- lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
- zend_str_tolower_copy(lcname->val,
- cur_method_ref->method_name->val,
- cur_method_ref->method_name->len);
- method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
- lcname);
- zend_string_free(lcname);
- if (!method_exists) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "A precedence rule was defined for %s::%s but this method does not exist",
- cur_method_ref->ce->name->val,
- cur_method_ref->method_name->val);
- }
-
- /** With the other traits, we are more permissive.
- We do not give errors for those. This allows to be more
- defensive in such definitions.
- However, we want to make sure that the insteadof declaration
- is consistent in itself.
- */
- j = 0;
- while (cur_precedence->exclude_from_classes[j].class_name) {
- zend_string* class_name = cur_precedence->exclude_from_classes[j].class_name;
-
- if (!(cur_precedence->exclude_from_classes[j].ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
- zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", class_name->val);
- }
- zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce TSRMLS_CC);
-
- /* make sure that the trait method is not from a class mentioned in
- exclude_from_classes, for consistency */
- if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i].ce) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "Inconsistent insteadof definition. "
- "The method %s is to be used from %s, but %s is also on the exclude list",
- cur_method_ref->method_name->val,
- cur_precedence->trait_method->ce->name->val,
- cur_precedence->trait_method->ce->name->val);
- }
-
- zend_string_release(class_name);
- j++;
- }
- }
- i++;
- }
- }
-
- if (ce->trait_aliases) {
- i = 0;
- while (ce->trait_aliases[i]) {
- /** For all aliases with an explicit class name, resolve the class now. */
- if (ce->trait_aliases[i]->trait_method->class_name) {
- cur_method_ref = ce->trait_aliases[i]->trait_method;
- if (!(cur_method_ref->ce = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
- zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", cur_method_ref->class_name->val);
- }
- zend_check_trait_usage(ce, cur_method_ref->ce TSRMLS_CC);
-
- /** And, ensure that the referenced method is resolvable, too. */
- lcname = zend_string_alloc(cur_method_ref->method_name->len, 0);
- zend_str_tolower_copy(lcname->val,
- cur_method_ref->method_name->val,
- cur_method_ref->method_name->len);
- method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
- lcname);
- zend_string_free(lcname);
-
- if (!method_exists) {
- zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", cur_method_ref->ce->name->val, cur_method_ref->method_name->val);
- }
- }
- i++;
- }
- }
-}
-/* }}} */
-
-static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
-{
- size_t i = 0, j;
-
- if (!precedences) {
- return;
- }
- while (precedences[i]) {
- if (precedences[i]->exclude_from_classes) {
- j = 0;
- while (precedences[i]->exclude_from_classes[j].ce) {
- if (precedences[i]->exclude_from_classes[j].ce == trait) {
- zend_string *lcname = zend_string_alloc(precedences[i]->trait_method->method_name->len, 0);
-
- zend_str_tolower_copy(lcname->val,
- precedences[i]->trait_method->method_name->val,
- precedences[i]->trait_method->method_name->len);
- if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
- zend_string_release(lcname);
- zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name->val, trait->name->val);
- }
- zend_string_release(lcname);
- }
- ++j;
- }
- }
- ++i;
- }
-}
-/* }}} */
-
-static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
- uint32_t i;
- HashTable *overriden = NULL;
- zend_string *key;
- zend_function *fn;
-
- for (i = 0; i < ce->num_traits; i++) {
- if (ce->trait_precedences) {
- HashTable exclude_table;
-
- /* TODO: revisit this start size, may be its not optimal */
- zend_hash_init_ex(&exclude_table, 8, NULL, NULL, 0, 0);
-
- zend_traits_compile_exclude_table(&exclude_table, ce->trait_precedences, ce->traits[i]);
-
- /* copies functions, applies defined aliasing, and excludes unused trait methods */
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
- zend_traits_copy_functions(key, fn, ce, &overriden, &exclude_table TSRMLS_CC);
- } ZEND_HASH_FOREACH_END();
-
- zend_hash_destroy(&exclude_table);
- } else {
- ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
- zend_traits_copy_functions(key, fn, ce, &overriden, NULL TSRMLS_CC);
- } ZEND_HASH_FOREACH_END();
- }
- }
-
- ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
- zend_fixup_trait_method(fn, ce);
- } ZEND_HASH_FOREACH_END();
-
- if (overriden) {
- zend_hash_destroy(overriden);
- FREE_HASHTABLE(overriden);
- }
-}
-/* }}} */
-
-static zend_class_entry* find_first_definition(zend_class_entry *ce, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
-{
- size_t i;
-
- if (coliding_ce == ce) {
- for (i = 0; i < current_trait; i++) {
- if (zend_hash_exists(&ce->traits[i]->properties_info, prop_name)) {
- return ce->traits[i];
- }
- }
- }
-
- return coliding_ce;
-}
-/* }}} */
-
-static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
- size_t i;
- zend_property_info *property_info;
- zend_property_info *coliding_prop;
- zval compare_result;
- zend_string* prop_name;
- const char* class_name_unused;
- zend_bool not_compatible;
- zval* prop_value;
- uint32_t flags;
- zend_string *doc_comment;
-
- /* In the following steps the properties are inserted into the property table
- * for that, a very strict approach is applied:
- * - check for compatibility, if not compatible with any property in class -> fatal
- * - if compatible, then strict notice
- */
- for (i = 0; i < ce->num_traits; i++) {
- ZEND_HASH_FOREACH_PTR(&ce->traits[i]->properties_info, property_info) {
- /* first get the unmangeld name if necessary,
- * then check whether the property is already there
- */
- flags = property_info->flags;
- if ((flags & ZEND_ACC_PPP_MASK) == ZEND_ACC_PUBLIC) {
- prop_name = zend_string_copy(property_info->name);
- } else {
- const char *pname;
- int pname_len;
-
- /* for private and protected we need to unmangle the names */
- zend_unmangle_property_name_ex(property_info->name->val, property_info->name->len,
- &class_name_unused, &pname, &pname_len);
- prop_name = zend_string_init(pname, pname_len, 0);
- }
-
- /* next: check for conflicts with current class */
- if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
- if (coliding_prop->flags & ZEND_ACC_SHADOW) {
- zend_hash_del(&ce->properties_info, prop_name);
- flags |= ZEND_ACC_CHANGED;
- } else {
- if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
- == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
- /* flags are identical, now the value needs to be checked */
- if (flags & ZEND_ACC_STATIC) {
- not_compatible = (FAILURE == compare_function(&compare_result,
- &ce->default_static_members_table[coliding_prop->offset],
- &ce->traits[i]->default_static_members_table[property_info->offset] TSRMLS_CC))
- || (Z_LVAL(compare_result) != 0);
- } else {
- not_compatible = (FAILURE == compare_function(&compare_result,
- &ce->default_properties_table[coliding_prop->offset],
- &ce->traits[i]->default_properties_table[property_info->offset] TSRMLS_CC))
- || (Z_LVAL(compare_result) != 0);
- }
- } else {
- /* the flags are not identical, thus, we assume properties are not compatible */
- not_compatible = 1;
- }
-
- if (not_compatible) {
- zend_error_noreturn(E_COMPILE_ERROR,
- "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
- find_first_definition(ce, i, prop_name, coliding_prop->ce)->name->val,
- property_info->ce->name->val,
- prop_name->val,
- ce->name->val);
- } else {
- zend_error(E_STRICT,
- "%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
- find_first_definition(ce, i, prop_name, coliding_prop->ce)->name->val,
- property_info->ce->name->val,
- prop_name->val,
- ce->name->val);
- zend_string_release(prop_name);
- continue;
- }
- }
- }
-
- /* property not found, so lets add it */
- if (flags & ZEND_ACC_STATIC) {
- prop_value = &ce->traits[i]->default_static_members_table[property_info->offset];
- } else {
- prop_value = &ce->traits[i]->default_properties_table[property_info->offset];
- }
- if (Z_REFCOUNTED_P(prop_value)) Z_ADDREF_P(prop_value);
-
- doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
- zend_declare_property_ex(ce, prop_name,
- prop_value, flags,
- doc_comment TSRMLS_CC);
- zend_string_release(prop_name);
- } ZEND_HASH_FOREACH_END();
- }
-}
-/* }}} */
-
-static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
- int i = 0;
- zend_trait_alias* cur_alias;
- zend_string* lc_method_name;
-
- if (ce->trait_aliases) {
- while (ce->trait_aliases[i]) {
- cur_alias = ce->trait_aliases[i];
- /** The trait for this alias has not been resolved, this means, this
- alias was not applied. Abort with an error. */
- if (!cur_alias->trait_method->ce) {
- if (cur_alias->alias) {
- /** Plain old inconsistency/typo/bug */
- zend_error_noreturn(E_COMPILE_ERROR,
- "An alias (%s) was defined for method %s(), but this method does not exist",
- cur_alias->alias->val,
- cur_alias->trait_method->method_name->val);
- } else {
- /** Here are two possible cases:
- 1) this is an attempt to modifiy the visibility
- of a method introduce as part of another alias.
- Since that seems to violate the DRY principle,
- we check against it and abort.
- 2) it is just a plain old inconsitency/typo/bug
- as in the case where alias is set. */
-
- lc_method_name = zend_string_alloc(cur_alias->trait_method->method_name->len, 0);
- zend_str_tolower_copy(
- lc_method_name->val,
- cur_alias->trait_method->method_name->val,
- cur_alias->trait_method->method_name->len);
- if (zend_hash_exists(&ce->function_table,
- lc_method_name)) {
- zend_string_free(lc_method_name);
- zend_error_noreturn(E_COMPILE_ERROR,
- "The modifiers for the trait alias %s() need to be changed in the same statment in which the alias is defined. Error",
- cur_alias->trait_method->method_name->val);
- } else {
- zend_string_free(lc_method_name);
- zend_error_noreturn(E_COMPILE_ERROR,
- "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
- cur_alias->trait_method->method_name->val);
-
- }
- }
- }
- i++;
- }
- }
-}
-/* }}} */
-
-ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
-{
-
- if (ce->num_traits <= 0) {
- return;
- }
-
- /* complete initialization of trait strutures in ce */
- zend_traits_init_trait_structures(ce TSRMLS_CC);
-
- /* first care about all methods to be flattened into the class */
- zend_do_traits_method_binding(ce TSRMLS_CC);
-
- /* Aliases which have not been applied indicate typos/bugs. */
- zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
-
- /* then flatten the properties into it, to, mostly to notfiy developer about problems */
- zend_do_traits_property_binding(ce TSRMLS_CC);
-
- /* verify that all abstract methods from traits have been implemented */
- zend_verify_abstract_class(ce TSRMLS_CC);
-
- /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
- if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
- ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
- }
-}
-/* }}} */
-
ZEND_API int do_bind_function(const zend_op_array *op_array, const zend_op *opline, HashTable *function_table, zend_bool compile_time TSRMLS_DC) /* {{{ */
{
zend_function *function, *new_function;
@@ -2668,13 +1093,11 @@ ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS
}
/* }}} */
-ZEND_API zend_string *zend_mangle_property_name(const char *src1, int src1_length, const char *src2, int src2_length, int internal) /* {{{ */
+ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, int internal) /* {{{ */
{
- zend_string *prop_name;
- int prop_name_length;
+ size_t prop_name_length = 1 + src1_length + 1 + src2_length;
+ zend_string *prop_name = zend_string_alloc(prop_name_length, internal);
- prop_name_length = 1 + src1_length + 1 + src2_length;
- prop_name = zend_string_alloc(prop_name_length, internal);
prop_name->val[0] = '\0';
memcpy(prop_name->val + 1, src1, src1_length+1);
memcpy(prop_name->val + 1 + src1_length + 1, src2, src2_length+1);
@@ -2682,105 +1105,94 @@ ZEND_API zend_string *zend_mangle_property_name(const char *src1, int src1_lengt
}
/* }}} */
-static int zend_strnlen(const char* s, int maxlen) /* {{{ */
+static int zend_strnlen(const char* s, size_t maxlen) /* {{{ */
{
- int len = 0;
+ size_t len = 0;
while (*s++ && maxlen--) len++;
return len;
}
/* }}} */
-ZEND_API int zend_unmangle_property_name_ex(const char *mangled_property, int len, const char **class_name, const char **prop_name, int *prop_len) /* {{{ */
+ZEND_API int zend_unmangle_property_name_ex(const zend_string *name, const char **class_name, const char **prop_name, size_t *prop_len) /* {{{ */
{
- int class_name_len;
+ size_t class_name_len;
*class_name = NULL;
- if (mangled_property[0]!=0) {
- *prop_name = mangled_property;
+ if (name->val[0] != '\0') {
+ *prop_name = name->val;
if (prop_len) {
- *prop_len = len;
+ *prop_len = name->len;
}
return SUCCESS;
}
- if (len < 3 || mangled_property[1]==0) {
+ if (name->len < 3 || name->val[1] == '\0') {
zend_error(E_NOTICE, "Illegal member variable name");
- *prop_name = mangled_property;
+ *prop_name = name->val;
if (prop_len) {
- *prop_len = len;
+ *prop_len = name->len;
}
return FAILURE;
}
- class_name_len = zend_strnlen(mangled_property + 1, --len - 1) + 1;
- if (class_name_len >= len || mangled_property[class_name_len]!=0) {
+ class_name_len = zend_strnlen(name->val + 1, name->len - 2);
+ if (class_name_len >= name->len - 2 || name->val[class_name_len + 1] != '\0') {
zend_error(E_NOTICE, "Corrupt member variable name");
- *prop_name = mangled_property;
+ *prop_name = name->val;
if (prop_len) {
- *prop_len = len + 1;
+ *prop_len = name->len;
}
return FAILURE;
}
- *class_name = mangled_property + 1;
- *prop_name = (*class_name) + class_name_len;
+
+ *class_name = name->val + 1;
+ *prop_name = name->val + class_name_len + 2;
if (prop_len) {
- *prop_len = len - class_name_len;
+ *prop_len = name->len - class_name_len - 2;
}
return SUCCESS;
}
/* }}} */
-static zend_constant *zend_get_ct_const(zend_string *name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
+static zend_constant *zend_lookup_reserved_const(const char *name, size_t len TSRMLS_DC) /* {{{ */
{
- zend_constant *c = NULL;
- char *lookup_name;
-
- if (name->val[0] == '\\') {
- c = zend_hash_str_find_ptr(EG(zend_constants), name->val + 1, name->len - 1);
- if (!c) {
- lookup_name = zend_str_tolower_dup(name->val + 1, name->len - 1);
- c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len - 1);
- efree(lookup_name);
-
- if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
- return c;
- }
- return NULL;
- }
- } else if ((c = zend_hash_find_ptr(EG(zend_constants), name)) == NULL) {
- lookup_name = zend_str_tolower_dup(name->val, name->len);
- c = zend_hash_str_find_ptr(EG(zend_constants), lookup_name, name->len);
- efree(lookup_name);
-
- if (c && (c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
- return c;
- }
- return NULL;
- }
-
- if (c->flags & CONST_CT_SUBST) {
- return c;
- }
- if (all_internal_constants_substitution &&
- (c->flags & CONST_PERSISTENT) &&
- !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION) &&
- !Z_CONSTANT(c->value)) {
+ zend_constant *c = zend_hash_find_ptr_lc(EG(zend_constants), name, len);
+ if (c && !(c->flags & CONST_CS) && (c->flags & CONST_CT_SUBST)) {
return c;
}
return NULL;
}
/* }}} */
-static int zend_constant_ct_subst(znode *result, zval *const_name, int all_internal_constants_substitution TSRMLS_DC) /* {{{ */
+static zend_bool zend_try_ct_eval_const(zval *zv, zend_string *name, zend_bool is_fully_qualified TSRMLS_DC) /* {{{ */
{
- zend_constant *c = zend_get_ct_const(Z_STR_P(const_name),
- all_internal_constants_substitution TSRMLS_CC);
+ zend_constant *c;
- if (c) {
- result->op_type = IS_CONST;
- ZVAL_DUP(&result->u.constant, &c->value);
- return 1;
+ if (!(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
+ /* Substitute case-sensitive (or lowercase) persistent constants */
+ c = zend_hash_find_ptr(EG(zend_constants), name);
+ if (c && (c->flags & CONST_PERSISTENT)) {
+ ZVAL_DUP(zv, &c->value);
+ return 1;
+ }
}
+
+ {
+ /* Substitute true, false and null (including unqualified usage in namespaces) */
+ const char *lookup_name = name->val;
+ size_t lookup_len = name->len;
+
+ if (!is_fully_qualified) {
+ zend_get_unqualified_name(name, &lookup_name, &lookup_len);
+ }
+
+ c = zend_lookup_reserved_const(lookup_name, lookup_len TSRMLS_CC);
+ if (c) {
+ ZVAL_DUP(zv, &c->value);
+ return 1;
+ }
+ }
+
return 0;
}
/* }}} */
@@ -2934,9 +1346,6 @@ again:
if (LANG_SCNG(yy_text)[LANG_SCNG(yy_leng)-1] != '>') {
CG(increment_lineno) = 1;
}
- if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
- goto again;
- }
retval = ';'; /* implicit ; */
break;
case T_OPEN_TAG_WITH_ECHO:
@@ -3311,7 +1720,9 @@ static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, z
SET_NODE(opline->op2, op2);
}
- zend_make_tmp_result(result, opline TSRMLS_CC);
+ if (result) {
+ zend_make_tmp_result(result, opline TSRMLS_CC);
+ }
return opline;
}
@@ -3575,7 +1986,6 @@ static zend_op *zend_compile_simple_var_no_cv(znode *result, zend_ast *ast, uint
zend_compile_expr(&name_node, name_ast TSRMLS_CC);
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline = zend_emit_op(result, ZEND_FETCH_R, &name_node, NULL TSRMLS_CC);
opline->extended_value = ZEND_FETCH_LOCAL;
@@ -3613,6 +2023,22 @@ static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t
/* }}} */
void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC);
+void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC);
+static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node TSRMLS_DC);
+
+static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */
+{
+ znode dummy_node;
+ if (var_ast->kind == ZEND_AST_LIST) {
+ zend_compile_list_assign(&dummy_node, var_ast, value_node TSRMLS_CC);
+ } else {
+ zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
+ zend_ast_create_znode(value_node));
+ zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC);
+ }
+ zend_do_free(&dummy_node TSRMLS_CC);
+}
+/* }}} */
static zend_op *zend_delayed_compile_dim(znode *result, zend_ast *ast, uint32_t type TSRMLS_DC) /* {{{ */
{
@@ -3773,7 +2199,7 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n
for (i = 0; i < list->children; ++i) {
zend_ast *var_ast = list->child[i];
- znode fetch_result, dim_node, var_node, assign_result;
+ znode fetch_result, dim_node;
zend_op *opline;
if (var_ast == NULL) {
@@ -3791,17 +2217,7 @@ static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_n
get_list_fetch_opcode(expr_node->op_type), expr_node, &dim_node TSRMLS_CC);
opline->extended_value |= ZEND_FETCH_ADD_LOCK;
- if (var_ast->kind != ZEND_AST_LIST) {
- if (is_this_fetch(var_ast)) {
- zend_error_noreturn(E_COMPILE_ERROR, "Cannot re-assign $this");
- }
- zend_compile_var(&var_node, var_ast, BP_VAR_W TSRMLS_CC);
- zend_emit_op(&assign_result, ZEND_ASSIGN, &var_node, &fetch_result TSRMLS_CC);
- zend_do_free(&assign_result TSRMLS_CC);
- } else {
- zend_compile_list_assign(&assign_result, var_ast, &fetch_result TSRMLS_CC);
- zend_do_free(&assign_result TSRMLS_CC);
- }
+ zend_emit_assign_znode(var_ast, &fetch_result TSRMLS_CC);
}
*result = *expr_node;
}
@@ -3903,16 +2319,6 @@ void zend_compile_assign(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
}
/* }}} */
-static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node TSRMLS_DC) /* {{{ */
-{
- znode dummy_node;
- zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
- zend_ast_create_znode(value_node));
- zend_compile_assign(&dummy_node, assign_ast TSRMLS_CC);
- zend_do_free(&dummy_node TSRMLS_CC);
-}
-/* }}} */
-
void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
{
zend_ast *target_ast = ast->child[0];
@@ -3929,6 +2335,10 @@ void zend_compile_assign_ref(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_var(&target_node, target_ast, BP_VAR_W TSRMLS_CC);
zend_compile_var(&source_node, source_ast, BP_VAR_REF TSRMLS_CC);
+ if (source_node.op_type != IS_VAR && zend_is_call(source_ast)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Cannot use result of built-in function in write context");
+ }
+
opline = zend_emit_op(result, ZEND_ASSIGN_REF, &target_node, &source_node TSRMLS_CC);
if (!result) {
opline->result_type |= EXT_TYPE_UNUSED;
@@ -4142,7 +2552,7 @@ void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast TS
SET_UNUSED(opline->op1);
opline->op2_type = IS_CONST;
opline->op2.constant = zend_add_ns_func_name_literal(
- CG(active_op_array), &name_node->u.constant TSRMLS_CC);
+ CG(active_op_array), Z_STR(name_node->u.constant) TSRMLS_CC);
zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
zend_compile_call_common(result, args_ast, NULL TSRMLS_CC);
@@ -4156,8 +2566,8 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a
SET_UNUSED(opline->op1);
if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) {
opline->op2_type = IS_CONST;
- opline->op2.constant
- = zend_add_func_name_literal(CG(active_op_array), &name_node->u.constant TSRMLS_CC);
+ opline->op2.constant = zend_add_func_name_literal(CG(active_op_array),
+ Z_STR(name_node->u.constant) TSRMLS_CC);
zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
} else {
SET_NODE(opline->op2, name_node);
@@ -4243,13 +2653,13 @@ int zend_compile_func_defined(znode *result, zend_ast_list *args TSRMLS_DC) /* {
}
/* }}} */
-static int zend_try_compile_ct_bound_init_user_func(znode *result, zend_ast *name_ast, uint32_t num_args TSRMLS_DC) /* {{{ */
+static int zend_try_compile_ct_bound_init_user_func(zend_ast *name_ast, uint32_t num_args TSRMLS_DC) /* {{{ */
{
zend_string *name, *lcname;
zend_function *fbc;
zend_op *opline;
- if (name_ast->kind != ZEND_AST_CONST || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
+ if (name_ast->kind != ZEND_AST_ZVAL || Z_TYPE_P(zend_ast_get_zval(name_ast)) != IS_STRING) {
return FAILURE;
}
@@ -4266,20 +2676,22 @@ static int zend_try_compile_ct_bound_init_user_func(znode *result, zend_ast *nam
}
opline = zend_emit_op(NULL, ZEND_INIT_FCALL, NULL, NULL TSRMLS_CC);
+ opline->extended_value = num_args;
+
opline->op2_type = IS_CONST;
LITERAL_STR(opline->op2, lcname);
- opline->extended_value = num_args;
+ zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
return SUCCESS;
}
/* }}} */
-static void zend_compile_init_user_func(znode *result, zend_ast *name_ast, uint32_t num_args, zend_string *orig_func_name TSRMLS_DC) /* {{{ */
+static void zend_compile_init_user_func(zend_ast *name_ast, uint32_t num_args, zend_string *orig_func_name TSRMLS_DC) /* {{{ */
{
zend_op *opline;
znode name_node;
- if (zend_try_compile_ct_bound_init_user_func(result, name_ast, num_args TSRMLS_CC) == SUCCESS) {
+ if (zend_try_compile_ct_bound_init_user_func(name_ast, num_args TSRMLS_CC) == SUCCESS) {
return;
}
@@ -4301,7 +2713,7 @@ int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcna
return FAILURE;
}
- zend_compile_init_user_func(NULL, args->child[0], 1, lcname TSRMLS_CC);
+ zend_compile_init_user_func(args->child[0], 1, lcname TSRMLS_CC);
zend_compile_expr(&arg_node, args->child[1] TSRMLS_CC);
zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL TSRMLS_CC);
zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL TSRMLS_CC);
@@ -4319,7 +2731,7 @@ int zend_compile_func_cuf(znode *result, zend_ast_list *args, zend_string *lcnam
return FAILURE;
}
- zend_compile_init_user_func(NULL, args->child[0], args->children - 1, lcname TSRMLS_CC);
+ zend_compile_init_user_func(args->child[0], args->children - 1, lcname TSRMLS_CC);
for (i = 1; i < args->children; ++i) {
zend_ast *arg_ast = args->child[i];
znode arg_node;
@@ -4469,8 +2881,8 @@ void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type TSRMLS
}
opline->op2_type = IS_CONST;
- opline->op2.constant =
- zend_add_func_name_literal(CG(active_op_array), &method_node.u.constant TSRMLS_CC);
+ opline->op2.constant = zend_add_func_name_literal(CG(active_op_array),
+ Z_STR(method_node.u.constant) TSRMLS_CC);
zend_alloc_polymorphic_cache_slot(opline->op2.constant TSRMLS_CC);
} else {
SET_NODE(opline->op2, &method_node);
@@ -4524,8 +2936,8 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type TSRMLS
if (method_node.op_type == IS_CONST) {
opline->op2_type = IS_CONST;
- opline->op2.constant =
- zend_add_func_name_literal(CG(active_op_array), &method_node.u.constant TSRMLS_CC);
+ opline->op2.constant = zend_add_func_name_literal(CG(active_op_array),
+ Z_STR(method_node.u.constant) TSRMLS_CC);
if (opline->op1_type == IS_CONST) {
zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
} else {
@@ -4551,7 +2963,7 @@ void zend_compile_new(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_class_ref(&class_node, class_ast TSRMLS_CC);
opnum = get_next_op_number(CG(active_op_array));
- opline = zend_emit_op(result, ZEND_NEW, &class_node, NULL TSRMLS_CC);
+ zend_emit_op(result, ZEND_NEW, &class_node, NULL TSRMLS_CC);
zend_compile_call_common(&ctor_result, args_ast, NULL TSRMLS_CC);
zend_do_free(&ctor_result TSRMLS_CC);
@@ -4588,7 +3000,8 @@ void zend_compile_global_var(zend_ast *ast TSRMLS_DC) /* {{{ */
}
if (zend_try_compile_cv(&result, var_ast TSRMLS_CC) == SUCCESS) {
- zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node TSRMLS_CC);
+ zend_op *opline = zend_emit_op(NULL, ZEND_BIND_GLOBAL, &result, &name_node TSRMLS_CC);
+ zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
} else {
zend_emit_op(&result, ZEND_FETCH_W, &name_node, NULL TSRMLS_CC);
@@ -4804,11 +3217,9 @@ void zend_compile_goto(zend_ast *ast TSRMLS_DC) /* {{{ */
void zend_compile_label(zend_ast *ast TSRMLS_DC) /* {{{ */
{
- zval *label = zend_ast_get_zval(ast->child[0]);
+ zend_string *label = zend_ast_get_str(ast->child[0]);
zend_label dest;
- ZEND_ASSERT(Z_TYPE_P(label) == IS_STRING);
-
if (!CG(context).labels) {
ALLOC_HASHTABLE(CG(context).labels);
zend_hash_init(CG(context).labels, 8, NULL, ptr_dtor, 0);
@@ -4817,8 +3228,8 @@ void zend_compile_label(zend_ast *ast TSRMLS_DC) /* {{{ */
dest.brk_cont = CG(context).current_brk_cont;
dest.opline_num = get_next_op_number(CG(active_op_array));
- if (!zend_hash_add_mem(CG(context).labels, Z_STR_P(label), &dest, sizeof(zend_label))) {
- zend_error_noreturn(E_COMPILE_ERROR, "Label '%s' already defined", Z_STRVAL_P(label));
+ if (!zend_hash_add_mem(CG(context).labels, label, &dest, sizeof(zend_label))) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Label '%s' already defined", label->val);
}
}
/* }}} */
@@ -4935,7 +3346,7 @@ void zend_compile_foreach(zend_ast *ast TSRMLS_DC) /* {{{ */
zend_bool is_variable = zend_is_variable(expr_ast) && !zend_is_call(expr_ast)
&& zend_can_write_to_variable(expr_ast);
- znode expr_node, reset_node, value_node, key_node, dummy_node;
+ znode expr_node, reset_node, value_node, key_node;
zend_op *opline;
uint32_t opnum_reset, opnum_fetch;
@@ -4958,10 +3369,14 @@ void zend_compile_foreach(zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
}
+ if (by_ref) {
+ zend_separate_if_call_and_write(&expr_node, expr_ast, BP_VAR_W TSRMLS_CC);
+ }
+
opnum_reset = get_next_op_number(CG(active_op_array));
opline = zend_emit_op(&reset_node, ZEND_FE_RESET, &expr_node, NULL TSRMLS_CC);
if (by_ref && is_variable) {
- opline->extended_value = ZEND_FE_RESET_VARIABLE | ZEND_FE_RESET_REFERENCE; // ???
+ opline->extended_value = ZEND_FE_FETCH_BYREF;
}
zend_stack_push(&CG(loop_var_stack), &reset_node);
@@ -4989,10 +3404,7 @@ void zend_compile_foreach(zend_ast *ast TSRMLS_DC) /* {{{ */
zend_make_tmp_result(&key_node, opline TSRMLS_CC);
}
- if (value_ast->attr == ZEND_AST_LIST) {
- zend_compile_list_assign(&dummy_node, value_ast, &value_node TSRMLS_CC);
- zend_do_free(&dummy_node TSRMLS_CC);
- } else if (by_ref) {
+ if (by_ref) {
zend_emit_assign_ref_znode(value_ast, &value_node TSRMLS_CC);
} else {
zend_emit_assign_znode(value_ast, &value_node TSRMLS_CC);
@@ -5091,6 +3503,11 @@ void zend_compile_switch(zend_ast *ast TSRMLS_DC) /* {{{ */
znode cond_node;
if (!cond_ast) {
+ if (has_default_case) {
+ CG(zend_lineno) = case_ast->lineno;
+ zend_error_noreturn(E_COMPILE_ERROR,
+ "Switch statements may only contain one default clause");
+ }
has_default_case = 1;
continue;
}
@@ -5129,7 +3546,7 @@ void zend_compile_switch(zend_ast *ast TSRMLS_DC) /* {{{ */
zend_end_loop(get_next_op_number(CG(active_op_array)), 1 TSRMLS_CC);
if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) {
- zend_emit_op(NULL, expr_node.op_type == IS_TMP_VAR ? ZEND_FREE : ZEND_SWITCH_FREE,
+ zend_emit_op(NULL, ZEND_FREE,
&expr_node, NULL TSRMLS_CC);
} else if (expr_node.op_type == IS_CONST) {
zval_dtor(&expr_node.u.constant);
@@ -5518,8 +3935,6 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
}
if (op_array->fn_flags & ZEND_ACC_ABSTRACT) {
- //zend_op *opline;
-
if (op_array->fn_flags & ZEND_ACC_PRIVATE) {
zend_error_noreturn(E_COMPILE_ERROR, "%s function %s::%s() cannot be declared private",
in_interface ? "Interface" : "Abstract", ce->name->val, name->val);
@@ -5531,11 +3946,6 @@ void zend_begin_method_decl(zend_op_array *op_array, zend_string *name, zend_boo
}
ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
-
- /*opline = get_next_op(op_array TSRMLS_CC);
- opline->opcode = ZEND_RAISE_ABSTRACT_ERROR;
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);*/
} else if (!has_body) {
zend_error_noreturn(E_COMPILE_ERROR, "Non-abstract method %s::%s() must contain body",
ce->name->val, name->val);
@@ -6288,10 +4698,11 @@ void zend_compile_use(zend_ast *ast TSRMLS_DC) /* {{{ */
if (new_name_ast) {
new_name = zend_string_copy(zend_ast_get_str(new_name_ast));
} else {
- /* The form "use A\B" is eqivalent to "use A\B as B" */
- const char *p = zend_memrchr(old_name->val, '\\', old_name->len);
- if (p) {
- new_name = zend_string_init(p + 1, old_name->len - (p - old_name->val + 1), 0);
+ const char *unqualified_name;
+ size_t unqualified_name_len;
+ if (zend_get_unqualified_name(old_name, &unqualified_name, &unqualified_name_len)) {
+ /* The form "use A\B" is eqivalent to "use A\B as B" */
+ new_name = zend_string_init(unqualified_name, unqualified_name_len, 0);
} else {
new_name = zend_string_copy(old_name);
@@ -6395,11 +4806,12 @@ void zend_compile_const_decl(zend_ast *ast TSRMLS_DC) /* {{{ */
value_node.op_type = IS_CONST;
zend_const_expr_to_zval(value_zv, value_ast TSRMLS_CC);
- if (zend_get_ct_const(name, 0 TSRMLS_CC)) {
+ if (zend_lookup_reserved_const(name->val, name->len TSRMLS_CC)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare constant '%s'", name->val);
}
name = zend_prefix_with_ns(name TSRMLS_CC);
+ name = zend_new_interned_string(name TSRMLS_CC);
if (CG(current_import_const)
&& (import_name = zend_hash_find_ptr(CG(current_import_const), name))
@@ -6524,7 +4936,7 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast TSRMLS_DC)
ZVAL_LONG(zv, CG(zend_lineno));
break;
case T_FILE:
- ZVAL_STR(zv, zend_string_copy(CG(compiled_filename)));
+ ZVAL_STR_COPY(zv, CG(compiled_filename));
break;
case T_DIR:
{
@@ -6547,7 +4959,7 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast TSRMLS_DC)
}
case T_FUNC_C:
if (op_array && op_array->function_name) {
- ZVAL_STR(zv, zend_string_copy(op_array->function_name));
+ ZVAL_STR_COPY(zv, op_array->function_name);
} else {
ZVAL_EMPTY_STRING(zv);
}
@@ -6555,13 +4967,13 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast TSRMLS_DC)
case T_METHOD_C:
if (ce) {
if (op_array && op_array->function_name) {
- ZVAL_STR(zv, zend_concat3(ce->name->val, ce->name->len, "::", 2,
+ ZVAL_NEW_STR(zv, zend_concat3(ce->name->val, ce->name->len, "::", 2,
op_array->function_name->val, op_array->function_name->len));
} else {
- ZVAL_STR(zv, zend_string_copy(ce->name));
+ ZVAL_STR_COPY(zv, ce->name);
}
} else if (op_array && op_array->function_name) {
- ZVAL_STR(zv, zend_string_copy(op_array->function_name));
+ ZVAL_STR_COPY(zv, op_array->function_name);
} else {
ZVAL_EMPTY_STRING(zv);
}
@@ -6571,7 +4983,7 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast TSRMLS_DC)
if (ZEND_CE_IS_TRAIT(ce)) {
return 0;
} else {
- ZVAL_STR(zv, zend_string_copy(ce->name));
+ ZVAL_STR_COPY(zv, ce->name);
}
} else {
ZVAL_EMPTY_STRING(zv);
@@ -6579,14 +4991,14 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast TSRMLS_DC)
break;
case T_TRAIT_C:
if (ce && ZEND_CE_IS_TRAIT(ce)) {
- ZVAL_STR(zv, zend_string_copy(ce->name));
+ ZVAL_STR_COPY(zv, ce->name);
} else {
ZVAL_EMPTY_STRING(zv);
}
break;
case T_NS_C:
if (CG(current_namespace)) {
- ZVAL_STR(zv, zend_string_copy(CG(current_namespace)));
+ ZVAL_STR_COPY(zv, CG(current_namespace));
} else {
ZVAL_EMPTY_STRING(zv);
}
@@ -6851,7 +5263,7 @@ void zend_compile_cast(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(&expr_node, expr_ast TSRMLS_CC);
- opline = zend_emit_op(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
+ opline = zend_emit_op_tmp(result, ZEND_CAST, &expr_node, NULL TSRMLS_CC);
opline->extended_value = ast->attr;
}
/* }}} */
@@ -6876,17 +5288,7 @@ static void zend_compile_shorthand_conditional(znode *result, zend_ast *ast TSRM
opline_jmp_set = &CG(active_op_array)->opcodes[opnum_jmp_set];
opline_jmp_set->op2.opline_num = get_next_op_number(CG(active_op_array)) + 1;
- if (cond_node.op_type == IS_VAR || cond_node.op_type == IS_CV
- || false_node.op_type == IS_VAR || false_node.op_type == IS_CV
- ) {
- opline_jmp_set->opcode = ZEND_JMP_SET_VAR;
- opline_jmp_set->result_type = IS_VAR;
- GET_NODE(result, opline_jmp_set->result);
-
- opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN_VAR, &false_node, NULL TSRMLS_CC);
- } else {
- opline_qm_assign = zend_emit_op(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC);
- }
+ opline_qm_assign = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &false_node, NULL TSRMLS_CC);
SET_NODE(opline_qm_assign->result, result);
}
/* }}} */
@@ -6913,7 +5315,7 @@ void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(&true_node, true_ast TSRMLS_CC);
opnum_qm_assign1 = get_next_op_number(CG(active_op_array));
- zend_emit_op(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC);
+ zend_emit_op_tmp(result, ZEND_QM_ASSIGN, &true_node, NULL TSRMLS_CC);
opnum_jmp = zend_emit_jump(0 TSRMLS_CC);
@@ -6922,14 +5324,6 @@ void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(&false_node, false_ast TSRMLS_CC);
opline_qm_assign1 = &CG(active_op_array)->opcodes[opnum_qm_assign1];
- if (true_node.op_type == IS_VAR || true_node.op_type == IS_CV
- || false_node.op_type == IS_VAR || false_node.op_type == IS_CV
- ) {
- opline_qm_assign1->opcode = ZEND_QM_ASSIGN_VAR;
- opline_qm_assign1->result_type = IS_VAR;
- GET_NODE(result, opline_qm_assign1->result);
- }
-
opline_qm_assign2 = zend_emit_op(NULL, opline_qm_assign1->opcode, &false_node, NULL TSRMLS_CC);
SET_NODE(opline_qm_assign2->result, result);
@@ -6937,6 +5331,30 @@ void zend_compile_conditional(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
}
/* }}} */
+void zend_compile_coalesce(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
+{
+ zend_ast *expr_ast = ast->child[0];
+ zend_ast *default_ast = ast->child[1];
+
+ znode expr_node, default_node;
+ zend_op *opline;
+ uint32_t opnum;
+
+ zend_compile_var(&expr_node, expr_ast, BP_VAR_IS TSRMLS_CC);
+
+ opnum = get_next_op_number(CG(active_op_array));
+ zend_emit_op_tmp(result, ZEND_COALESCE, &expr_node, NULL TSRMLS_CC);
+
+ zend_compile_expr(&default_node, default_ast TSRMLS_CC);
+
+ opline = zend_emit_op_tmp(NULL, ZEND_QM_ASSIGN, &default_node, NULL TSRMLS_CC);
+ SET_NODE(opline->result, result);
+
+ opline = &CG(active_op_array)->opcodes[opnum];
+ opline->op2.opline_num = get_next_op_number(CG(active_op_array));
+}
+/* }}} */
+
void zend_compile_print(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
{
zend_ast *expr_ast = ast->child[0];
@@ -7141,7 +5559,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
{
zend_ast_list *list = zend_ast_get_list(ast);
zend_op *opline;
- uint32_t i, opnum_init;
+ uint32_t i, opnum_init = -1;
zend_bool packed = 1;
if (zend_try_ct_eval_array(&result->u.constant, ast TSRMLS_CC)) {
@@ -7149,8 +5567,6 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
return;
}
- opnum_init = get_next_op_number(CG(active_op_array));
-
for (i = 0; i < list->children; ++i) {
zend_ast *elem_ast = list->child[i];
zend_ast *value_ast = elem_ast->child[0];
@@ -7173,6 +5589,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
}
if (i == 0) {
+ opnum_init = get_next_op_number(CG(active_op_array));
opline = zend_emit_op_tmp(result, ZEND_INIT_ARRAY, &value_node, key_node_ptr TSRMLS_CC);
opline->extended_value = list->children << ZEND_ARRAY_SIZE_SHIFT;
} else {
@@ -7194,6 +5611,7 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
/* Add a flag to INIT_ARRAY if we know this array cannot be packed */
if (!packed) {
+ ZEND_ASSERT(opnum_init != -1);
opline = &CG(active_op_array)->opcodes[opnum_init];
opline->extended_value |= ZEND_ARRAY_NOT_PACKED;
}
@@ -7203,17 +5621,17 @@ void zend_compile_array(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
{
zend_ast *name_ast = ast->child[0];
- zend_string *orig_name = zend_ast_get_str(name_ast);
- zend_bool is_fully_qualified;
- zval resolved_name;
zend_op *opline;
- ZVAL_STR(&resolved_name, zend_resolve_const_name(
- orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC));
+ zend_bool is_fully_qualified;
+ zend_string *orig_name = zend_ast_get_str(name_ast);
+ zend_string *resolved_name = zend_resolve_const_name(
+ orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC);
- if (zend_constant_ct_subst(result, &resolved_name, 1 TSRMLS_CC)) {
- zval_dtor(&resolved_name);
+ if (zend_try_ct_eval_const(&result->u.constant, resolved_name, is_fully_qualified TSRMLS_CC)) {
+ result->op_type = IS_CONST;
+ zend_string_release(resolved_name);
return;
}
@@ -7222,16 +5640,16 @@ void zend_compile_const(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
if (is_fully_qualified) {
opline->op2.constant = zend_add_const_name_literal(
- CG(active_op_array), &resolved_name, 0 TSRMLS_CC);
+ CG(active_op_array), resolved_name, 0 TSRMLS_CC);
} else {
opline->extended_value = IS_CONSTANT_UNQUALIFIED;
if (CG(current_namespace)) {
opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
opline->op2.constant = zend_add_const_name_literal(
- CG(active_op_array), &resolved_name, 1 TSRMLS_CC);
+ CG(active_op_array), resolved_name, 1 TSRMLS_CC);
} else {
opline->op2.constant = zend_add_const_name_literal(
- CG(active_op_array), &resolved_name, 0 TSRMLS_CC);
+ CG(active_op_array), resolved_name, 0 TSRMLS_CC);
}
}
zend_alloc_cache_slot(opline->op2.constant TSRMLS_CC);
@@ -7279,7 +5697,7 @@ void zend_compile_resolve_class_name(znode *result, zend_ast *ast TSRMLS_DC) /*
"Cannot access self::class when no class scope is active");
}
result->op_type = IS_CONST;
- ZVAL_STR(&result->u.constant, zend_string_copy(CG(active_class_entry)->name));
+ ZVAL_STR_COPY(&result->u.constant, CG(active_class_entry)->name);
break;
case ZEND_FETCH_CLASS_STATIC:
case ZEND_FETCH_CLASS_PARENT:
@@ -7402,7 +5820,7 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */
zend_ast *ast = *ast_ptr;
zend_ast *class_ast = ast->child[0];
zend_ast *const_ast = ast->child[1];
- zend_string *class_name = zend_ast_get_str(class_ast);
+ zend_string *class_name;
zend_string *const_name = zend_ast_get_str(const_ast);
zval result;
int fetch_type;
@@ -7412,6 +5830,7 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */
"Dynamic class names are not allowed in compile-time class constant references");
}
+ class_name = zend_ast_get_str(class_ast);
fetch_type = zend_get_class_fetch_type(class_name);
if (ZEND_FETCH_CLASS_STATIC == fetch_type) {
@@ -7429,9 +5848,6 @@ void zend_compile_const_expr_class_const(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */
class_name->val, class_name->len, "::", 2, const_name->val, const_name->len);
Z_TYPE_INFO(result) = IS_CONSTANT_EX;
- if (IS_INTERNED(Z_STR(result))) {
- Z_TYPE_FLAGS(result) &= ~ (IS_TYPE_REFCOUNTED | IS_TYPE_COPYABLE);
- }
Z_CONST_FLAGS(result) = fetch_type;
zend_ast_destroy(ast);
@@ -7445,21 +5861,20 @@ void zend_compile_const_expr_const(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */
{
zend_ast *ast = *ast_ptr;
zend_ast *name_ast = ast->child[0];
- zval *orig_name = zend_ast_get_zval(name_ast);
+ zend_string *orig_name = zend_ast_get_str(name_ast);
zend_bool is_fully_qualified;
- znode result;
- zval resolved_name;
+ zval result, resolved_name;
+ ZVAL_STR(&resolved_name, zend_resolve_const_name(
+ orig_name, name_ast->attr, &is_fully_qualified TSRMLS_CC));
- if (zend_constant_ct_subst(&result, orig_name, 0 TSRMLS_CC)) {
+ if (zend_try_ct_eval_const(&result, Z_STR(resolved_name), is_fully_qualified TSRMLS_CC)) {
+ zend_string_release(Z_STR(resolved_name));
zend_ast_destroy(ast);
- *ast_ptr = zend_ast_create_zval(&result.u.constant);
+ *ast_ptr = zend_ast_create_zval(&result);
return;
}
- ZVAL_STR(&resolved_name, zend_resolve_const_name(
- Z_STR_P(orig_name), name_ast->attr, &is_fully_qualified TSRMLS_CC));
-
Z_TYPE_INFO(resolved_name) = IS_CONSTANT_EX;
if (!is_fully_qualified) {
Z_CONST_FLAGS(resolved_name) = IS_CONSTANT_UNQUALIFIED;
@@ -7483,7 +5898,7 @@ void zend_compile_const_expr_resolve_class_name(zend_ast **ast_ptr TSRMLS_DC) /*
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot access self::class when no class scope is active");
}
- ZVAL_STR(&result, zend_string_copy(CG(active_class_entry)->name));
+ ZVAL_STR_COPY(&result, CG(active_class_entry)->name);
break;
case ZEND_FETCH_CLASS_STATIC:
case ZEND_FETCH_CLASS_PARENT:
@@ -7774,6 +6189,9 @@ void zend_compile_expr(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
case ZEND_AST_CONDITIONAL:
zend_compile_conditional(result, ast TSRMLS_CC);
return;
+ case ZEND_AST_COALESCE:
+ zend_compile_coalesce(result, ast TSRMLS_CC);
+ return;
case ZEND_AST_PRINT:
zend_compile_print(result, ast TSRMLS_CC);
return;
@@ -7940,15 +6358,20 @@ void zend_eval_const_expr(zend_ast **ast_ptr TSRMLS_DC) /* {{{ */
return;
}
break;
- case ZEND_AST_CONST: {
- znode result_node;
+ case ZEND_AST_CONST:
+ {
+ zend_ast *name_ast = ast->child[0];
+ zend_bool is_fully_qualified;
+ zend_string *resolved_name = zend_resolve_const_name(
+ zend_ast_get_str(name_ast), name_ast->attr, &is_fully_qualified TSRMLS_CC);
- if (!zend_constant_ct_subst(&result_node, zend_ast_get_zval(ast->child[0]), 0 TSRMLS_CC)) {
+ if (!zend_try_ct_eval_const(&result, resolved_name, is_fully_qualified TSRMLS_CC)) {
+ zend_string_release(resolved_name);
return;
}
- zend_ast_destroy(ast);
- *ast_ptr = zend_ast_create_zval(&result_node.u.constant);
- return;
+
+ zend_string_release(resolved_name);
+ break;
}
default:
return;