php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #63911 Ignore conflicting trait methods originationg from identical sub traits
Submitted: 2013-01-05 18:27 UTC Modified: 2017-11-22 17:11 UTC
Votes:47
Avg. Score:4.6 ± 0.7
Reproduced:47 of 47 (100.0%)
Same Version:10 (21.3%)
Same OS:13 (27.7%)
From: bitluni at bitluni dot net Assigned: pmmaga (profile)
Status: Closed Package: Class/Object related
PHP Version: 5.6.9 OS: *
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: bitluni at bitluni dot net
New email:
PHP Version: OS:

 

 [2013-01-05 18:27 UTC] bitluni at bitluni dot net
Description:
------------
When extracting traits I would like to extract some general functions into sub traits and 'use' them in the traits where needed.
But when I compose a class out of multiple traits with sub traits I have to do obsolete statements regardless if the colliding methods originate from same sub trait.

Just add a check if a method collides with itself

Test script:
---------------
trait A
{
    public function a(){}
}
trait B
{
    use A;
}
trait C
{
    use A;
}
class D
{
    use B, C;
}

Actual result:
--------------
Fatal error: Trait method a has not been applied, because there are collisions with other trait methods on D in

Patches

Pull Requests

Pull requests:

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-01-05 18:39 UTC] bitluni at bitluni dot net
same issue for properties
 [2013-01-06 02:36 UTC] necktrox at gmail dot com
# from http://php.net/manual/de/language.oop5.traits.php

trait A {
    public function smallTalk() {
        echo 'a';
    }
    public function bigTalk() {
        echo 'A';
    }
}

trait B {
    public function smallTalk() {
        echo 'b';
    }
    public function bigTalk() {
        echo 'B';
    }
}

class Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}
 [2013-01-06 10:31 UTC] bitluni at bitluni dot net
@necktrox

I know there is 'insteadof' but see my example, there is just one function implemented yet still I get collision error. The traits are just usable very flat at the moment. If you have an hirachical stucture of traits like I do, you have to do potentally exponetial count of 'insteadof's in the top level class even there's not one dublicate function implemented.
 [2013-05-03 10:26 UTC] simon at simon dot geek dot nz
This is still occurring with PHP 5.5, commit 
cbe2870b72c4cfdb5c295e83c88d7cff5c39e396 (Fri May 3 12:25:49 2013 +0400).

Not being able to use multiple traits that have the same trait somewhere in their 
composition trees is a rather major limitation of the trait system.
 [2013-09-15 17:23 UTC] heruan at aldu dot net
insteadOf in this case is just a workaround, since there is nothing to 'use 
instead of' something else because here there is a property/method conflicting 
with its very self!
And BTW insteadOf cannot be used as a workaround with properties.
 [2013-09-19 09:17 UTC] gron@php.net
-Status: Open +Status: Verified -Type: Feature/Change Request +Type: Bug
 [2013-09-19 09:17 UTC] gron@php.net
This is indeed a bug. Unfortunately, this case slipped and did not get tested. It 
is a perfectly valid usecase, and should not require the use of insteadof at all.

Best regards
Stefan
 [2013-12-07 08:31 UTC] gaetaneislockedoutof at gmail dot com
I have this issue. It makes me very sad :'(

Windows 7 Home Premium Edition Service Pack 1, 64bit
PHP 5.5.6 / Apache/2.4.7 (Win32)
 [2014-10-29 16:08 UTC] jpauli@php.net
Can someone explain me what you expect as a result ?

For me, this is the right behavior, the engine has no way of differenciating between B::a() and C::A() , you have to help it using 'insteadof'
 [2014-10-29 17:15 UTC] gaetane dot le dot grange at gmail dot com
I went into some detail here: http://stackoverflow.com/questions/20382202/php-trait-method-conflicts-trait-inheritance-and-trait-hierarchies
 [2014-10-29 19:30 UTC] keithdavis at solidtechservice dot com
I think the point here is that if I use the same trait twice because I use a trait that uses an already used trait, it's the SAME method included twice.
 [2014-12-22 21:10 UTC] mw dot wanrooij at vodafonevast dot nl
In my humble opinion, a solution/improvement would be that precedence order should not only be appliccable to classes, but also to traits.

