Hello php, looks good to me. See more detailed thoughts in separate mail resonses. The biggest issue I see is finding a syntax everyone likes.
Personally I like everything but one tiny piece, that is you do '!method' to ignore a method from a trait. Since renaming happens in a php array like style I would prefer to have that approach apply for ignoring methods as well. The way to do that imo is 'method=>false' or 'method=>NULL' which both should be obvious to PHP programmers that heard about Traits. Other than that I'd even appriciate it, if we could get this for 5.3. I mean come on guys it is ready and a very nice solution to the code reuse problem. marcus Monday, February 18, 2008, 8:27:00 PM, you wrote: > Hi, > during last six months I've studied a language construct called Traits. > It is a construct to allow fine-grained code reuse and in my opinon > this would be a nice feature for PHP, which I did like to propose here. > The following RFC deals with the questions what Traits are, how they are > used, why they are usefull and how they do look like in PHP. > A patch implementing this new language construct is available, too. > Thank you for your attention and I'm looking forward to hear your comments > :) > Kind Regards > Stefan > Request for Comments: Traits for PHP > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ > :HTML: http://www.stefan-marr.de/artikel/rfc-traits-for-php.html > ... contents:: > This RFC will discuss at first the motivation for Traits describing the > rationals > and presenting a short real world use case. The main part will describe the > concept of Traits in detail using the syntax for Traits implemented in a > patch > which is part of this proposal. In the end, the URL of the patch and > additional resources about Traits are given. > Introduction > ============ > *Traits* is a mechanism for code reuse in single inheritance languages such > as PHP. A Trait is intended to reduce some limitations of single inheritance > by enabeling a developer to reuse sets of methods freely in several > independent > classes living in different class hierarchies. > The semantics of the combination of Traits and classes is defined in a way, > which reduces complexity and avoids the typical problems associated with > multiple > inheritance and Mixins. > They are recognized for their potential in supporting better composition > and reuse, hence their integration in newer versions of languages > such as Perl 6, Squeak, Scala, Slate and Fortress. > Traits have also been ported to Java and C#. > Why do we need Traits? > ---------------------- > Code reuse is one of the main goals that object-oriented languages try to > achieve > with inheritance. Unfortunately, single inheritance often forces the > developer > to take a decision in favor for either code reuse *or* conceptual clean > class > hierarchies. To achieve code reuse, methods have either to be duplicated or > to be moved near the root of the class hierarchy, but this hampers > understandability and maintainability of code. > To circumvent this problems multiple inheritance and Mixins have been > invented. > But both of them are complex and hard to understand. PHP5 > has been explicitly designed with the clean and successful model of Java in > mind: single inheritance, but multiple interfaces. This decision has been > taken > to avoid the known problems of for example C++. > Traits have been invented to avoid those problems, too. They enable designer > to build > conceptually clean class hierarchies without the need to consider code reuse > or > complexity problems, but focusing on the real problem domain and > maintainability > instead. > Traits: A Mechanism for Fine-grained Reuse > ========================================== > A Trait is a unit of reuse much like a class, but only intended to group > functionality in a fine-grained and consistent way. It is not possible to > instantiate a Trait on its own. It is an addition to traditional inheritance > and enables horizontal composition of behavior. > The following code illustrates the current implementation of an extended > version of the PHP reflection API which provides detailed access to doc > comment > blocks. > ReflectionMethod and ReflectionFunction are classes from the reflection API > and > have to be extended with exactly the same code. In some situations it > would be possible to add a common base class, but in this case it is > impossible, because the extended classes are not under our control, i.e., > they > are implemented in third party code or even in C, like it is the case here. > :: > <?php > class ezcReflectionMethod extends ReflectionMethod { > /* ... */ > function getReturnType() { /*1*/ } > function getReturnDescription() { /*2*/ } > /* ... */ > } > class ezcReflectionFunction extends ReflectionFunction { > /* ... */ > function getReturnType() { /*1*/ } > function getReturnDescription() { /*2*/ } > /* ... */ > } > ?> > With Traits it is possible to refactor this redundant code out. > :: > <?php > trait ezcReflectionReturnInfo { > function getReturnType() { /*1*/ } > function getReturnDescription() { /*2*/ } > } > class ezcReflectionMethod extends ReflectionMethod { > use ezcReflectionReturnInfo; > /* ... */ > } > class ezcReflectionFunction extends ReflectionFunction { > use ezcReflectionReturnInfo; > /* ... */ > } > ?> > This is just a small example of what Traits are useful for. > The next sections will discuss on more advanced techniques and describe how > the > current implementation of Traits for PHP works. > The Flattening Property > ----------------------- > As already mentioned, multiple inheritance and Mixins are complex > mechanisms. > Traits are an alternative which have been designed to impose no > additional semantics on classes. 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. > Precedence Order > """""""""""""""" > Flattening is achieved by applying some simple rules on the composition > mechanism. Instead of implementing a fancy and awkward algorithm to solve > problems, the entire control about the composition is left in the hand of > the > developer and fits nicely into the known inheritance model of PHP. > The following examples illustrate the semantics of Traits and their relation > to methods defined in classes. > :: > <?php > class Base { > public function sayHello() { > echo 'Hello '; > } > } > > trait SayWorld { > public function sayHello() { > parent::sayHello(); > echo 'World!'; > } > } > class MyHelloWorld extends Base { > use SayWorld; > } > $o = new MyHelloWorld(); > $o->sayHello(); // echos Hello World! > ?> > As shown in the above code, an inherited method from a base class is > overridden > by the method inserted into ``MyHelloWorld`` from the ``SayWorld`` Trait. > The behavior is the same for methods defined in the ``MyHelloWorld`` class. > The precedence order is that methods from the current class override Trait > methods, > which in return override methods from the base class. > :: > <?php > trait HelloWorld { > public function sayHello() { > echo 'Hello World!'; > } > } > class TheWorldIsNotEnough { > use HelloWorld; > public function sayHello() { > echo 'Hello Universe!'; > } > } > $o = new TheWorldIsNotEnough(); > $o->sayHello(); // echos Hello Universe! > ?> > Multiple Traits Usage > """"""""""""""""""""" > To keep things simple in the beginning, there has only one Trait being used > at > a time, but obviously a class could use multiple Traits at the same time. > :: > <?php > trait Hello { > public function sayHello() { > echo 'Hello '; > } > } > trait World { > public function sayWorld() { > echo ' World'; > } > } > > class MyHelloWorld { > use Hello; > use World; > public function sayExclamationMark() { > echo '!'; > } > } > > $o = new MyHelloWorld(); > $o->sayHello(); > $o->sayWorld(); > $o->sayExclamationMark(); > // Results eventually in: Hello World! > Conflict Resolution > """"""""""""""""""" > But now a problem will occur, if different Traits provide methods with the > same name. > :: > <?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'; > } > } > ?> > Both classes have to be used in a class named ``Talker``. Multiple > inheritance > and Mixins define an algorithm to resolve this conflict. Traits don't. > Conflicts > aren't solved implicitly by any kind of precedence. Instead, to avoid > implicit > complexity, the developer has full control over class composition. > :: > <?php > class Talker { > use A; > use B; > } > ?> > > In case of the above definition of ``Talker``, PHP will show a notice that > there > have been conflicts and name the methods ``smallTalk()`` and ``bigTalk()`` > as the reason of this conflict. Therefore, neither of the given > implementations > will be available in the class. > Instead, the developer can exactly define which methods are used and how the > conflict is resolved. > :: > <?php > class Talker { > use A { !smallTalk } > use B { !bigTalk } > } > ?> > This definition will result in the exclusion of ``smallTalk()`` from the > Trait A > and ``bigTalk()`` from Trait B. Therefore, the resulting class Talker would > echo ``'b'`` for ``smallTalk()`` and ``'A'`` for ``bigTalk().`` > But simple exclusion of methods is not the best choice for all situations. > :: > <?php > class Talker { > use A { !smallTalk } > use B { !bigTalk, talk => bigTalk } > } > ?> > > Beside the exclusion an alias operation is available, too. This alias > operation, notated like a ``key => value`` for arrays even has a similar > semantics like the array notation. The definition ``talk => bigTalk`` > lets the new name ``talk`` refer to the method body of ``bigTalk`` > of the Trait B. The resulting ``Talker`` class will consist of following > three methods: > * ``bigTalk() { echo 'A'; }`` > * ``smallTalk() { echo 'b'; }`` > * ``talk() { echo 'B'; }`` > Since the alias operation adds a new name to an existing method body, the > ``bigTalk`` method still has to be excluded. Otherwise, PHP would print > a notice that two methods from Traits have a conflict and are excluded. > Aliasing is not renaming and references in methods to a given method name > aren't changed either. On the first look this may sound strange, but it > provides the opportunity to build Traits and even hierarchies of Traits > which > fit together very well. > Traits Composed from Traits > """"""""""""""""""""""""""" > Not explicitly mentioned jet, but implied by the flattening property is the > composition of Traits from Traits. > 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. > The following code illustrates this:: > <?php > trait Hello { > public function sayHello() { > echo 'Hello '; > } > } > trait World { > public function sayWorld() { > echo 'World!'; > } > } > trait HelloWorld { > use Hello; > use World; > } > class MyHelloWorld { > use HelloWorld; > } > $o = new MyHelloWorld(); > $o->sayHello(); > $o->sayWorld(); > // Results eventually in: Hello World! > ?> > Traits itself can take part in arbitrary compositions, but Traits are not > part > of the inheritance tree i.e., it is not possible to inherit from a Trait to > avoid confusion and misuse of Traits. > Traits Semantics Summarized > --------------------------- > 1. Traits do not add runtime semantics, they only take part in the process > of > building a class. > 2. Traits integrate into the precedence order of method overriding. > 3. To avoid complexity, conflicts between Trait methods have to be solved > explicitly. Otherwise a notice is generated and the conflicting methods > are excluded. > 4. Specific methods can be excluded from a composition to handle conflicts. > 5. Aliases can be defined for methods to enable reuse of conflicting > methods. > 6. Traits can be composed from Traits. > As a result of this semantics, at runtime, classes build using Traits are > not distinguishable > from classes not using Traits but traditional code duplication instead. > Semantics of ``parent`` and ``$this`` hasn't changed, too. Used in a Trait > method, they behave exactly the same as if the method has been defined in > the > class directly. > Visibility and Interfaces > ------------------------- > Visibility modifiers have not been discussed so far. Since Traits are meant > as > units of reuse, modifiers should be changeable easily in the context of a > composed class. Therefore, the aliasing operation is able to change the > visibility modifier of a method, too. > :: > <?php > trait HelloWorld { > public function sayHello() { > echo 'Hello World!'; > } > } > class MyClass1 { > use HelloWorld { protected sayHello } > } > class MyClass2 { > use HelloWorld { private doHelloWorld => sayHello } > } > ?> > The abstract and final modifiers are supported, too. Abstract methods in > Traits are commonly used to define requirements a Trait needs to have > implemented by a class. The static modifier is not supported, because it > would > change the methods semantics and references to ``$this`` would break. > Another important feature of PHP is the support of interfaces. A often used > metaphor to describe Traits is *Traits are interfaces with implementation*. > Traits can be utilized to provide the implementation for a specific > interface > and since an interface is a guarantee that some methods are available it > fits > in the concept of Traits which provides those methods very well. > To underpin this relationship, it is possible to declare that a Trait > implements an interface like this:: > <?php > interface IHello { > public function sayHello(); > } > > trait SayHello implements IHello { > public function sayHello() { > echo 'Hello World!'; > } > } > class MyHelloWorld { > use SayHello; > } > > $o = new MyHelloWorld(); > var_dump($o instanceof IHello); // bool(true) > If a Trait implements an interface, this definition is propagated to the > class > using the Trait. Therefore, it is possible to provide implementations for an > interface > and reuse them in different classes. > Proposal and Patch > ================== > This Request for Comments proposes a new language feature for PHP named > Traits. > Traits are a nice approach to enhance the capabilities to design conceptual > consistent class hierarchies and avoid code duplication. > The patch against the PHP_5_2 branch is available at > http://toolslave.net/snapshots/traits/traits.patch > The written test cases are located here: > http://toolslave.net/snapshots/traits/traits-tests.zip > Additionally, the SVN repo used for developing this patch is located at > https://instantsvc.svn.sourceforge.net/svnroot/instantsvc/branches/php-exten > sion/traits-php/ > Alternative Syntax Proposals > ---------------------------- > This section collects proposals for alternative Traits syntaxes. > Traits Use Definition in the Class Header > """"""""""""""""""""""""""""""""""""""""" > Instead of declaring the Trait composition in the class body, it could be > defined in the class prologue like this:: > > <?php > trait Hello { > public function sayHello() {} > } > class MyHelloWorld extends BaseClass > uses Hello (hello => sayHello, !sayHello) > { > public function foo() {} > } > ?> > The drawback of this notation is the implied notation of Traits as some kind > of > a type changing construct. Since they do not influence the type as their > major > feature, this notion would be misleading. Furthermore, this notation seams > to > have readability problems. Complex compositions are not as clearly arranged > as > they are with the *In-Body* notation. > A patch implementing this notation is available at: > http://toolslave.net/snapshots/traits/traits-head-syntax.patch > More about Traits > ----------------- > As already mentioned, Traits is not a totally new concept, but the semantics > used in this proposal has been fully defined at first in 2003. For > scientific > information and papers about Traits > http://www.iam.unibe.ch/~scg/Research/Traits/ > is a good starting point. Since it isn't a purely academic concepts, there > are > already languages supporting Traits out there. Squeak, Perl6, Scala, Slate, > Fortress and even for C#/Rotor implementation are available. > A detailed technical report has been published at > http://www.iam.unibe.ch/~scg/Archive/Papers/Duca06bTOPLASTraits.pdf > It explains Traits and gives some formal proves about the soundness of > Traits, too. > Last but not least, in this Phd thesis > http://www.iam.unibe.ch/~scg/Archive/PhD/schaerli-phd.pdf > two case studies have been publish illustrating the benefits Traits are > providing. Best regards, Marcus -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php