<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>stevehollis.com &#187; magic methods</title>
	<atom:link href="http://www.stevehollis.com/tag/magic-methods/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.stevehollis.com</link>
	<description>Barking on about PHP, MySQL and Zend Framework</description>
	<lastBuildDate>Mon, 05 Apr 2010 18:07:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Trait-like Functionality for PHP</title>
		<link>http://www.stevehollis.com/2010/04/trait-like-functionality-for-php/</link>
		<comments>http://www.stevehollis.com/2010/04/trait-like-functionality-for-php/#comments</comments>
		<pubDate>Mon, 05 Apr 2010 18:07:04 +0000</pubDate>
		<dc:creator>Steve</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[magic methods]]></category>
		<category><![CDATA[reflection]]></category>
		<category><![CDATA[traits]]></category>

		<guid isPermaLink="false">http://www.stevehollis.com/?p=134</guid>
		<description><![CDATA[Eliminating repetition and encouraging code reuse are central tenets of software development. PHP&#8217;s lack of multiple inheritance means sometimes there are tough design choices to be made when similar functionality is required in separate branches of the class heirarchy. As proposed in the Horizontal Reuse for PHP RFC, traits offer a means of duplicating functionality [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.stevehollis.com/wp-content/uploads/2010/04/php-logo1.png"><img src="http://www.stevehollis.com/wp-content/uploads/2010/04/php-logo1.png" alt="" title="PHP Logo" width="300" height="211" class="alignright size-full wp-image-176" /></a>Eliminating repetition and encouraging code reuse are central tenets of software development.</p>
<p>PHP&#8217;s lack of multiple inheritance means sometimes there are tough design choices to be made when similar functionality is required in separate branches of the class heirarchy. </p>
<p>As proposed in the <a href="http://wiki.php.net/rfc/horizontalreuse">Horizontal Reuse for PHP RFC</a>, traits offer a means of duplicating functionality in independent classes.</p>
<p>In this post, I&#8217;ll be detailing an approach that offers trait-like functionality to your objects in an intuitive and straightforward way.</p>
<h2>Why Traits?</h2>
<p>So why do we need traits, anyway? </p>
<p>PHP is a single inheritance language, meaning that each class can only extend one other. This allows us to build logical class hierarchies which extend functionality in a &#8220;vertical&#8221; way. </p>
<p>For example, the Lion class might extend a Mammal class, which in turn extends Animal. Or Eagle could extend Bird which also extends Animal. Or maybe Locust -> Insect -> Animal. Pretty logical stuff.</p>
<p>The problem arises when an overlap in functionality occurs in different branches of the class hierarchy. Say, for instance, we are interested how the different species of animals get around. Both our locust and our eagle are flyers, but they&#8217;re in separate branches of the class hierarchy. So where do we put our getAverageFlyingSpeed() and getMaxAltitude() methods?</p>
<p>At this point we have two choices. The first option is to move the methods into a class higher up the tree, like the Animal class. The drawback here is that we end up with a superclass containing scores of methods that are redundant for all but a handful of concrete classes. Not good.</p>
<p>The second option is to simply duplicate the code in the classes where it is required. This, however, flies in the face of the <acronym title="Don't Repeat Yourself">DRY</acronym> principle and can make the code harder to maintain.</p>
<p>What we need is a means of re-using code other than simple inheritance. That&#8217;s where traits come in. </p>
<p>Traits are classes containing a collection of methods, usually relating to a particular behaviour. Since they can be applied at will, they are independent of the inheritance hierarchy. Conceptually, traits are very much like interfaces with actual methods.</p>
<p>Using our example, we could create a Flight trait which could be applied to both the eagle and locust classes, giving the desired functionality without the drawbacks associated with single class inheritance.</p>
<h2>I Want Them Now!</h2>
<p>Whoa there! One step at a time <img src='http://www.stevehollis.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Hopefully the benefits of traits for a language like PHP should be pretty clear.</p>
<p>Sadly, they&#8217;re unlikely to included in any PHP release in the near future (although you can download Stefan Marr&#8217;s <a href="http://stefan-marr.de/2009/09/traits-patch-updated-backported-and-available-on-github/">patched PHP versions</a>). </p>
<p>In the meantime, I&#8217;ve put together an approach that offers trait-like functionality and is reasonably easy to implement. There&#8217;s too much code to include it all in this post, so you can download the source code <a href='http://www.stevehollis.com/wp-content/uploads/2010/04/traits.zip'>here</a>.</p>
<h2>The Code</h2>
<p>In this setup, traits are classes that extend My_Trait_Abstract. To illustrate this, we&#8217;ll create a trait, My_Trait_Json, that adds a toJson method to any class it is added to.</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'My/Trait/Abstract.php'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> My_Trait_Json <span style="color: #000000; font-weight: bold;">extends</span> My_Trait_Abstract
<span style="color: #009900;">&#123;</span>
    <span style="color: #009933; font-style: italic;">/**
     * @param My_Object $object
     * @return string
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> toJson<span style="color: #009900;">&#40;</span> My_Object <span style="color: #000088;">$object</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$json</span> <span style="color: #339933;">=</span> <span style="color: #990000;">json_encode</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">get_object_vars</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$object</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$json</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>Every public method in a trait class will be available to the classes to which they&#8217;re added. Also notice that the first parameter of each method <strong>must</strong> be an instance of the object which it is working on&#8230; that&#8217;ll make more sense later.</p>
<p>The abstract trait class uses reflection to examine each trait to find public methods &#8211; only the constructor and getMethods are excluded. _retrieveMethods is lazy-loaded and only carried out on a call to getMethods.</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #009933; font-style: italic;">/**
     * @return array
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getMethods<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #009900; font-weight: bold;">NULL</span> <span style="color: #339933;">===</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_methods <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_methods <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_retrieveMethods<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_methods<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @return My_Trait_Abstract
     */</span>
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> _retrieveMethods<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// Exclude the constructor and public getMethods method</span>
	<span style="color: #000088;">$exclude</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
	    <span style="color: #0000ff;">'__construct'</span><span style="color: #339933;">,</span>
	    <span style="color: #0000ff;">'getMethods'</span>
	<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$refObject</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> ReflectionObject<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$refObject</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getMethods</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$method</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isPublic</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #000088;">$name</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$method</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getName</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #990000;">in_array</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$name</span><span style="color: #339933;">,</span> <span style="color: #000088;">$exclude</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_addMethod<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$name</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	    <span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @param string $method Name of method
     * @return My_Trait_Abstract
     */</span>
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> _addMethod<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #990000;">method_exists</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #000088;">$method</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;Method '<span style="color: #006699; font-weight: bold;">$method</span>' does not exist&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_methods <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;Duplicate method '<span style="color: #006699; font-weight: bold;">$method</span>'&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_methods<span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$method</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<h2>The Glue</h2>
<p>With our trait classes in order, we now need a way to access their functionality.</p>
<p>To do this, we&#8217;ll use a __call magic method in our object superclass and a &#8220;trait broker&#8221; &#8211; a class which maintains trait instances and their methods. (For Zend Framework users, the TraitBroker works in a very similar way to ZF&#8217;s PluginBroker.)</p>
<p>Here&#8217;s our object superclass:</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
abstract <span style="color: #000000; font-weight: bold;">class</span> My_Object
<span style="color: #009900;">&#123;</span>
    <span style="color: #009933; font-style: italic;">/**
     * @var My_TraitBroker
     */</span>
    static <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000088;">$_traitBroker</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @param   string $method
     * @param   array $args
     * @return  mixed
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> __call<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">,</span> <span style="color: #000088;">$args</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// Check trait broker for extended functionality</span>
	<span style="color: #000088;">$class</span> <span style="color: #339933;">=</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$traitBroker</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTraitBroker</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// Check whether class traits have been initialised</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #000088;">$traitBroker</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">isClassRegistered</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$class</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_initTraits<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #000088;">$traitBroker</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerClass</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$class</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #000088;">$traitBroker</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">hasMethod</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">,</span> <span style="color: #000088;">$class</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	     <span style="color: #b1b100;">return</span> <span style="color: #000088;">$traitBroker</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">callMethod</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">,</span> <span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="color: #000088;">$args</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> Exception<span style="color: #009900;">&#40;</span>
	    <span style="color: #0000ff;">&quot;Invalid method &quot;</span><span style="color: #339933;">.</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;::&quot;</span><span style="color: #339933;">.</span> <span style="color: #000088;">$method</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;(&quot;</span><span style="color: #339933;">.</span> <span style="color: #990000;">print_r</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$args</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1</span> <span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;)&quot;</span>
	<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #666666; font-style: italic;">//////////////////////////</span>
    <span style="color: #666666; font-style: italic;">// Trait Functionality //</span>
    <span style="color: #666666; font-style: italic;">//////////////////////////</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @return My_TraitBroker
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> getTraitBroker<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$_traitBroker</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	    <span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'My/TraitBroker.php'</span><span style="color: #339933;">;</span>
	    <span style="color: #000088;">$broker</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> My_TraitBroker<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$_traitBroker</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$broker</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$_traitBroker</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @param My_TraitBroker
     * @return void
     */</span>
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> _initTraits<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// Do nothing - child classes add traits here</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @param My_Trait_Abstract
     * @return My_Object
     */</span>
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> _registerTrait<span style="color: #009900;">&#40;</span> My_Trait_Abstract <span style="color: #000088;">$trait</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getTraitBroker</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">registerTrait</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$trait</span><span style="color: #339933;">,</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$this</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$this</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>The __call method will trap calls to non-existent methods, at which point the TraitBroker is instantiated and any traits for the class are initialised. All that our child classes need to do is extend _initTraits and specify which traits it uses.</p>
<p>Internally, the TraitBroker takes care of getting the right trait instance and calling the requested method.</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;">    <span style="color: #009933; font-style: italic;">/**
     * Call the trait method
     *
     * @param string $method
     * @param string $objectClass
     * @param My_Object $object
     * @param array $args
     * @return mixed
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> callMethod<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">,</span> My_Object <span style="color: #000088;">$object</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span> <span style="color: #000088;">$args</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$objectClass</span> <span style="color: #339933;">=</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$object</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">hasMethod</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$method</span><span style="color: #339933;">,</span> <span style="color: #000088;">$objectClass</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">throw</span> <span style="color: #000000; font-weight: bold;">new</span> My_Exception<span style="color: #009900;">&#40;</span> <span style="color: #0000ff;">&quot;Cannot call method '<span style="color: #006699; font-weight: bold;">$method</span>' - not registered.&quot;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000088;">$trait</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_methods<span style="color: #009900;">&#91;</span> <span style="color: #000088;">$objectClass</span> <span style="color: #009900;">&#93;</span><span style="color: #009900;">&#91;</span> <span style="color: #000088;">$method</span> <span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$args</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_merge</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$object</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$args</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #990000;">call_user_func_array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$trait</span><span style="color: #339933;">,</span> <span style="color: #000088;">$method</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
            <span style="color: #000088;">$args</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>As you can see, the trait class is passed the calling object and any arguments trapped by the __call method. This does mean that traits can only manipulate an object&#8217;s public methods and properties &#8211; how much of a limitation this is will depend on your exact implementation. In practice, I&#8217;ve found that this is usually easy to work around.</p>
<p>Now all we need is a class extending My_Object that registers the Json trait.</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'My/Object.php'</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'My/Trait/Json.php'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> My_Model <span style="color: #000000; font-weight: bold;">extends</span> My_Object
<span style="color: #009900;">&#123;</span>
    <span style="color: #009933; font-style: italic;">/**
     * @var string
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$foo</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'bar'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @var string
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000088;">$bat</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'baz'</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * @return void
     */</span>
    <span style="color: #000000; font-weight: bold;">protected</span> <span style="color: #000000; font-weight: bold;">function</span> _initTraits<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// Register traits</span>
	<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_registerTrait<span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> My_Trait_Json<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

<p></code></p>
<p>The protected _registerTrait method takes care of registering the the trait with the broker. </p>
<p>The client code and output is exactly the same as if the toJson method were part of our model.</p>
<p><code></p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #b1b100;">require_once</span> <span style="color: #0000ff;">'My/Model.php'</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$object</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> My_Model<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #990000;">var_dump</span><span style="color: #009900;">&#40;</span> <span style="color: #000088;">$object</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">toJson</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// outputs</span>
<span style="color: #666666; font-style: italic;">// string(25) &quot;{&quot;foo&quot;:&quot;bar&quot;,&quot;bat&quot;:&quot;baz&quot;}&quot;</span></pre></div></div>

<p></code></p>
<p>A few notes:</p>
<ul>
<li>Since the _initTraits method is inherited by child classes like any other, traits will also be inherited. You can override this by putting a custom (or empty) _initTraits method in the child class.</li>
<li>My_Trait_Abstract allows for an associative array of options to be passed to its constructor. For these to have any effect, you&#8217;ll need to add a protected _set<em>OptionName</em> method in your trait class.</li>
<li>Although I haven&#8217;t benchmarked it, there is sure to be a small performance hit using traits against hard coded methods due to the use of __call and reflection. Chances are it&#8217;ll be pretty insignificant in a real world application though.</li>
</ul>
<p>Although the JSON trait is a very simple example, I hope that you can see the potential value in this kind of setup. I&#8217;ve only been tinkering with it for a couple of weeks, but I&#8217;ve already used traits for things like addresses and HTML metadata (for a content management system). In fact, I&#8217;ve started putting functionality into traits that I&#8217;d normally hard code into classes, purely because the potential for re-use is so much greater.</p>
<h2>Final Thoughts</h2>
<p>PHP is at an exciting stage in its development and it will be interesting to see how the language changes over the next year or so, especially towards the release of PHP 6. But until new features like traits and grafts are available within the language itself, it&#8217;s up to us to come up with other ways around the limitations we face.</p>
<p>This approach to implementing traits is one way in which you can help to reduce repetition and promote code reuse within your applications.</p>
<p>Don&#8217;t forget that you download the <a href='http://www.stevehollis.com/wp-content/uploads/2010/04/traits.zip'>complete source code</a>.</p>
<p>Please let me know what you think by leaving a comment <img src='http://www.stevehollis.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.stevehollis.com/2010/04/trait-like-functionality-for-php/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