To expand on the given example at the start of this topic, when:
trait A
{
    public function a(){}
    public function b(){}
    public function c(){}
    public function z(){}
}
trait B
{
    use A;
}
trait C
{
    use A;
}
class D
{
    use B, C;
}
The expected result here would be that methods in trait C override methods in trait B, unless explicitly specified using the insteadof operator.

Shortened example using the insteadof operator:
class D
{
    use B;
    use C {
        B::a insteadof C;
    }
}
Here, the expected results would be that methods in trait C override methods in trait B, except for method B::a() which is explicitly defined to be used instead of C::a()

If one would change which methods would override other methods, one would simply change the precedence other, as with the example:
class D
{
    use C;
    use B {
        C::a insteadof B;
    }
}
Here, the expected results would be that methods in trait B override methods in trait C, except for method C::a() which is explicitly defined to be used instead of B::a()

Am I making sense?
 [2014-12-24 05:15 UTC] keithdavis at solidtechservice dot com
I suppose that would work, but that does still divert from the actual issue here - that there is nothing to "override", as it's the same trait being used twice.
 [2015-03-17 15:02 UTC] paul at edunation dot co dot uk
Fixing this issue could make traits a far more useful composition tool! (and avoid countless insteadof statements)

If tampering with the "use" statement is problematic, could an explicit "use_once" statement not add a simple, per-class usage check for a given trait?
 [2015-06-09 14:12 UTC] cmb@php.net
-Operating System: debian +Operating System: * -PHP Version: 5.4.10 +PHP Version: 5.6.9 -Assigned To: +Assigned To: gron
 [2015-06-09 14:12 UTC] cmb@php.net
I would assume that a use statement simply injects the members of
the trait into the lexically current class/trait. So B and C in
the test script of the OP have separate a() methods, which leads
to a conflict when both traits are used in D.

The section "The Flattening Property" in the respective RFC[1]
supports this assumption:

| Traits are only entities of the literal code written in your
| source files. There is no notion about Traits at runtime. They
| are used to group methods and reuse code and are totally
| flattened into the classes composed from them. It is almost like
| a language supported and failsafe copy'n'paste mechanism to
| build classes.

The section "Traits Composed from Traits"[2] furthermore states:

> Since Traits are fully flattened away at compile time it is
> possible to use Traits to compose Traits without any additional
> impact on the semantics.

According to that information I would say the behavior is to be
expected, and as such is not a bug, but rather needs to be
documented in the PHP manual.

As gron stated otherwise, I'm assigning to him. Stefan, can you
please have a look at this issue?

See also <http://3v4l.org/RkYH5>.

[1] <https://wiki.php.net/rfc/horizontalreuse#the_flattening_property>
[2] <https://wiki.php.net/rfc/horizontalreuse#traits_composed_from_traits>
 [2015-12-12 15:44 UTC] serovov at gmail dot com
I would like to add another test case to this issue. It should handle same methods not only from sub-traits but also from current class.

Thanks!

<?php

trait helper {
    public function helper() {}
}


trait util_useful {
    use helper;
    public function do_something_useful() {$this->helper(); return 'useful';}
}

trait util_useless {
    use helper;
    public function do_something_useless() {$this->helper();  return 'useless';}
}

class utils {
    use helper;
    use util_useful;
    use util_useless;

    public function use_helper() { $this->helper();}
}

$ob = new utils();

echo $ob->do_something_useful(), "\n";
echo $ob->do_something_useless(), "\n";
echo $ob->use_helper(), "\n";

?>
 [2017-09-04 11:04 UTC] nicolas dot giraud dot dev at gmail dot com
I experiment the same issue here and it is very unpleasant.
https://3v4l.org/nnvOK

Plus, the error message is frustrating as it tells there are collisions while there are not! :(
 [2017-10-24 05:22 UTC] kalle@php.net
-Status: Verified +Status: Assigned
 [2017-10-24 07:05 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: gron +Assigned To:
 [2017-11-22 17:11 UTC] pmmaga@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: pmmaga
 [2017-11-22 17:11 UTC] pmmaga@php.net
The fix for this bug has been committed.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.

 For Windows:

http://windows.php.net/snapshots/
 
Thank you for the report, and for helping us make PHP better.

Fixed with commit: http://git.php.net/?p=php-src.git;a=commit;h=179ed6e43d9703fe6bdaa286aec79f7e131a8ab0
 [2017-11-24 18:10 UTC] keithdavis at solidtechservice dot com
I could kiss you!
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Mon Dec 09 07:01:27 2024 UTC