rfc:nonbreakabletraits

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
rfc:nonbreakabletraits [2008/03/06 22:38] sixdrfc:nonbreakabletraits [2017/09/22 13:28] (current) – external edit 127.0.0.1
Line 1: Line 1:
 ====== Request for Comments: Non Breakable Traits for PHP ====== ====== Request for Comments: Non Breakable Traits for PHP ======
   * Version: 1.0   * Version: 1.0
-  * Date: YYYY-MM-DD +  * Date: 2008-02-29 
-  * Author:  +  * Author: Joshua Thompson 
-  * Status: [Under Discussion|Implemented in some form]+  * Status: Under Discussion 
 + 
 +This idea is a continuation of the stateful traits discussed in 
 +"Stateful Traits and their Formalization" [[http://www.iam.unibe.ch/~scg/Archive/Papers/Berg07eStatefulTraits.pdf |[1]]]. I would suggest reading 
 +Section 4: "Stateful traits: reconciling traits and state" before 
 +continuing this discussion. 
 + 
 +Instead of automatically including all trait methods into the scope of 
 +the class, all methods and properties are automatically in the local 
 +scope of the trait. The developer then has the option of finer grained 
 +control on the method and property level. 
 + 
 +The options include the following: 
 + 
 +  - Keeping the method or properties //local// to the scope of the trait. 
 +  - Placing the method or properties into the scope of the including //class//
 +  - Making an //alias// of the property or method and use either scope. 
 +  - //Merging// multiple properties or methods in the class scope. 
 + 
 + 
 +===== Keywords Used In Sample Code ===== 
 + 
 +For all of the code examples, the following keywords were used: 
 + 
 +''trait'': This keyword is used to mark a trait definition exactly as the ''class'' keyword works for classes. 
 + 
 +''class'': Same as current PHP keyword. 
 + 
 +''include'': Used to include a trait into a class definition 
 + 
 +''private'': This keyword is used in its current PHP sense as well as to mean that a property or method is to retain its //local// trait scope. 
 + 
 +''public'': This keyword is used in its current PHP sense as well as to mean that a property or method is to be used within the scope of the including class. 
 + 
 +''as'': Used to //alias// or //merge// a trait into a class. 
 + 
 + 
 +===== Keeping Methods and Properties Local ===== 
 + 
 +Keeping a method or property //local// to a trait denies access from 
 +within the class or an object created from the class. It also keeps all 
 +references from methods within //that// trait to the method or property 
 +linked to the local method, even if the same name is used in another 
 +included trait, or is overridden in the including class. 
 + 
 +The problem with including an entire trait locally is that there is no way 
 +to use the methods or properties. The trait is only useful if you 
 +include at least one of the methods or properties into the class scope. 
 + 
 +The following code example shows how //local// scoping works:: 
 + 
 +<code php> 
 +  trait A1 { 
 +    private $a = 'A1'; 
 +    private function printA() { 
 +      echo $this->a; 
 +    } 
 +    public function callPrintA1() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  trait A2 { 
 +    private $a = 'A2'; 
 +    protected function printA() { 
 +      echo $this->a; 
 +    } 
 +    public function callPrintA2() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  class A { 
 +    include A1 { 
 +      public callPrintA1(); 
 +    } 
 +    include A2 { 
 +      public printA(); 
 +    } 
 +    public function callPrintA() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  $a = new A(); 
 +  $a->callPrintA1(); // 'A1' 
 +  $a->callPrintA2(); // Fatal Error: Undefined method... 
 +  $a->callPrintA(); // 'A2' 
 +</code> 
 + 
 +===== Placing Methods and Properties into the Class Scope ===== 
 + 
 +When placed into the scope of the class, a method or property behave as 
 +if it were copied and pasted directly into the class, with one 
 +exception: to not break the rules of trait local scope, any method or 
 +property with trait local scope in the class is used instead of a 
 +property or method in the class scope. This exception is the most 
 +important distinction between normal traits and non-breaking traits. 
 + 
 +As shown in the code example for local scope, the method call to 
 +''callPrintA1'' has a subsequent call to ''printA''. Since the ''printA'' 
 +method from the trait was in the local scope, it is called instead of 
 +the method in the class scope. 
 + 
 +===== Making An Alias ===== 
 + 
 +An alias can be made of a method or property in either local or class 
 +scope. When the alias is made, it is placed into the class scope (what 
 +else would the alias be for?). The alias still adheres to the rules for 
 +methods and properties locally scoped to the trait. Also, any change to an aliased property changes the original property. The same is not true for an aliased method being reimplemented in the class; it will not replace a trait's local method. 
 + 
 +The following code example shows how aliasing works: 
 + 
 +<code php> 
 +  trait A1 { 
 +    private $a = 'A1'; 
 +    private function printA() { 
 +      echo $this->a; 
 +    } 
 +    public function callPrintA1() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  trait A2 { 
 +    private $a = 'A2'; 
 +    protected function printA() { 
 +      echo $this->a; 
 +    } 
 +    public function callPrintA2() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  class A { 
 +    include A1 { 
 +      private $a as $a_from_A1; 
 +      public callPrintA1(); 
 +    } 
 +    include A2 { 
 +      public printA(); 
 +      private callPrintA2() as callPrintA(); 
 +    } 
 +    public function setA1( $value ) { 
 +      $this->a_from_A1 = $value; 
 +    } 
 +  } 
 +  $a = new A(); 
 +  $a->callPrintA1(); // 'A1' 
 +  $a->setA1( 'A1-changed' ); 
 +  $a->callPrintA1(); // 'A1-changed' 
 +  $a->callPrintA2(); // Fatal Error: Undefined method... 
 +  $a->callPrintA(); // 'A2' 
 +</code> 
 + 
 +===== Merging Multiple Methods or Properties ===== 
 + 
 +Merging is an extension of aliasing. Instead of aliasing properties or methods to unique names, multiple properties or methods are aliased to the same name, and an implementation of the method or a value for the property is placed in the combined class. 
 + 
 +To access the original method from within the class, multiple aliases will need to be made, or the method can be made local to the class scope and accessed from its original name. 
 + 
 + 
 +The following code example shows how aliasing works: 
 +<code php> 
 +  trait A1 { 
 +    private $a = 'A1'; 
 +    private function printA() { 
 +      echo $this->a; 
 +    } 
 +    public function callPrintA1() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  trait A2 { 
 +    private $a = 'A2'; 
 +    protected function printA() { 
 +      echo $this->a; 
 +    } 
 +    public function callPrintA2() { 
 +      $this->printA(); 
 +    } 
 +  } 
 +  class A { 
 +    include A1 { 
 +      private $a as $my_a; 
 +      public callPrintA1() as callPrintA(); 
 +    } 
 +    include A2 { 
 +      private $a as $my_a; 
 +      public printA(); 
 +      public callPrintA2() as callPrintA(); 
 +    } 
 +    private $my_a = 'A'; 
 +    public function setA( $value ) { 
 +      $this->my_a = $value; 
 +    } 
 +  } 
 +  $a = new A(); 
 +  $a->callPrintA1(); // 'A' 
 +  $a->setA( 'A-changed' ); 
 +  $a->callPrintA1(); // 'A-changed' 
 +  $a->callPrintA2(); // 'A-changed' 
 +  $a->callPrintA(); // 'A-changed' 
 +</code> 
 + 
 +====== Implementation Ideas ====== 
 + 
 +Two approaches to implementation are outlined below: 
 + 
 +  - Flatten 
 +  - Don't Flatten 
 + 
 +  I am not familiar with PHP internals, and these are only my thoughts 
 +  on the matter. I will let others decide the best route to take on 
 +  this. 
 + 
 +===== Flatten ===== 
 + 
 +The idea here is to place all of the properties and methods into the class definition at compile time. This makes it possible to run the code as if traits don't even exist. The benefits of this is that the run-time internals of PHP should not be affected. The downside is that compiling becomes more complicated. 
 + 
 +To keep methods and properties from colliding, some kind of alpha-renaming of those that are locally scoped must be made. The most common suggestion is to append the trait name (including namespace) to the front of the method or property seperated by the double colon (::). This should be an acceptable solution to the issue. However, every use of the method or property within the trait, must be changed to this new name. 
 + 
 +===== Don't Flatten ===== 
 + 
 +Instead of flattening, the traits could be kept separate from the class. Instead, during runtime, when a call is made to a trait method or property, the correct action is decided. This will require changes to the run-time internals of PHP, but could provide some benefit to opcode caches, as they could cache the trait once and use it for each of the classes that include it. 
 + 
 +====== Conclusion ====== 
 + 
 +An outline of non-breaking traits has been given. The changes build upon the work on stateful traits, and take it to the next obvious step. The benefit of this approach over multiple inheritance or mix-ins, is that the developer of the class has full control over exactly how the traits will be included into the class. 
 + 
 +Only simple code examples have been given, and questions will surely arise over what will happen if you include traits a certain way. In this case, more explanation and example code may be required. 
 + 
 + 
 +====== Bibliography ====== 
 + 
 +[1Alexandre Bergel, Stéphane Ducasse, Oscar Nierstrasz and Roel Wuyts,\\  
 +“Stateful Traits and their Formalization,” Journal of Computer\\ 
 +Languages, Systems and Structures, vol. 34, no. 2-3, 2008, pp. 83-108.\\ 
 +http://www.iam.unibe.ch/~scg/Archive/Papers/Berg07eStatefulTraits.pdf
rfc/nonbreakabletraits.1204843117.txt.gz · Last modified: 2017/09/22 13:28 (external edit)