mirror of
https://github.com/php/php-src.git
synced 2026-04-29 11:13:36 +02:00
Changed structure of zend_class_entry.trait_aliases and zend_class_entry.trait_precedences to avoid keeping "intermediate" trait references, that are used only during inheritance.
This commit is contained in:
+4
-7
@@ -86,20 +86,17 @@ typedef struct _zend_unserialize_data zend_unserialize_data;
|
||||
|
||||
typedef struct _zend_trait_method_reference {
|
||||
zend_string *method_name;
|
||||
zend_class_entry *ce;
|
||||
zend_string *class_name;
|
||||
} zend_trait_method_reference;
|
||||
|
||||
typedef struct _zend_trait_precedence {
|
||||
zend_trait_method_reference *trait_method;
|
||||
union {
|
||||
zend_class_entry *ce;
|
||||
zend_string *class_name;
|
||||
} *exclude_from_classes;
|
||||
zend_trait_method_reference trait_method;
|
||||
uint32_t num_excludes;
|
||||
zend_string *exclude_class_names[1];
|
||||
} zend_trait_precedence;
|
||||
|
||||
typedef struct _zend_trait_alias {
|
||||
zend_trait_method_reference *trait_method;
|
||||
zend_trait_method_reference trait_method;
|
||||
|
||||
/**
|
||||
* name for method to be added
|
||||
|
||||
+12
-27
@@ -6174,13 +6174,11 @@ void zend_compile_class_const_decl(zend_ast *ast) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_trait_method_reference *zend_compile_method_ref(zend_ast *ast) /* {{{ */
|
||||
static void zend_compile_method_ref(zend_ast *ast, zend_trait_method_reference *method_ref) /* {{{ */
|
||||
{
|
||||
zend_ast *class_ast = ast->child[0];
|
||||
zend_ast *method_ast = ast->child[1];
|
||||
|
||||
zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
|
||||
method_ref->ce = NULL;
|
||||
method_ref->method_name = zend_string_copy(zend_ast_get_str(method_ast));
|
||||
|
||||
if (class_ast) {
|
||||
@@ -6188,25 +6186,6 @@ static zend_trait_method_reference *zend_compile_method_ref(zend_ast *ast) /* {{
|
||||
} else {
|
||||
method_ref->class_name = NULL;
|
||||
}
|
||||
|
||||
return method_ref;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static zend_string **zend_compile_name_list(zend_ast *ast) /* {{{ */
|
||||
{
|
||||
zend_ast_list *list = zend_ast_get_list(ast);
|
||||
zend_string **names = safe_emalloc(sizeof(zend_string *), list->children + 1, 0);
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < list->children; ++i) {
|
||||
zend_ast *name_ast = list->child[i];
|
||||
names[i] = zend_resolve_class_name_ast(name_ast);
|
||||
}
|
||||
|
||||
names[list->children] = NULL;
|
||||
|
||||
return names;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -6214,11 +6193,17 @@ static void zend_compile_trait_precedence(zend_ast *ast) /* {{{ */
|
||||
{
|
||||
zend_ast *method_ref_ast = ast->child[0];
|
||||
zend_ast *insteadof_ast = ast->child[1];
|
||||
zend_ast_list *insteadof_list = zend_ast_get_list(insteadof_ast);
|
||||
uint32_t i;
|
||||
|
||||
zend_trait_precedence *precedence = emalloc(sizeof(zend_trait_precedence));
|
||||
precedence->trait_method = zend_compile_method_ref(method_ref_ast);
|
||||
precedence->exclude_from_classes
|
||||
= (void *) zend_compile_name_list(insteadof_ast);
|
||||
zend_trait_precedence *precedence = emalloc(sizeof(zend_trait_precedence) + (insteadof_list->children - 1) * sizeof(zend_string*));
|
||||
zend_compile_method_ref(method_ref_ast, &precedence->trait_method);
|
||||
precedence->num_excludes = insteadof_list->children;
|
||||
|
||||
for (i = 0; i < insteadof_list->children; ++i) {
|
||||
zend_ast *name_ast = insteadof_list->child[i];
|
||||
precedence->exclude_class_names[i] = zend_resolve_class_name_ast(name_ast);
|
||||
}
|
||||
|
||||
zend_add_to_list(&CG(active_class_entry)->trait_precedences, precedence);
|
||||
}
|
||||
@@ -6241,7 +6226,7 @@ static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
|
||||
}
|
||||
|
||||
alias = emalloc(sizeof(zend_trait_alias));
|
||||
alias->trait_method = zend_compile_method_ref(method_ref_ast);
|
||||
zend_compile_method_ref(method_ref_ast, &alias->trait_method);
|
||||
alias->modifiers = modifiers;
|
||||
|
||||
if (alias_ast) {
|
||||
|
||||
+131
-133
@@ -1257,22 +1257,24 @@ static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /*
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table) /* {{{ */
|
||||
static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable **overriden, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
|
||||
{
|
||||
zend_trait_alias *alias, **alias_ptr;
|
||||
zend_string *lcname;
|
||||
zend_function fn_copy;
|
||||
int i;
|
||||
|
||||
/* 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;
|
||||
i = 0;
|
||||
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)
|
||||
&& ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname)
|
||||
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
|
||||
&& (!aliases[i] || fn->common.scope == aliases[i])
|
||||
&& ZSTR_LEN(alias->trait_method.method_name) == ZSTR_LEN(fnname)
|
||||
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method.method_name), ZSTR_LEN(alias->trait_method.method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
|
||||
fn_copy = *fn;
|
||||
|
||||
/* if it is 0, no modifieres has been changed */
|
||||
@@ -1285,12 +1287,17 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
|
||||
zend_string_release_ex(lcname, 0);
|
||||
|
||||
/* Record the trait from which this alias was resolved. */
|
||||
if (!alias->trait_method->ce) {
|
||||
alias->trait_method->ce = fn->common.scope;
|
||||
if (!aliases[i]) {
|
||||
aliases[i] = fn->common.scope;
|
||||
}
|
||||
if (!alias->trait_method.class_name) {
|
||||
/* TODO: try to avoid this assignment (it's necessary only for reflection) */
|
||||
alias->trait_method.class_name = zend_string_copy(fn->common.scope->name);
|
||||
}
|
||||
}
|
||||
alias_ptr++;
|
||||
alias = *alias_ptr;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,22 +1310,28 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
|
||||
if (ce->trait_aliases) {
|
||||
alias_ptr = ce->trait_aliases;
|
||||
alias = *alias_ptr;
|
||||
i = 0;
|
||||
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)
|
||||
&& (ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname))
|
||||
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
|
||||
&& (!aliases[i] || fn->common.scope == aliases[i])
|
||||
&& (ZSTR_LEN(alias->trait_method.method_name) == ZSTR_LEN(fnname))
|
||||
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method.method_name), ZSTR_LEN(alias->trait_method.method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 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;
|
||||
if (!aliases[i]) {
|
||||
aliases[i] = fn->common.scope;
|
||||
}
|
||||
if (!alias->trait_method.class_name) {
|
||||
/* TODO: try to avoid this assignment (it's necessary only for reflection) */
|
||||
alias->trait_method.class_name = zend_string_copy(fn->common.scope->name);
|
||||
}
|
||||
}
|
||||
alias_ptr++;
|
||||
alias = *alias_ptr;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1329,24 +1342,26 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait) /* {{{ */
|
||||
static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait) /* {{{ */
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
if (UNEXPECTED((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", ZSTR_VAL(trait->name));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ce->num_traits; i++) {
|
||||
if (ce->traits[i] == trait) {
|
||||
return;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void zend_traits_init_trait_structures(zend_class_entry *ce) /* {{{ */
|
||||
static void zend_traits_init_trait_structures(zend_class_entry *ce, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
|
||||
{
|
||||
size_t i, j = 0;
|
||||
zend_trait_precedence **precedences;
|
||||
@@ -1354,153 +1369,137 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce) /* {{{ */
|
||||
zend_trait_method_reference *cur_method_ref;
|
||||
zend_string *lcname;
|
||||
zend_bool method_exists;
|
||||
HashTable **exclude_tables = NULL;
|
||||
zend_class_entry **aliases = NULL;
|
||||
zend_class_entry *trait;
|
||||
|
||||
/* resolve class references */
|
||||
if (ce->trait_precedences) {
|
||||
exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
|
||||
i = 0;
|
||||
precedences = ce->trait_precedences;
|
||||
ce->trait_precedences = NULL;
|
||||
while ((cur_precedence = 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))) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
|
||||
}
|
||||
zend_check_trait_usage(ce, cur_precedence->trait_method->ce);
|
||||
cur_method_ref = &cur_precedence->trait_method;
|
||||
trait = zend_fetch_class(cur_method_ref->class_name,
|
||||
ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
if (!trait) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
|
||||
}
|
||||
zend_check_trait_usage(ce, trait);
|
||||
|
||||
/** Ensure that the preferred method is actually available. */
|
||||
lcname = zend_string_tolower(cur_method_ref->method_name);
|
||||
method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
|
||||
lcname);
|
||||
zend_string_release_ex(lcname, 0);
|
||||
if (!method_exists) {
|
||||
/** Ensure that the preferred method is actually available. */
|
||||
lcname = zend_string_tolower(cur_method_ref->method_name);
|
||||
method_exists = zend_hash_exists(&trait->function_table, lcname);
|
||||
if (!method_exists) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"A precedence rule was defined for %s::%s but this method does not exist",
|
||||
ZSTR_VAL(trait->name),
|
||||
ZSTR_VAL(cur_method_ref->method_name));
|
||||
}
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
|
||||
for (j = 0; j < cur_precedence->num_excludes; j++) {
|
||||
zend_string* class_name = cur_precedence->exclude_class_names[j];
|
||||
zend_class_entry *exclude_ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
uint32_t trait_num;
|
||||
|
||||
if (!exclude_ce) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
|
||||
}
|
||||
trait_num = zend_check_trait_usage(ce, exclude_ce);
|
||||
if (!exclude_tables[trait_num]) {
|
||||
ALLOC_HASHTABLE(exclude_tables[trait_num]);
|
||||
zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
|
||||
}
|
||||
if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", ZSTR_VAL(precedences[i]->trait_method.method_name), ZSTR_VAL(exclude_ce->name));
|
||||
}
|
||||
|
||||
/* make sure that the trait method is not from a class mentioned in
|
||||
exclude_from_classes, for consistency */
|
||||
if (trait == exclude_ce) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"A precedence rule was defined for %s::%s but this method does not exist",
|
||||
ZSTR_VAL(cur_method_ref->ce->name),
|
||||
ZSTR_VAL(cur_method_ref->method_name));
|
||||
}
|
||||
|
||||
/** 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))) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
|
||||
}
|
||||
zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j].ce);
|
||||
|
||||
/* 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[j].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",
|
||||
ZSTR_VAL(cur_method_ref->method_name),
|
||||
ZSTR_VAL(cur_precedence->trait_method->ce->name),
|
||||
ZSTR_VAL(cur_precedence->trait_method->ce->name));
|
||||
}
|
||||
|
||||
zend_string_release_ex(class_name, 0);
|
||||
j++;
|
||||
"Inconsistent insteadof definition. "
|
||||
"The method %s is to be used from %s, but %s is also on the exclude list",
|
||||
ZSTR_VAL(cur_method_ref->method_name),
|
||||
ZSTR_VAL(trait->name),
|
||||
ZSTR_VAL(trait->name));
|
||||
}
|
||||
}
|
||||
zend_string_release_ex(lcname, 0);
|
||||
i++;
|
||||
}
|
||||
ce->trait_precedences = precedences;
|
||||
}
|
||||
|
||||
if (ce->trait_aliases) {
|
||||
i = 0;
|
||||
while (ce->trait_aliases[i]) {
|
||||
i++;
|
||||
}
|
||||
aliases = ecalloc(i, sizeof(zend_class_entry*));
|
||||
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))) {
|
||||
if (ce->trait_aliases[i]->trait_method.class_name) {
|
||||
cur_method_ref = &ce->trait_aliases[i]->trait_method;
|
||||
trait = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD);
|
||||
if (!trait) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
|
||||
}
|
||||
zend_check_trait_usage(ce, cur_method_ref->ce);
|
||||
zend_check_trait_usage(ce, trait);
|
||||
aliases[i] = trait;
|
||||
|
||||
/** And, ensure that the referenced method is resolvable, too. */
|
||||
lcname = zend_string_tolower(cur_method_ref->method_name);
|
||||
method_exists = zend_hash_exists(&cur_method_ref->ce->function_table,
|
||||
lcname);
|
||||
method_exists = zend_hash_exists(&trait->function_table, lcname);
|
||||
zend_string_release_ex(lcname, 0);
|
||||
|
||||
if (!method_exists) {
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(cur_method_ref->ce->name), ZSTR_VAL(cur_method_ref->method_name));
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name));
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
*exclude_tables_ptr = exclude_tables;
|
||||
*aliases_ptr = aliases;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
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_tolower(precedences[i]->trait_method->method_name);
|
||||
if (zend_hash_add_empty_element(exclude_table, lcname) == NULL) {
|
||||
zend_string_release_ex(lcname, 0);
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", ZSTR_VAL(precedences[i]->trait_method->method_name), ZSTR_VAL(trait->name));
|
||||
}
|
||||
zend_string_release_ex(lcname, 0);
|
||||
}
|
||||
++j;
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void zend_do_traits_method_binding(zend_class_entry *ce) /* {{{ */
|
||||
static void zend_do_traits_method_binding(zend_class_entry *ce, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
|
||||
{
|
||||
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;
|
||||
zend_trait_precedence **precedences;
|
||||
|
||||
/* TODO: revisit this start size, may be its not optimal */
|
||||
zend_hash_init_ex(&exclude_table, 8, NULL, NULL, 0, 0);
|
||||
|
||||
precedences = ce->trait_precedences;
|
||||
ce->trait_precedences = NULL;
|
||||
zend_traits_compile_exclude_table(&exclude_table, precedences, ce->traits[i]);
|
||||
|
||||
if (exclude_tables) {
|
||||
for (i = 0; i < ce->num_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);
|
||||
zend_traits_copy_functions(key, fn, ce, &overriden, exclude_tables[i], aliases);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
zend_hash_destroy(&exclude_table);
|
||||
ce->trait_precedences = precedences;
|
||||
} else {
|
||||
if (exclude_tables[i]) {
|
||||
zend_hash_destroy(exclude_tables[i]);
|
||||
FREE_HASHTABLE(exclude_tables[i]);
|
||||
exclude_tables[i] = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < ce->num_traits; i++) {
|
||||
ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->traits[i]->function_table, key, fn) {
|
||||
zend_traits_copy_functions(key, fn, ce, &overriden, NULL);
|
||||
zend_traits_copy_functions(key, fn, ce, &overriden, NULL, aliases);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
}
|
||||
}
|
||||
@@ -1509,17 +1508,6 @@ static void zend_do_traits_method_binding(zend_class_entry *ce) /* {{{ */
|
||||
zend_fixup_trait_method(fn, ce);
|
||||
} ZEND_HASH_FOREACH_END();
|
||||
|
||||
if (ce->trait_precedences) {
|
||||
i = 0;
|
||||
while (ce->trait_precedences[i]) {
|
||||
if (ce->trait_precedences[i]->exclude_from_classes) {
|
||||
efree(ce->trait_precedences[i]->exclude_from_classes);
|
||||
ce->trait_precedences[i]->exclude_from_classes = NULL;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (overriden) {
|
||||
zend_hash_destroy(overriden);
|
||||
FREE_HASHTABLE(overriden);
|
||||
@@ -1661,7 +1649,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce) /* {{{ */
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce) /* {{{ */
|
||||
static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce, zend_class_entry **aliases) /* {{{ */
|
||||
{
|
||||
int i = 0;
|
||||
zend_trait_alias* cur_alias;
|
||||
@@ -1672,13 +1660,13 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce)
|
||||
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 (!aliases[i]) {
|
||||
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",
|
||||
ZSTR_VAL(cur_alias->alias),
|
||||
ZSTR_VAL(cur_alias->trait_method->method_name));
|
||||
ZSTR_VAL(cur_alias->trait_method.method_name));
|
||||
} else {
|
||||
/** Here are two possible cases:
|
||||
1) this is an attempt to modifiy the visibility
|
||||
@@ -1689,18 +1677,18 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce)
|
||||
as in the case where alias is set. */
|
||||
|
||||
lc_method_name = zend_string_tolower(
|
||||
cur_alias->trait_method->method_name);
|
||||
cur_alias->trait_method.method_name);
|
||||
if (zend_hash_exists(&ce->function_table,
|
||||
lc_method_name)) {
|
||||
zend_string_release_ex(lc_method_name, 0);
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"The modifiers for the trait alias %s() need to be changed in the same statement in which the alias is defined. Error",
|
||||
ZSTR_VAL(cur_alias->trait_method->method_name));
|
||||
ZSTR_VAL(cur_alias->trait_method.method_name));
|
||||
} else {
|
||||
zend_string_release_ex(lc_method_name, 0);
|
||||
zend_error_noreturn(E_COMPILE_ERROR,
|
||||
"The modifiers of the trait method %s() are changed, but this method does not exist. Error",
|
||||
ZSTR_VAL(cur_alias->trait_method->method_name));
|
||||
ZSTR_VAL(cur_alias->trait_method.method_name));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1713,19 +1701,29 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce)
|
||||
|
||||
ZEND_API void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */
|
||||
{
|
||||
HashTable **exclude_tables;
|
||||
zend_class_entry **aliases;
|
||||
|
||||
if (ce->num_traits == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* complete initialization of trait strutures in ce */
|
||||
zend_traits_init_trait_structures(ce);
|
||||
zend_traits_init_trait_structures(ce, &exclude_tables, &aliases);
|
||||
|
||||
/* first care about all methods to be flattened into the class */
|
||||
zend_do_traits_method_binding(ce);
|
||||
zend_do_traits_method_binding(ce, exclude_tables, aliases);
|
||||
|
||||
/* Aliases which have not been applied indicate typos/bugs. */
|
||||
zend_do_check_for_inconsistent_traits_aliasing(ce);
|
||||
zend_do_check_for_inconsistent_traits_aliasing(ce, aliases);
|
||||
|
||||
if (aliases) {
|
||||
efree(aliases);
|
||||
}
|
||||
|
||||
if (exclude_tables) {
|
||||
efree(exclude_tables);
|
||||
}
|
||||
|
||||
/* then flatten the properties into it, to, mostly to notfiy developer about problems */
|
||||
zend_do_traits_property_binding(ce);
|
||||
|
||||
+11
-20
@@ -169,14 +169,11 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce)
|
||||
if (ce->trait_aliases) {
|
||||
size_t i = 0;
|
||||
while (ce->trait_aliases[i]) {
|
||||
if (ce->trait_aliases[i]->trait_method) {
|
||||
if (ce->trait_aliases[i]->trait_method->method_name) {
|
||||
zend_string_release_ex(ce->trait_aliases[i]->trait_method->method_name, 0);
|
||||
}
|
||||
if (ce->trait_aliases[i]->trait_method->class_name) {
|
||||
zend_string_release_ex(ce->trait_aliases[i]->trait_method->class_name, 0);
|
||||
}
|
||||
efree(ce->trait_aliases[i]->trait_method);
|
||||
if (ce->trait_aliases[i]->trait_method.method_name) {
|
||||
zend_string_release_ex(ce->trait_aliases[i]->trait_method.method_name, 0);
|
||||
}
|
||||
if (ce->trait_aliases[i]->trait_method.class_name) {
|
||||
zend_string_release_ex(ce->trait_aliases[i]->trait_method.class_name, 0);
|
||||
}
|
||||
|
||||
if (ce->trait_aliases[i]->alias) {
|
||||
@@ -191,21 +188,15 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce)
|
||||
}
|
||||
|
||||
if (ce->trait_precedences) {
|
||||
size_t i = 0;
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
while (ce->trait_precedences[i]) {
|
||||
zend_string_release_ex(ce->trait_precedences[i]->trait_method->method_name, 0);
|
||||
zend_string_release_ex(ce->trait_precedences[i]->trait_method->class_name, 0);
|
||||
efree(ce->trait_precedences[i]->trait_method);
|
||||
zend_string_release_ex(ce->trait_precedences[i]->trait_method.method_name, 0);
|
||||
zend_string_release_ex(ce->trait_precedences[i]->trait_method.class_name, 0);
|
||||
|
||||
if (ce->trait_precedences[i]->exclude_from_classes) {
|
||||
size_t j = 0;
|
||||
zend_trait_precedence *cur_precedence = ce->trait_precedences[i];
|
||||
while (cur_precedence->exclude_from_classes[j].class_name) {
|
||||
zend_string_release_ex(cur_precedence->exclude_from_classes[j].class_name, 0);
|
||||
j++;
|
||||
}
|
||||
efree(ce->trait_precedences[i]->exclude_from_classes);
|
||||
for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
|
||||
zend_string_release_ex(ce->trait_precedences[i]->exclude_class_names[j], 0);
|
||||
}
|
||||
efree(ce->trait_precedences[i]);
|
||||
i++;
|
||||
|
||||
@@ -437,8 +437,6 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
|
||||
while (ce->trait_aliases[i]) {
|
||||
trait_aliases[i] = emalloc(sizeof(zend_trait_alias));
|
||||
memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
|
||||
trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
|
||||
memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
|
||||
i++;
|
||||
}
|
||||
trait_aliases[i] = NULL;
|
||||
@@ -455,28 +453,8 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
|
||||
trait_precedences = emalloc(sizeof(zend_trait_precedence*) * (i + 1));
|
||||
i = 0;
|
||||
while (ce->trait_precedences[i]) {
|
||||
trait_precedences[i] = emalloc(sizeof(zend_trait_precedence));
|
||||
memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence));
|
||||
trait_precedences[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
|
||||
memcpy(trait_precedences[i]->trait_method, ce->trait_precedences[i]->trait_method, sizeof(zend_trait_method_reference));
|
||||
|
||||
if (trait_precedences[i]->exclude_from_classes) {
|
||||
zend_string **exclude_from_classes;
|
||||
int j = 0;
|
||||
|
||||
while (trait_precedences[i]->exclude_from_classes[j].class_name) {
|
||||
j++;
|
||||
}
|
||||
exclude_from_classes = emalloc(sizeof(zend_string*) * (j + 1));
|
||||
j = 0;
|
||||
while (trait_precedences[i]->exclude_from_classes[j].class_name) {
|
||||
exclude_from_classes[j] =
|
||||
trait_precedences[i]->exclude_from_classes[j].class_name;
|
||||
j++;
|
||||
}
|
||||
exclude_from_classes[j] = NULL;
|
||||
trait_precedences[i]->exclude_from_classes = (void*)exclude_from_classes;
|
||||
}
|
||||
trait_precedences[i] = emalloc(sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
|
||||
memcpy(trait_precedences[i], ce->trait_precedences[i], sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
|
||||
i++;
|
||||
}
|
||||
trait_precedences[i] = NULL;
|
||||
|
||||
@@ -648,19 +648,11 @@ static void zend_file_cache_serialize_class(zval *zv,
|
||||
q = *p;
|
||||
UNSERIALIZE_PTR(q);
|
||||
|
||||
if (q->trait_method) {
|
||||
zend_trait_method_reference *m;
|
||||
|
||||
SERIALIZE_PTR(q->trait_method);
|
||||
m = q->trait_method;
|
||||
UNSERIALIZE_PTR(m);
|
||||
|
||||
if (m->method_name) {
|
||||
SERIALIZE_STR(m->method_name);
|
||||
}
|
||||
if (m->class_name) {
|
||||
SERIALIZE_STR(m->class_name);
|
||||
}
|
||||
if (q->trait_method.method_name) {
|
||||
SERIALIZE_STR(q->trait_method.method_name);
|
||||
}
|
||||
if (q->trait_method.class_name) {
|
||||
SERIALIZE_STR(q->trait_method.class_name);
|
||||
}
|
||||
|
||||
if (q->alias) {
|
||||
@@ -672,6 +664,7 @@ static void zend_file_cache_serialize_class(zval *zv,
|
||||
|
||||
if (ce->trait_precedences) {
|
||||
zend_trait_precedence **p, *q;
|
||||
int j;
|
||||
|
||||
SERIALIZE_PTR(ce->trait_precedences);
|
||||
p = ce->trait_precedences;
|
||||
@@ -682,32 +675,15 @@ static void zend_file_cache_serialize_class(zval *zv,
|
||||
q = *p;
|
||||
UNSERIALIZE_PTR(q);
|
||||
|
||||
if (q->trait_method) {
|
||||
zend_trait_method_reference *m;
|
||||
|
||||
SERIALIZE_PTR(q->trait_method);
|
||||
m = q->trait_method;
|
||||
UNSERIALIZE_PTR(m);
|
||||
|
||||
if (m->method_name) {
|
||||
SERIALIZE_STR(m->method_name);
|
||||
}
|
||||
if (m->class_name) {
|
||||
SERIALIZE_STR(m->class_name);
|
||||
}
|
||||
if (q->trait_method.method_name) {
|
||||
SERIALIZE_STR(q->trait_method.method_name);
|
||||
}
|
||||
if (q->trait_method.class_name) {
|
||||
SERIALIZE_STR(q->trait_method.class_name);
|
||||
}
|
||||
|
||||
if (q->exclude_from_classes) {
|
||||
zend_string **s;
|
||||
|
||||
SERIALIZE_PTR(q->exclude_from_classes);
|
||||
s = (zend_string**)q->exclude_from_classes;
|
||||
UNSERIALIZE_PTR(s);
|
||||
|
||||
while (*s) {
|
||||
SERIALIZE_STR(*s);
|
||||
s++;
|
||||
}
|
||||
for (j = 0; j < q->num_excludes; j++) {
|
||||
SERIALIZE_STR(q->exclude_class_names[j]);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
@@ -1278,18 +1254,11 @@ static void zend_file_cache_unserialize_class(zval *zv,
|
||||
UNSERIALIZE_PTR(*p);
|
||||
q = *p;
|
||||
|
||||
if (q->trait_method) {
|
||||
zend_trait_method_reference *m;
|
||||
|
||||
UNSERIALIZE_PTR(q->trait_method);
|
||||
m = q->trait_method;
|
||||
|
||||
if (m->method_name) {
|
||||
UNSERIALIZE_STR(m->method_name);
|
||||
}
|
||||
if (m->class_name) {
|
||||
UNSERIALIZE_STR(m->class_name);
|
||||
}
|
||||
if (q->trait_method.method_name) {
|
||||
UNSERIALIZE_STR(q->trait_method.method_name);
|
||||
}
|
||||
if (q->trait_method.class_name) {
|
||||
UNSERIALIZE_STR(q->trait_method.class_name);
|
||||
}
|
||||
|
||||
if (q->alias) {
|
||||
@@ -1301,6 +1270,7 @@ static void zend_file_cache_unserialize_class(zval *zv,
|
||||
|
||||
if (ce->trait_precedences) {
|
||||
zend_trait_precedence **p, *q;
|
||||
int j;
|
||||
|
||||
UNSERIALIZE_PTR(ce->trait_precedences);
|
||||
p = ce->trait_precedences;
|
||||
@@ -1309,30 +1279,15 @@ static void zend_file_cache_unserialize_class(zval *zv,
|
||||
UNSERIALIZE_PTR(*p);
|
||||
q = *p;
|
||||
|
||||
if (q->trait_method) {
|
||||
zend_trait_method_reference *m;
|
||||
|
||||
UNSERIALIZE_PTR(q->trait_method);
|
||||
m = q->trait_method;
|
||||
|
||||
if (m->method_name) {
|
||||
UNSERIALIZE_STR(m->method_name);
|
||||
}
|
||||
if (m->class_name) {
|
||||
UNSERIALIZE_STR(m->class_name);
|
||||
}
|
||||
if (q->trait_method.method_name) {
|
||||
UNSERIALIZE_STR(q->trait_method.method_name);
|
||||
}
|
||||
if (q->trait_method.class_name) {
|
||||
UNSERIALIZE_STR(q->trait_method.class_name);
|
||||
}
|
||||
|
||||
if (q->exclude_from_classes) {
|
||||
zend_string **s;
|
||||
|
||||
UNSERIALIZE_PTR(q->exclude_from_classes);
|
||||
s = (zend_string**)q->exclude_from_classes;
|
||||
|
||||
while (*s) {
|
||||
UNSERIALIZE_STR(*s);
|
||||
s++;
|
||||
}
|
||||
for (j = 0; j < q->num_excludes; j++) {
|
||||
UNSERIALIZE_STR(q->exclude_class_names[j]);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
+11
-25
@@ -775,16 +775,11 @@ static void zend_persist_class_entry(zval *zv)
|
||||
if (ce->trait_aliases) {
|
||||
int i = 0;
|
||||
while (ce->trait_aliases[i]) {
|
||||
if (ce->trait_aliases[i]->trait_method) {
|
||||
if (ce->trait_aliases[i]->trait_method->method_name) {
|
||||
zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method->method_name);
|
||||
}
|
||||
if (ce->trait_aliases[i]->trait_method->class_name) {
|
||||
zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method->class_name);
|
||||
}
|
||||
ce->trait_aliases[i]->trait_method->ce = NULL;
|
||||
zend_accel_store(ce->trait_aliases[i]->trait_method,
|
||||
sizeof(zend_trait_method_reference));
|
||||
if (ce->trait_aliases[i]->trait_method.method_name) {
|
||||
zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method.method_name);
|
||||
}
|
||||
if (ce->trait_aliases[i]->trait_method.class_name) {
|
||||
zend_accel_store_interned_string(ce->trait_aliases[i]->trait_method.class_name);
|
||||
}
|
||||
|
||||
if (ce->trait_aliases[i]->alias) {
|
||||
@@ -800,26 +795,17 @@ static void zend_persist_class_entry(zval *zv)
|
||||
|
||||
if (ce->trait_precedences) {
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
while (ce->trait_precedences[i]) {
|
||||
zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method->method_name);
|
||||
zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method->class_name);
|
||||
ce->trait_precedences[i]->trait_method->ce = NULL;
|
||||
zend_accel_store(ce->trait_precedences[i]->trait_method,
|
||||
sizeof(zend_trait_method_reference));
|
||||
zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method.method_name);
|
||||
zend_accel_store_interned_string(ce->trait_precedences[i]->trait_method.class_name);
|
||||
|
||||
if (ce->trait_precedences[i]->exclude_from_classes) {
|
||||
int j = 0;
|
||||
|
||||
while (ce->trait_precedences[i]->exclude_from_classes[j].class_name) {
|
||||
zend_accel_store_interned_string(ce->trait_precedences[i]->exclude_from_classes[j].class_name);
|
||||
j++;
|
||||
}
|
||||
zend_accel_store(ce->trait_precedences[i]->exclude_from_classes,
|
||||
sizeof(zend_class_entry*) * (j + 1));
|
||||
for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
|
||||
zend_accel_store_interned_string(ce->trait_precedences[i]->exclude_class_names[j]);
|
||||
}
|
||||
|
||||
zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence));
|
||||
zend_accel_store(ce->trait_precedences[i], sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
|
||||
i++;
|
||||
}
|
||||
zend_accel_store(
|
||||
|
||||
@@ -345,14 +345,11 @@ static void zend_persist_class_entry_calc(zval *zv)
|
||||
if (ce->trait_aliases) {
|
||||
int i = 0;
|
||||
while (ce->trait_aliases[i]) {
|
||||
if (ce->trait_aliases[i]->trait_method) {
|
||||
if (ce->trait_aliases[i]->trait_method->method_name) {
|
||||
ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_method->method_name, 0);
|
||||
}
|
||||
if (ce->trait_aliases[i]->trait_method->class_name) {
|
||||
ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_method->class_name, 0);
|
||||
}
|
||||
ADD_SIZE(sizeof(zend_trait_method_reference));
|
||||
if (ce->trait_aliases[i]->trait_method.method_name) {
|
||||
ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_method.method_name, 0);
|
||||
}
|
||||
if (ce->trait_aliases[i]->trait_method.class_name) {
|
||||
ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_method.class_name, 0);
|
||||
}
|
||||
|
||||
if (ce->trait_aliases[i]->alias) {
|
||||
@@ -366,22 +363,16 @@ static void zend_persist_class_entry_calc(zval *zv)
|
||||
|
||||
if (ce->trait_precedences) {
|
||||
int i = 0;
|
||||
int j;
|
||||
|
||||
while (ce->trait_precedences[i]) {
|
||||
ADD_INTERNED_STRING(ce->trait_precedences[i]->trait_method->method_name, 0);
|
||||
ADD_INTERNED_STRING(ce->trait_precedences[i]->trait_method->class_name, 0);
|
||||
ADD_SIZE(sizeof(zend_trait_method_reference));
|
||||
ADD_INTERNED_STRING(ce->trait_precedences[i]->trait_method.method_name, 0);
|
||||
ADD_INTERNED_STRING(ce->trait_precedences[i]->trait_method.class_name, 0);
|
||||
|
||||
if (ce->trait_precedences[i]->exclude_from_classes) {
|
||||
int j = 0;
|
||||
|
||||
while (ce->trait_precedences[i]->exclude_from_classes[j].class_name) {
|
||||
ADD_INTERNED_STRING(ce->trait_precedences[i]->exclude_from_classes[j].class_name, 0);
|
||||
j++;
|
||||
}
|
||||
ADD_SIZE(sizeof(zend_class_entry*) * (j + 1));
|
||||
for (j = 0; j < ce->trait_precedences[i]->num_excludes; j++) {
|
||||
ADD_INTERNED_STRING(ce->trait_precedences[i]->exclude_class_names[j], 0);
|
||||
}
|
||||
ADD_SIZE(sizeof(zend_trait_precedence));
|
||||
ADD_SIZE(sizeof(zend_trait_precedence) + (ce->trait_precedences[i]->num_excludes - 1) * sizeof(zend_string*));
|
||||
i++;
|
||||
}
|
||||
ADD_SIZE(sizeof(zend_trait_precedence*) * (i + 1));
|
||||
|
||||
@@ -4939,12 +4939,12 @@ ZEND_METHOD(reflection_class, getTraitAliases)
|
||||
array_init(return_value);
|
||||
while (ce->trait_aliases[i]) {
|
||||
zend_string *mname;
|
||||
zend_trait_method_reference *cur_ref = ce->trait_aliases[i]->trait_method;
|
||||
zend_trait_method_reference *cur_ref = &ce->trait_aliases[i]->trait_method;
|
||||
|
||||
if (ce->trait_aliases[i]->alias) {
|
||||
|
||||
mname = zend_string_alloc(ZSTR_LEN(cur_ref->ce->name) + ZSTR_LEN(cur_ref->method_name) + 2, 0);
|
||||
snprintf(ZSTR_VAL(mname), ZSTR_LEN(mname) + 1, "%s::%s", ZSTR_VAL(cur_ref->ce->name), ZSTR_VAL(cur_ref->method_name));
|
||||
mname = zend_string_alloc(ZSTR_LEN(cur_ref->class_name) + ZSTR_LEN(cur_ref->method_name) + 2, 0);
|
||||
snprintf(ZSTR_VAL(mname), ZSTR_LEN(mname) + 1, "%s::%s", ZSTR_VAL(cur_ref->class_name), ZSTR_VAL(cur_ref->method_name));
|
||||
add_assoc_str_ex(return_value, ZSTR_VAL(ce->trait_aliases[i]->alias), ZSTR_LEN(ce->trait_aliases[i]->alias), mname);
|
||||
}
|
||||
i++;
|
||||
|
||||
Reference in New Issue
Block a user