rfc:mixin

Request for Comments: mixin

Introduction

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:

Presentation on Traits

Traits RFC

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.

Use Cases

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.

Use Case #1 - From the traits example

class ezcReflectionReturnInfo {
   function getReturnType() { /*1*/ }
   function getReturnDescription() { /*2*/ }
}
 
class ezcReflectionMethod extends ReflectionMethod  mixin  ezcReflectionReturnInfo {
   /* ... */
}
 
class ezcReflectionFunction extends ReflectionFunction  mixin  ezcReflectionReturnInfo {
   /* ... */
}

Use Case #2 - Commonly used events

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"

Use Case #3 - Real world billing information (i.e. telecom company)

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.

Use Case #4 – Development, allow dynamic mixins

// 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");

PHP.ini

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);

Proposal and Patch

Learning how to hack PHP. Contributions welcome.

Notes

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”.

rfc/mixin.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1