# 5.4a2 trait attribute name conflict resolution

- Thread: https://externals.io/message/54129
- Original archive: https://news-web.php.net/php.internals/54129
- Started by Alex Howansky on 2011-07-22T15:17:48+00:00
- Messages: 18
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #54129 — Alex Howansky — 2011-07-22T15:17:48+00:00

URL: https://externals.io/message/54129#54129

Hello folks,

I've just grabbed 5.4a2 to play with traits. I've found some behaviour 
which I'm not sure is a bug, an inconsistency, or a design decision.

Consider a trait and a class that implements it but also overrides both 
a trait method and a trait attribute:

trait foo
{
      public $zoo = 'foo::zoo';
      public function bar()
      {
          echo "in foo::bar\n";
      }
}

class baz
{
      use foo;
      public $zoo = 'baz::zoo';
      public function bar()
      {
          echo "in baz::bar\n";
      }
}

$obj = new baz();
$obj->bar();
echo $obj->zoo, "\n";

We get:

in baz::bar
foo::zoo

It seems this is not correct and that it should be:

in baz::bar
baz::zoo

The traits RFC pretty clearly states that if a class method conflicts 
with a trait method then the trait method will be ignored, which is 
what's happening, but it says nothing about what happens to attributes 
in that same condition. Is this a bug?

Thanks,

-- 
Alex Howansky

---

## #54131 — Richard Quadling — 2011-07-22T15:40:51+00:00

URL: https://externals.io/message/54129#54131 · In reply to: #54129

>
> Hello folks,
>
> I've just grabbed 5.4a2 to play with traits. I've found some behaviour which
> I'm not sure is a bug, an inconsistency, or a design decision.
>
> Consider a trait and a class that implements it but also overrides both a
> trait method and a trait attribute:
>
> trait foo
> {
>     public $zoo = 'foo::zoo';
>     public function bar()
>     {
>         echo "in foo::bar\n";
>     }
> }
>
> class baz
> {
>     use foo;
>     public $zoo = 'baz::zoo';
>     public function bar()
>     {
>         echo "in baz::bar\n";
>     }
> }
>
> $obj = new baz();
> $obj->bar();
> echo $obj->zoo, "\n";
>
> We get:
>
> in baz::bar
> foo::zoo
>
> It seems this is not correct and that it should be:
>
> in baz::bar
> baz::zoo
>
> The traits RFC pretty clearly states that if a class method conflicts with a
> trait method then the trait method will be ignored, which is what's
> happening, but it says nothing about what happens to attributes in that same
> condition. Is this a bug?
>
> Thanks,
>
> --
> Alex Howansky
>
>

In my limited understanding, a trait is sort of composited at compile
time (ish). As properties are dynamic (ish), they will overwrite. Just
like an inherited class will overwrite public properties in their
parent class.

-- 
Richard Quadling
Twitter : EE : Zend : PHPDoc
@RQuadling : e-e.com/M_248814.html : bit.ly/9O8vFY : bit.ly/lFnVea

---

## #54130 — Anthony Ferrara — 2011-07-22T15:46:46+00:00

URL: https://externals.io/message/54129#54130 · In reply to: #54129

I was under the impression that traits were not supposed to have
properties at all:

From the RFC:
Since Traits do not contain any state/properties, there is a need to
describe the requirements a Trait will rely on. In PHP it would be
possible to utilize the dynamic language features, but it is a common
practice to give this requirements explicitly. This is possible with
abstract methods like it is used for abstract classes.

Is the support for properties the bug perhaps?

Anthony


>
> Hello folks,
>
> I've just grabbed 5.4a2 to play with traits. I've found some behaviour which
> I'm not sure is a bug, an inconsistency, or a design decision.
>
> Consider a trait and a class that implements it but also overrides both a
> trait method and a trait attribute:
>
> trait foo
> {
>     public $zoo = 'foo::zoo';
>     public function bar()
>     {
>         echo "in foo::bar\n";
>     }
> }
>
> class baz
> {
>     use foo;
>     public $zoo = 'baz::zoo';
>     public function bar()
>     {
>         echo "in baz::bar\n";
>     }
> }
>
> $obj = new baz();
> $obj->bar();
> echo $obj->zoo, "\n";
>
> We get:
>
> in baz::bar
> foo::zoo
>
> It seems this is not correct and that it should be:
>
> in baz::bar
> baz::zoo
>
> The traits RFC pretty clearly states that if a class method conflicts with a
> trait method then the trait method will be ignored, which is what's
> happening, but it says nothing about what happens to attributes in that same
> condition. Is this a bug?
>
> Thanks,
>
> --
> Alex Howansky

