rfc:nonbreakabletraits
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
rfc:nonbreakabletraits [2008/03/06 22:38] – sixd | rfc: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: |
- | * Status: | + | * Status: Under Discussion |
+ | |||
+ | This idea is a continuation of the stateful traits discussed in | ||
+ | " | ||
+ | Section 4: " | ||
+ | continuing this discussion. | ||
+ | |||
+ | Instead of automatically including all trait methods into the scope of | ||
+ | the class, all methods and properties are automatically | ||
+ | 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 // | ||
+ | - 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: | ||
+ | |||
+ | '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | '' | ||
+ | |||
+ | |||
+ | ===== 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 = ' | ||
+ | private function printA() { | ||
+ | echo $this-> | ||
+ | } | ||
+ | public function callPrintA1() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | trait A2 { | ||
+ | private $a = ' | ||
+ | protected function printA() { | ||
+ | echo $this-> | ||
+ | } | ||
+ | public function callPrintA2() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | class A { | ||
+ | include A1 { | ||
+ | public callPrintA1(); | ||
+ | } | ||
+ | include A2 { | ||
+ | public printA(); | ||
+ | } | ||
+ | public function callPrintA() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | $a = new A(); | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | </ | ||
+ | |||
+ | ===== 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 | ||
+ | '' | ||
+ | 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' | ||
+ | |||
+ | The following code example shows how aliasing works: | ||
+ | |||
+ | <code php> | ||
+ | trait A1 { | ||
+ | private $a = ' | ||
+ | private function printA() { | ||
+ | echo $this-> | ||
+ | } | ||
+ | public function callPrintA1() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | trait A2 { | ||
+ | private $a = ' | ||
+ | protected function printA() { | ||
+ | echo $this-> | ||
+ | } | ||
+ | public function callPrintA2() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | 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 = new A(); | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | </ | ||
+ | |||
+ | ===== 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 = ' | ||
+ | private function printA() { | ||
+ | echo $this-> | ||
+ | } | ||
+ | public function callPrintA1() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | trait A2 { | ||
+ | private $a = ' | ||
+ | protected function printA() { | ||
+ | echo $this-> | ||
+ | } | ||
+ | public function callPrintA2() { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | 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 = ' | ||
+ | public function setA( $value ) { | ||
+ | $this-> | ||
+ | } | ||
+ | } | ||
+ | $a = new A(); | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | $a-> | ||
+ | </ | ||
+ | |||
+ | ====== 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, | ||
+ | |||
+ | ===== 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 ====== | ||
+ | |||
+ | [1] Alexandre Bergel, Stéphane Ducasse, Oscar Nierstrasz and Roel Wuyts,\\ | ||
+ | “Stateful Traits and their Formalization, | ||
+ | Languages, Systems and Structures, vol. 34, no. 2-3, 2008, pp. 83-108.\\ | ||
+ | http:// |
rfc/nonbreakabletraits.1204843117.txt.gz · Last modified: 2017/09/22 13:28 (external edit)