Edit report at https://bugs.php.net/bug.php?id=61147&edit=1

 ID:                 61147
 Updated by:         g...@php.net
 Reported by:        greywire at gmail dot com
 Summary:            No conflict resolution for properties in traits
 Status:             Suspended
 Type:               Feature/Change Request
 Package:            Class/Object related
 Operating System:   MacOS X 10.7
 PHP Version:        5.4.0RC8
 Block user comment: N
 Private report:     N

 New Comment:

When I write 'alias', I refer to the 'as' keyword.
https://wiki.php.net/rfc/horizontalreuse#conflict_resolution
Verbosely, the example in the RFC (`use A, B {B::bigTalk as talk;}`) can be 
read 
as: use the method body of B::bigTalk and refer to it as 'talk' in the composed 
class. Important is here, that bigTalk ends up still in the class and has not 
been changed in any way by the addition of a new alias. (In the RFC's example 
there is even a conflict that needs resolution.)

Classes just have hash-tables of methods, i.e., the method name is mapped to 
the 
method body.
Method bodies are not changed at all by the traits implementation, and all 
references to methods are basically by name, i.e., a string. Thus, a method 
call 
will look up the method body in the hash table based on a name/string.
The same is true for properties.

I do not see how your idea with __get/__set works. It is still the same name of 
the property that would be used. And it is not clear to me how they could be 
distinguished.
Something like that would require name-mangling like for private properties, in 
the trait's method.
But then again, you have quite a number of possible semantics of how to handle 
properties. Sometimes, they are supposed to access the same, sometimes they are 
supposed to be distinct.

That would require quite a bit of syntax/complexity. And, as I said, the 
academic literature on that topic brings way to much complexity for my taste.
There was a proposal on the list or on the wiki to introduce a 'local' keyword.
We might want to consider that for a future version.

The current solution, fail if it smells like something funny is going on, seems 
at least to me as a compromise that avoids nasty surprises when maintaining 
code, and allows us to weaken the restrictions later on.

Best regards
Stefan


Previous Comments:
------------------------------------------------------------------------
[2012-02-21 15:24:48] greywire at gmail dot com

I'm trying to understand here.  When you say alias, do you mean generically 
like "reference" or "pointer" to a method?  Or is there some aliasing construct 
I'm not aware of in the language?

Traits are supposed to be flattened in the class, so its more like a language 
assisted cut and paste, correct?  Which means two conflicting method names have 
to be renamed uniquely (or not named at all?) and then a 
reference/alias/pointer to the desired one is put in place with the original 
name.  I don't know how the traits are actually implemented internally...

Attempting to do this by hand I see that you could, using runkit, remove the 
two conflicting methods and put in one "aliased" method pointing to one that 
was removed.  But doing this with a property as you said results in a new 
property that does not affect the other two.  I thought maybe you could set 
that new property with a "&$obj->renamedprop" but that doesnt work.

Running through my options (thinking about if runkit could be used to fix it.  
I've used runkit before to sorta implement my own traits functionality) I see 
its a tricky problem to solve indeed.

The only thing I came up with is that if at runtime PHP just removed the 
conflicting properties altogether so the code compiles and runs, and then the 
two properties (and the needed alias) could just be caught with __get/__set and 
handled by the user.  You'd get no warning or error about the conflict, but, 
you would immediately know about it when you accessed one of the properties.  
This may seem like a hack but at least it would give people an option...

Is that a palatable compromise that wouldn't be hard to implement?  :)

------------------------------------------------------------------------
[2012-02-21 09:26:36] g...@php.net

Unfortunately, the solution is not easy at all.

One reason is the dynamic nature of PHP. You can easily access properties based 
on their string name:

$foo = 'bar';
$this->$foo = 'foobar';

For exactly the same reason, we do NOT provide 'renaming'. The conflict 
resolution for methods allows to introduce an alias.
Nothing more. An alias is a new name pointing to an unchanged method-body.
(If you think about what that means, note that it breaks recursion in typical 
cases.)

Thus, your proposal does not work with the current semantics. It would only 
result in a new property in the class that is never actually used.

So far, we refrained from adding any of the constructs proposed in literature, 
since they would add considerable complexity.

>From time to time there have been proposals for related features that could 
>make 
it into a future version of PHP, but for the moment being, I do not see how we 
can make this work without changing the nature of PHP.

Suggestions are welcome of course.
Thanks
Stefan

------------------------------------------------------------------------
[2012-02-20 18:59:00] greywire at gmail dot com

Description:
------------
There is no way to resolve a conflict in two used traits with the same 
property.  The resolution method used to resolve conflicting method names 
should be able to be used similarly on properties.

I realize this may be the intended behavior to discourage use of properties in 
traits as properties were not originally intended in traits, but since 
properties are allowed, there should be a way to resolve the conflict, and the 
solution is simple and fits with existing syntax.



Test script:
---------------
<?php
trait testone {
    public $test;

}

trait testtwo {
    public $test;

}

//** this should work but doesn't
class traittest {
    use testtwo, testone {
        testone::$test insteadof testtwo;
        testtwo::$test as $testalso;
    }
}
?>

Expected result:
----------------
No errors or warnings.

Actual result:
--------------
Parse error: syntax error, unexpected '$test' (T_VARIABLE), expecting 
identifier (T_STRING) in index.php on line 14


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



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=61147&edit=1

Reply via email to