---

## #54134 — Michael Stowe — 2011-07-22T16:12:07+00:00

URL: https://externals.io/message/54129#54134 · In reply to: #54131

Didn't send to list the first time, please accept my apologies if you
received this twice  - Thanks

That makes sense if it would overwrite the methods as well, but otherwise it
seems like it provides inconsistent functionality.  Perhaps I'm wrong as
likewise I have a very limited understanding here.

- Mike



-- Past Conversation ---
---------------------------------
In my limited understanding, a trait is sort of composited at compile
time (ish). As properties are dynamic (ish), they will overwrite. Just
like an inherited class will overwrite public properties in their
parent class.

Richard

---------------------------------

I was under the impression that traits were not supposed to have
properties at all:

From the RFC:
Since Traits do not contain any state/properties, there is a need to
describe the requirements a Trait will rely on. In PHP it would be
possible to utilize the dynamic language features, but it is a common
practice to give this requirements explicitly. This is possible with
abstract methods like it is used for abstract classes.

Is the support for properties the bug perhaps?

Anthony


---------------------------------


Hello folks,

I've just grabbed 5.4a2 to play with traits. I've found some behaviour which
I'm not sure is a bug, an inconsistency, or a design decision.

Consider a trait and a class that implements it but also overrides both a
trait method and a trait attribute:

trait foo
{
    public $zoo = 'foo::zoo';
    public function bar()
    {
        echo "in foo::bar\n";
    }
}

class baz
{
    use foo;
    public $zoo = 'baz::zoo';
    public function bar()
    {
        echo "in baz::bar\n";
    }
}

$obj = new baz();
$obj->bar();
echo $obj->zoo, "\n";

We get:

in baz::bar
foo::zoo

It seems this is not correct and that it should be:

in baz::bar
baz::zoo

The traits RFC pretty clearly states that if a class method conflicts with a
trait method then the trait method will be ignored, which is what's
happening, but it says nothing about what happens to attributes in that same
condition. Is this a bug?

Alex

---

## #54133 — Alex Howansky — 2011-07-22T16:12:20+00:00

URL: https://externals.io/message/54129#54133

> That makes sense if it would overwrite the methods as well, but
> otherwise it seems like it provides inconsistent functionality.

Exactly. At the least, it's inconsistent. If it's a bug, then it seems 
the question becomes:

Is the bug this:

"Properties defined in a trait should be overridden by same-named 
properties defined in a class that use the trait."

Or (as pointed out by Anthony) this:

"You shouldn't be able to define properties in a trait."

-- 
Alex Howansky

---

## #54136 — Adam Harvey — 2011-07-22T16:18:27+00:00

URL: https://externals.io/message/54129#54136 · In reply to: #54133

>
> > […]
>
> Exactly. At the least, it's inconsistent. If it's a bug, then it seems the
> question becomes:
>
> Is the bug this:
>
> "Properties defined in a trait should be overridden by same-named properties
> defined in a class that use the trait."
>
> Or (as pointed out by Anthony) this:
>
> "You shouldn't be able to define properties in a trait."

Traits definitely need to be able to support properties, IMO, so I'd
say that the first behaviour just needs to be documented (and
potentially a notice added). Either the trait or the class is going to
have its property overwritten, so we should pick which definition wins
and go from there.

Adam

---

## #54137 — Michael Stowe — 2011-07-22T16:22:38+00:00

URL: https://externals.io/message/54129#54137 · In reply to: #54136

I agree with Adam, I think it would be nice to let the trait contain its own
properties which can then be overwritten by the class properties.

This way we could include default properties that the trait may be dependent
on, while providing the opportunity to override individual properties to
provide a specific reaction for the class the trait is used in.

