This is first draft of adding the 'mixin' keyword into the PHP language. It based around the 'trait' proposal where the primary advantage is to avoid code duplication and re-factoring of code.
For a good summary and detailed research on the advantages, see:
More background about mixins on Wikipedia.
This proposal only introduces 1 keyword 'mixin' and the function class_mixin().
Hopefully, the use cases will speak for themselves.
The use cases should represent how the mixin feature is expected to be used, highlight both best-practices and “ugly hacks” or problems that could result from the syntax.
class ezcReflectionReturnInfo { function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod mixin ezcReflectionReturnInfo { /* ... */ } class ezcReflectionFunction extends ReflectionFunction mixin ezcReflectionReturnInfo { /* ... */ }
class eventDelete { public $isDeleted; function onDelete() { $this->isDeleted = true; // Log this... other work here? } } class eventSave { function save() { echo "save"; $this->onSave(); } function onSave() {} } class shoppingCart mixin eventSave, eventDelete { } $s = new shoppingCart; $s->save(); // calls eventSave->save(); class shoppingCart2 mixin eventSave, eventDelete { function save() { echo "called"; // mixin::save(); would call eventSave::save() } } $s = new shoppingCart2; $s->save(); // calls shoppingCart2::save(); "called"
class SOME _Billing_Information { function getAccount() { // implement... } function getAddressBilling() { echo "mixin address"; } function setAddressBilling($address) { // implement... } } class Customer_Telecom extends Person mixin SOME_Billing_Information { } class Company_Telecom extends Company mixin SOME_Billing_Information { function getAddressBilling() { echo "I stay the same"; } } class Company_Rogers extends Company_Telecom { function getAddressBilling() { echo parent::getAddressBilling(); // "I stay the same" echo mixin::getAddressBilling(); // "mixin address" } function getAccount() { echo "different"; } }
The mixin clobbers any methods or properties into the given object.
It does not replace any exiting methods or properties defined in the class, primarily for language security. Any method or property that already exists in the class or parent/extended class cannot be changed unless using class_mixin() see below.
// dynamic mixin: class_mixin("shoppingCart", array("eventsA", "eventsB")); // Same as class_mixin("shoppingCart", "eventsA"); class_mixin("shoppingCart", "eventsB"); // Not equivalent (order matters) class_mixin("shoppingCart", "eventsB"); class_mixin("shoppingCart", "eventsA"); // Taken from this post: // [[http://usrportage.de/archives/828-A-naive-approach-to-mixins-in-PHP.html]] class_mixin("PHPUnit_Framework_Assert", "MY_Assert_Methods");
The default php.ini would contain ~:
mixin.security = true # default and CANNOT be changed using ini_set()
class_mixin('PHPUnit_Framework_Assert', 'MY_Assert_Methods'); // throws an E_ERROR
Dynamic mixins would be supported by editing php.ini:
mixin.security = false
class_mixin('PHPUnit_Framework_Assert', 'MY_Assert_Methods'); // OK $a = new PHPUnit_Framework_Assert; $a->myAssertType('okk', $obj);
Learning how to hack PHP. Contributions welcome.
There was an interesting paper in the ACM (2006) about “intuitive OO design”.
The goal here is to keep OO intuitive and allow for multiple inheritance “PHP style”.