php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62069 binding wrong traits if they have same name methods
Submitted: 2012-05-19 06:30 UTC Modified: 2020-03-10 15:24 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: laruence@php.net Assigned: nikic (profile)
Status: Closed Package: Scripting Engine problem
PHP Version: 5.4.3 OS:
Private report: No CVE-ID: None
 [2012-05-19 06:30 UTC] laruence@php.net
Description:
------------
if a function binding more than two traits and they have same method name, the 
result is wrong.

Test script:
---------------
<?php
trait T1 {
    public function func() {
        echo "From T1\n";
    }
}

trait T2 {
    public function func() {
        echo "From T2\n";
    }
}

class Bar {
    public function func() {
        echo "From Bar\n";
    }
    use T1 {
        func as f1;
    }
    use T2 {
        func as f2;
    }
}

$b = new Bar();
$b->f2();

Expected result:
----------------
From T2

Actual result:
--------------
From T1

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-05-19 06:40 UTC] laruence@php.net
-Assigned To: +Assigned To: dmitry
 [2012-05-19 06:40 UTC] laruence@php.net
Hi, dmitry, could you please look at this? thanks

the problem occurrs in zend_traits_merge_functions. in that function, it will 
unique the trait methods name. 

the fix will be a big change, since we should re-implemention the whole merge 
functions mechanism, maybe add the tarit name as a suffix to method name.

thanks
 [2012-05-19 06:44 UTC] laruence@php.net
and if the class have no own func method defination, the result will be:
<?php
trait T1 {
    public function func() {
        echo "From T1\n";
    }
}

trait T2 {
    public function func() {
        echo "From T2\n";
    }
}

class Bar {
    use T1 {
        func as f1;
    }
    use T2 {
        func as f2;
    }
}

PHP Fatal error:  Trait method func has not been applied, because there are 
collisions with other trait methods on Bar in /tmp/1.php on line 21

this should also be a bug. thanks :)
 [2012-05-19 13:55 UTC] gron@php.net
Hi Laruence:

The first example is a bug, indeed.

Why is the second example a bug?
To me it looks like the perfectly intended traits semantics, no?
 [2012-05-20 04:53 UTC] laruence@php.net
@gron, the second example is try to description another bug of the first example, 
that is , if the class have a own defined same name as trait, no fatal error 
occurred, :)
 [2012-05-20 07:19 UTC] gron@php.net
@laruence it is intended behavior to have no fatal error in this case.
The method of the class has precedence and solves the conflict explicitly.

If the class does not define a method with that name, the conflict remains 
unsolved, and you will get an error.
 [2012-05-20 08:41 UTC] laruence@php.net
@gron, oh, I see, thanks.
 [2012-05-21 12:15 UTC] dmitry@php.net
I think this is not a bug (at least according to documentation http://php.net/manual/en/language.oop5.traits.php).

The alias defined using "as" statement adds an *additional* name but doesn't resolve the conflict.

The proper test would be:

<?php
trait T1 {
    public function func() {
        echo "From T1\n";
    }
}

trait T2 {
    public function func() {
        echo "From T2\n";
    }
}

class Bar {
    use T1, T2 {
        T1::func insteadof T2;
        T1::func as f1;
        T2::func as f2;
    }
}
$x = new Bar();
$x->f1();
$x->f2();
$x->func();
Expected result:
----------------
From T1
From T2
From T1

It's passed fine, however the whole traits concept is messed and not intuitive.
 [2012-05-21 13:55 UTC] dmitry@php.net
-Status: Assigned +Status: Feedback
 [2012-05-21 22:13 UTC] gron@php.net
Dmitry, there is nothing wrong with Laruence original example.
Except, that it indeed points out a bug.
 [2012-05-22 02:24 UTC] laruence@php.net
-Status: Feedback +Status: Open
 [2012-05-22 02:24 UTC] laruence@php.net
@dmitry, as a common guess, the second should have a high priority, I think it 
should be a bug ... :)
 [2012-05-22 06:25 UTC] dmitry@php.net
I would say it's not an implementation bug, but design mistake that allows ambiguous syntax.

The problem that class may include several "use" statements, each statement may refer several traits and each such statement may be followed by a block with alias declarations. However, all these blocks have equal rights and it doesn't mean which traits were used in "use" statement before.

So the second example is treated as:

use T1, T2 {
  func as f1;
  func as f2;
}

To refer to the proper traits methods need to be qualified

use T1, T2 {
  T1::func as f1;
  T2::func as f2;
}


I'll try to take a look, if it's possible to fix it, but I don't think it's possible to do it in 5.4 (without binary compatibility break).
 [2012-05-22 07:17 UTC] gron@php.net
Sorry, I don't have the time to look into the code.

But I guess, I compiled the 'as' of 'use T1 { func as f1; }' without the 
information of being related to T1.
If the compilation step would automatically add the T1 to 'as' for 'use' 
statements with only a single trait, this particular bug here would be solved.

It does not solve the ambiguity however.
Not sure what to do with that.

I still think it is convenient, to be able to leave out the T1:: infront of the 
method name.
 [2012-05-22 08:38 UTC] dmitry@php.net
I agree that syntax "use T1 {func as f1;}" where "func" belong to another trait looks unnatural, and it's better to interpret "func" as "T1::func" in this case, but it won't solve the problem in general, because it's possible to refer few traits in a single "use" statement.
 [2017-10-24 07:58 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: dmitry +Assigned To:
 [2020-03-03 13:31 UTC] nikic@php.net
-Assigned To: +Assigned To: nikic
 [2020-03-10 15:24 UTC] nikic@php.net
-Status: Assigned +Status: Closed
 [2020-03-10 15:24 UTC] nikic@php.net
Fixed by https://github.com/php/php-src/commit/fff5771cccaca49565c90349320f3c06cbe19328 in master. The code will now throw a fatal error and require explicit disambiguation using T1::func or T2::func.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 03:01:29 2024 UTC