Just curious, if the trait property is set to private what happens?

- Mike





> 
> > […]
> the
> > […]
> properties
> > […]
>
> Traits definitely need to be able to support properties, IMO, so I'd
> say that the first behaviour just needs to be documented (and
> potentially a notice added). Either the trait or the class is going to
> have its property overwritten, so we should pick which definition wins
> and go from there.
>
> Adam
>
>

-- 
-----------------------

"My command is this: Love each other as I
have loved you."                         John 15:12

---

## #54139 — Anthony Ferrara — 2011-07-22T16:25:26+00:00

URL: https://externals.io/message/54129#54139 · In reply to: #54136

> Traits definitely need to be able to support properties, IMO

Well, if traits support properties, they stop being traits and become
mixins.  A trait is nothing more than a mixin that does not have a
state (so no properties).  I'm not saying that it wouldn't be useful
to contain properties (and hence state), but the RFC was for traits,
they are called traits, and the RFC does mention that they shouldn't
contain state.  So a trait (by definition) should be purely behavioral
(methods only).

So, based on that, it does indeed seem like a bug to me that they
currently support properties.

If properties are to be supported, then why don't we rename the trait
to a mixin and have some semblance of consistency...

Anthony


> 
> > […]
>
> Traits definitely need to be able to support properties, IMO, so I'd
> say that the first behaviour just needs to be documented (and
> potentially a notice added). Either the trait or the class is going to
> have its property overwritten, so we should pick which definition wins
> and go from there.
>
> Adam

---

## #54140 — Alex Howansky — 2011-07-22T16:32:47+00:00

URL: https://externals.io/message/54129#54140 · In reply to: #54137

> Just curious, if the trait property is set to private what happens?

Ooh, good question.

PHP Fatal error:  baz and foo define the same property ($zoo) in the 
composition of baz. However, the definition differs and is considered 
incompatible.

-- 
Alex Howansky

---

## #54144 — Jonathan Bond-Caron — 2011-07-22T17:01:18+00:00

URL: https://externals.io/message/54129#54144 · In reply to: #54129

> trait foo
> {
>       public $zoo = 'foo::zoo';
>       public function bar()
>       {
>           echo "in foo::bar\n";
>       }
> }
> 
> class baz
> {
>       use foo;
>       public $zoo = 'baz::zoo';
>       public function bar()
>       {
>           echo "in baz::bar\n";
>       }
> }
> 
> $obj = new baz();
> $obj->bar();
> echo $obj->zoo, "\n";
> 
> We get:
> 
> in baz::bar
> foo::zoo
> 
> It seems this is not correct and that it should be:
> 
> in baz::bar
> baz::zoo
> 

The expected behavior is an `E_STRICT` notice:
http://svn.php.net/viewvc/php/php-src/trunk/Zend/tests/traits/property001.ph
pt?view=markup&pathrev=306476

If the modifier is different/conflicting (public, protected, private)
E_FATAL
http://svn.php.net/viewvc?view=revision&revision=306476
http://marc.info/?l=php-internals&m=129251322332367&w=2

The theory is traits should not have conflicting state/properties.
Best practice, always choose trait property names carefully/~unique so that
you don't run into conflicts.

The short answer is it's not a bug but maybe an implementation issue...
should it be an `E_WARNING` instead of E_STRICT?

---

## #54146 — Philip Olson — 2011-07-22T17:09:20+00:00

URL: https://externals.io/message/54129#54146 · In reply to: #54140

> 
> > […]
> 
> Ooh, good question.
> 
> PHP Fatal error:  baz and foo define the same property ($zoo) in the composition of baz. However, the definition differs and is considered incompatible.

And while people have traits on the mind, please also review 
the three open bug reports which also discuss how trait behavior 
should be defined:

  https://bugs.php.net/search.php?search_for=trait&cmd=display

Regards,
Philip

---

## #54147 — Alex Howansky — 2011-07-22T17:46:40+00:00

URL: https://externals.io/message/54129#54147 · In reply to: #54144

> Best practice, always choose trait property names carefully/~unique
 > so that you don't run into conflicts.

