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

Reply via email to