Skip to content

Commit e141e08

Browse files
committed
Fix #74872 - Disambiguate the source of a trait
1 parent 5d21a15 commit e141e08

File tree

9 files changed

+173
-17
lines changed

9 files changed

+173
-17
lines changed

Zend/tests/traits/bug74872.phpt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
Bug #74872 (First Trait wins on importing same methods with diff alias)
3+
--FILE--
4+
<?php
5+
6+
trait Trait1
7+
{
8+
public function init()
9+
{
10+
echo("Trait1 - init\n");
11+
}
12+
}
13+
14+
trait Trait2
15+
{
16+
public function init()
17+
{
18+
echo("Trait2 - init\n");
19+
}
20+
}
21+
22+
class Test
23+
{
24+
use Trait1 {
25+
init as public method1trait1;
26+
}
27+
28+
use Trait2 {
29+
init as public method1trait2;
30+
}
31+
32+
final public function __construct()
33+
{
34+
$this->init();
35+
$this->method1trait1();
36+
$this->method1trait2();
37+
}
38+
39+
public function init()
40+
{
41+
echo("Test - init\n");
42+
}
43+
}
44+
45+
$test = new Test();
46+
47+
$reflection = new ReflectionClass( $test );
48+
49+
foreach($reflection->getTraitAliases() as $k => $v)
50+
{
51+
echo $k.' => '.$v."\n";
52+
}
53+
?>
54+
--EXPECT--
55+
Test - init
56+
Trait1 - init
57+
Trait2 - init
58+
method1trait1 => Trait1::init
59+
method1trait2 => Trait2::init

Zend/zend.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ typedef struct _zend_trait_alias {
110110
* modifiers to be set on trait method
111111
*/
112112
uint32_t modifiers;
113+
114+
/**
115+
* names of the traits for this alias
116+
*/
117+
zend_string **trait_names;
113118
} zend_trait_alias;
114119

115120
struct _zend_class_entry {

Zend/zend_compile.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6150,7 +6150,7 @@ static void zend_compile_trait_precedence(zend_ast *ast) /* {{{ */
61506150
}
61516151
/* }}} */
61526152

6153-
static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
6153+
static void zend_compile_trait_alias(zend_ast *ast, zend_ast *traits_ast) /* {{{ */
61546154
{
61556155
zend_ast *method_ref_ast = ast->child[0];
61566156
zend_ast *alias_ast = ast->child[1];
@@ -6169,6 +6169,11 @@ static void zend_compile_trait_alias(zend_ast *ast) /* {{{ */
61696169
alias = emalloc(sizeof(zend_trait_alias));
61706170
alias->trait_method = zend_compile_method_ref(method_ref_ast);
61716171
alias->modifiers = modifiers;
6172+
if (!alias->trait_method->class_name) {
6173+
alias->trait_names = zend_compile_name_list(traits_ast);
6174+
} else {
6175+
alias->trait_names = NULL;
6176+
}
61726177

61736178
if (alias_ast) {
61746179
alias->alias = zend_string_copy(zend_ast_get_str(alias_ast));
@@ -6227,7 +6232,7 @@ void zend_compile_use_trait(zend_ast *ast) /* {{{ */
62276232
zend_compile_trait_precedence(adaptation_ast);
62286233
break;
62296234
case ZEND_AST_TRAIT_ALIAS:
6230-
zend_compile_trait_alias(adaptation_ast);
6235+
zend_compile_trait_alias(adaptation_ast, ast->child[0]);
62316236
break;
62326237
EMPTY_SWITCH_DEFAULT_CASE()
62336238
}

Zend/zend_inheritance.c

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,7 +1245,7 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
12451245
zend_string *lcname;
12461246
zend_function fn_copy;
12471247

1248-
/* apply aliases which are qualified with a class name, there should not be any ambiguity */
1248+
/* aliases which are qualified with a class name won't have any ambiguity. method names try to match with alias->trait_names */
12491249
if (ce->trait_aliases) {
12501250
alias_ptr = ce->trait_aliases;
12511251
alias = *alias_ptr;
@@ -1255,20 +1255,38 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
12551255
&& (!alias->trait_method->ce || fn->common.scope == alias->trait_method->ce)
12561256
&& ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname)
12571257
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
1258-
fn_copy = *fn;
12591258

1260-
/* if it is 0, no modifieres has been changed */
1261-
if (alias->modifiers) {
1262-
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1259+
if (alias->trait_names) {
1260+
size_t i = 0;
1261+
while (alias->trait_names[i]) {
1262+
if (zend_binary_strcasecmp(
1263+
ZSTR_VAL(fn->common.scope->name),
1264+
ZSTR_LEN(fn->common.scope->name),
1265+
ZSTR_VAL(alias->trait_names[i]),
1266+
ZSTR_LEN(alias->trait_names[i])) == 0) {
1267+
1268+
alias->trait_method->class_name = alias->trait_names[i];
1269+
}
1270+
i++;
1271+
}
12631272
}
12641273

1265-
lcname = zend_string_tolower(alias->alias);
1266-
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overriden);
1267-
zend_string_release(lcname);
1274+
if (alias->trait_method->ce || alias->trait_method->class_name) {
1275+
fn_copy = *fn;
1276+
1277+
/* if it is 0, no modifiers have been changed */
1278+
if (alias->modifiers) {
1279+
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1280+
}
1281+
1282+
lcname = zend_string_tolower(alias->alias);
1283+
zend_add_trait_method(ce, ZSTR_VAL(alias->alias), lcname, &fn_copy, overriden);
1284+
zend_string_release(lcname);
12681285

1269-
/* Record the trait from which this alias was resolved. */
1270-
if (!alias->trait_method->ce) {
1271-
alias->trait_method->ce = fn->common.scope;
1286+
/* Record the trait from which this alias was resolved. */
1287+
if (!alias->trait_method->ce) {
1288+
alias->trait_method->ce = fn->common.scope;
1289+
}
12721290
}
12731291
}
12741292
alias_ptr++;
@@ -1292,11 +1310,28 @@ static int zend_traits_copy_functions(zend_string *fnname, zend_function *fn, ze
12921310
&& (ZSTR_LEN(alias->trait_method->method_name) == ZSTR_LEN(fnname))
12931311
&& (zend_binary_strcasecmp(ZSTR_VAL(alias->trait_method->method_name), ZSTR_LEN(alias->trait_method->method_name), ZSTR_VAL(fnname), ZSTR_LEN(fnname)) == 0)) {
12941312

1295-
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1313+
if (alias->trait_names) {
1314+
size_t i = 0;
1315+
while (alias->trait_names[i]) {
1316+
if (zend_binary_strcasecmp(
1317+
ZSTR_VAL(fn->common.scope->name),
1318+
ZSTR_LEN(fn->common.scope->name),
1319+
ZSTR_VAL(alias->trait_names[i]),
1320+
ZSTR_LEN(alias->trait_names[i])) == 0) {
12961321

1297-
/** Record the trait from which this alias was resolved. */
1298-
if (!alias->trait_method->ce) {
1299-
alias->trait_method->ce = fn->common.scope;
1322+
alias->trait_method->class_name = alias->trait_names[i];
1323+
}
1324+
i++;
1325+
}
1326+
}
1327+
1328+
if (alias->trait_method->ce || alias->trait_method->class_name) {
1329+
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
1330+
1331+
/** Record the trait from which this alias was resolved. */
1332+
if (!alias->trait_method->ce) {
1333+
alias->trait_method->ce = fn->common.scope;
1334+
}
13001335
}
13011336
}
13021337
alias_ptr++;

Zend/zend_opcode.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,16 @@ void _destroy_zend_class_traits_info(zend_class_entry *ce)
211211
zend_string_release(ce->trait_aliases[i]->alias);
212212
}
213213

214+
if (ce->trait_aliases[i]->trait_names) {
215+
size_t j = 0;
216+
while (ce->trait_aliases[i]->trait_names[j]) {
217+
zend_string_release(ce->trait_aliases[i]->trait_names[j]);
218+
j++;
219+
}
220+
221+
efree(ce->trait_aliases[i]->trait_names);
222+
}
223+
214224
efree(ce->trait_aliases[i]);
215225
i++;
216226
}