Sure, but in this case, I created the conflict intentionally because I 
*want* to override it, and I'm not allowed to like I am with methods. 
Don't you think that's inconsistent?

 > The short answer is it's not a bug but maybe an implementation
 > issue... should it be an `E_WARNING` instead of E_STRICT?

At least. Consider the situation where I'm using classes/traits from 
somebody else's library that I may not be intimately familiar with. I'll 
have to know what every one of their properties is named so I can plan 
my code accordingly -- else I'll silently start getting their values in 
what I think are my variables.

-- 
Alex Howansky

---

## #54151 — Jonathan Bond-Caron — 2011-07-22T18:41:44+00:00

URL: https://externals.io/message/54129#54151 · In reply to: #54147

> 
> Sure, but in this case, I created the conflict intentionally because I
> *want* to override it, and I'm not allowed to like I am with methods.
> Don't you think that's inconsistent?
> 

Agree

> > […]
> issue... should it be an `E_WARNING` instead of E_STRICT?
> 
> At least. Consider the situation where I'm using classes/traits from 
> somebody else's library that I may not be intimately familiar with.
> I'll have to know what every one of their properties is named so I can 
> plan my code accordingly -- else I'll silently start getting their 
> values in what I think are my variables.

Part of the problem is if you have something like:

 trait foo
 {
       private $zoo = 'important_do_not_modify';

       public function showZoo(){
         echo $this->zoo;
        }

       public function doSomething(){
         if($this->zoo !== 'important_do_not_modify') die('bad');
        }
 }

 class baz
 {
       use foo;
       private $zoo = 'modified';
}

 $obj = new baz();
 $obj->bar();
 echo $obj->showZoo(); // modified
 echo $obj->doSomething();

You can essentially 'break' the trait. So if you think of using someone
else's library/trait, it's not fun either when you break something without
knowing it.
But even then, I'm with you on allowing to change the default property value
in the composing class (I'm in favor of it).

What traits would likely need is:
trait foo
{
       trait $zoo = 'important_do_not_modify';

       public function doSomething(){
         if(trait::$zoo !== 'important_do_not_modify') die('bad');
        }
 }

So that traits can keep their own private state (Ben Schmidt's idea)

---

## #54153 — Stefan Marr — 2011-07-23T13:55:36+00:00

URL: https://externals.io/message/54129#54153 · In reply to: #54129

Hi:


>
> Hello folks,
>
> I've just grabbed 5.4a2 to play with traits. I've found some behaviour which
> I'm not sure is a bug, an inconsistency, or a design decision.
>
> Consider a trait and a class that implements it but also overrides both a
> trait method and a trait attribute:
>
> trait foo
> {
>     public $zoo = 'foo::zoo';
>     public function bar()
>     {
>         echo "in foo::bar\n";
>     }
> }
>
> class baz
> {
>     use foo;
>     public $zoo = 'baz::zoo';
>     public function bar()
>     {
>         echo "in baz::bar\n";
>     }
> }
>
> $obj = new baz();
> $obj->bar();
> echo $obj->zoo, "\n";
>
> We get:
>
> in baz::bar
> foo::zoo
>
> It seems this is not correct and that it should be:
>
> in baz::bar
> baz::zoo

After some more thought, my take on this is that those properties are
not compatible, and we do the only simple thing possible and raise an
error as soon as possible, because the trait might have changed to
something that is not compatible with the class and the developer has
to be made aware of that.

While traits do not support state per se, we defined a minimal set of
rules so that the use of properties which conflict in their semantics
breaks as early as possible and noticeable to the developer.
Please refer to
https://wiki.php.net/rfc/horizontalreuse?&#handling_of_propertiesstate
for the exact set of rules defined currently.

These rules (rule 1) define that properties are considered
incompatible if they differ in their initial value.
Thus, the case you see here is, according to the rules defined in the
RFC, a bug.

And after looking at the implementation, it turns out that I just
forgot to check one of the return values of the compare function.
Thus, this is fixed as per
http://svn.php.net/viewvc?view=revision&revision=313632

Best regards
Stefan

---

## #54154 — Stefan Marr — 2011-07-23T13:57:20+00:00

URL: https://externals.io/message/54129#54154 · In reply to: #54147

Hi Alex:


>
> > […]
>
> Sure, but in this case, I created the conflict intentionally because I
> *want* to override it, and I'm not allowed to like I am with methods. Don't
> you think that's inconsistent?
>
> > […]
>
> At least. Consider the situation where I'm using classes/traits from
> somebody else's library that I may not be intimately familiar with. I'll
> have to know what every one of their properties is named so I can plan my
> code accordingly -- else I'll silently start getting their values in what I
> think are my variables.

If their trait grows that complex, with its own set of invariants, it
is a clear sign that it should be a class instead.
Traits are supposed to be a very light-weight mechanism for reuse of behavior.
Classes already provide you with the necessary means of encapsulation
you are asking for here: but traits do not do that.

If you want to reuse a trait that is that complex, consider to use it
in a separate class, which is then used in a composition in the class
were you originally were going to use the trait directly.

Traits do not allow to be reused without knowing their internals. The
metaphor of a compiler-assisted copy'n'past mechanism hints at that.

At least that is my interpretation of the topic.

Best regards
Stefan

---

## #54155 — Stefan Marr — 2011-07-23T13:58:36+00:00

URL: https://externals.io/message/54129#54155 · In reply to: #54151

> 
> > […]
>
> Agree

I do not agree, because for methods there is for most cases a way
around. You can introduce a new alias for the same behavior and use
that from the method which is overriding the original method name of
the trait. Thus, there is a flexible way to compose behavior, and that
is what we do everyday.
State how ever, does not come with that property, and the last time we
discussed different ideas in that direction they were deemed to be
complex.

> So that traits can keep their own private state (Ben Schmidt's idea)

One of those ideas should definitely be reconsidered for a later
version of PHP, but for the moment, I would prefer to concentrate on
getting bug-free what we have already and gather some experience on
how it is actually used in real-world scenarios.
In the end, if you trait is to complex and can 'break' easily, I think
that shows that it is worth to be implemented as a class, and you
might use instead a trait that provides you with the necessary
delegation functions.

Best regards
Stefan

---

## #54159 — Mike Stowe — 2011-07-23T16:49:32+00:00

URL: https://externals.io/message/54129#54159 · In reply to: #54155

So am I understanding correctly that the initial properties must be identical both in type and value, otherwise it would throw an error. To me that would make the most sense as they could be overridden in a construct or other method. 

If they are allowed to be different with one overriding the other- than for usability the class should override the trait properties as it does with methods.  This way it remains consistent, which I think would be the general expectation.  The trait should likewise override the parent class properties as it does with the parent methods (unless I misread that). But essentially if they're allowed to be different the overriding pattern IMHO should be the same as that used for methods. 

- Mike :o)

Sent from my iPhone



> 
> > […]
> 
> I do not agree, because for methods there is for most cases a way
> around. You can introduce a new alias for the same behavior and use
> that from the method which is overriding the original method name of
> the trait. Thus, there is a flexible way to compose behavior, and that
> is what we do everyday.
> State how ever, does not come with that property, and the last time we
> discussed different ideas in that direction they were deemed to be
> complex.
> 
> > […]
> 
> One of those ideas should definitely be reconsidered for a later
> version of PHP, but for the moment, I would prefer to concentrate on
> getting bug-free what we have already and gather some experience on
> how it is actually used in real-world scenarios.
> In the end, if you trait is to complex and can 'break' easily, I think
> that shows that it is worth to be implemented as a class, and you
> might use instead a trait that provides you with the necessary
> delegation functions.
> 
> Best regards
> Stefan

---

## #54160 — Stefan Marr — 2011-07-23T18:18:23+00:00

URL: https://externals.io/message/54129#54160 · In reply to: #54159

Hi Mike:


> So am I understanding correctly that the initial properties must be identical both in type and value, otherwise it would throw an error. To me that would make the most sense as they could be overridden in a construct or other method.

Yes, they have to be perfectly identical. Any difference indicates, in
this strict model, a potential conflict and different semantics of
that particular property i.e. the state.
Since we do not provide any means to manage such conflicts, we bail
out as early as possible and ask the programmer to fix his code by
ensuring everything is compatible.

Best regards
Stefan