ext/opcache/zend_accelerator_util_funcs.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ static void zend_class_copy_ctor(zend_class_entry **pce)
425425
memcpy(trait_aliases[i], ce->trait_aliases[i], sizeof(zend_trait_alias));
426426
trait_aliases[i]->trait_method = emalloc(sizeof(zend_trait_method_reference));
427427
memcpy(trait_aliases[i]->trait_method, ce->trait_aliases[i]->trait_method, sizeof(zend_trait_method_reference));
428+
trait_aliases[i]->trait_names = ce->trait_aliases[i]->trait_names;
428429
i++;
429430
}
430431
trait_aliases[i] = NULL;

ext/opcache/zend_file_cache.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,19 @@ static void zend_file_cache_serialize_class(zval *zv,
644644
}
645645
}
646646

647+
if (q->trait_names) {
648+
zend_string **r;
649+
650+
SERIALIZE_PTR(q->trait_names);
651+
r = q->trait_names;
652+
UNSERIALIZE_PTR(r);
653+
654+
while (*r) {
655+
SERIALIZE_STR(*r);
656+
r++;
657+
}
658+
}
659+
647660
if (q->alias) {
648661
SERIALIZE_STR(q->alias);
649662
}
@@ -1278,6 +1291,18 @@ static void zend_file_cache_unserialize_class(zval *zv,
12781291
}
12791292
}
12801293

1294+
if (q->trait_names) {
1295+
zend_string **r;
1296+
1297+
UNSERIALIZE_PTR(q->trait_names);
1298+
r = q->trait_names;
1299+
1300+
while (*r) {
1301+
UNSERIALIZE_STR(*r);
1302+
r++;
1303+
}
1304+
}
1305+
12811306
if (q->alias) {
12821307
UNSERIALIZE_STR(q->alias);
12831308
}

ext/opcache/zend_persist.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,14 @@ static void zend_persist_class_entry(zval *zv)
742742
sizeof(zend_trait_method_reference));
743743
}
744744

745+
if (ce->trait_aliases[i]->trait_names) {
746+
int j = 0;
747+
while (ce->trait_aliases[i]->trait_names[j]) {
748+
zend_accel_store_interned_string(ce->trait_aliases[i]->trait_names[j]);
749+
j++;
750+
}
751+
}
752+
745753
if (ce->trait_aliases[i]->alias) {
746754
zend_accel_store_interned_string(ce->trait_aliases[i]->alias);
747755
}

ext/opcache/zend_persist_calc.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,14 @@ static void zend_persist_class_entry_calc(zval *zv)
356356
ADD_SIZE(sizeof(zend_trait_method_reference));
357357
}
358358

359+
if (ce->trait_aliases[i]->trait_names) {
360+
int j = 0;
361+
while (ce->trait_aliases[i]->trait_names[j]) {
362+
ADD_INTERNED_STRING(ce->trait_aliases[i]->trait_names[j], 0);
363+
j++;
364+
}
365+
}
366+
359367
if (ce->trait_aliases[i]->alias) {
360368
ADD_INTERNED_STRING(ce->trait_aliases[i]->alias, 0);
361369
}

0 commit comments

Comments
 (0)