<?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>john wyles dot com &#187; magic</title>
	<atom:link href="http://johnwyles.com/tag/magic/feed/" rel="self" type="application/rss+xml" />
	<link>http://johnwyles.com</link>
	<description>a man a plan a blog san francisco</description>
	<lastBuildDate>Tue, 08 Jun 2010 06:02:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>PHP Magic Accessors Make Me Want to Punch Babies</title>
		<link>http://johnwyles.com/2010/02/10/php-magic-accessors-make-me-want-to-punch-babies/</link>
		<comments>http://johnwyles.com/2010/02/10/php-magic-accessors-make-me-want-to-punch-babies/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 06:30:18 +0000</pubDate>
		<dc:creator>John Wyles</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[accessors]]></category>
		<category><![CDATA[getter]]></category>
		<category><![CDATA[magic]]></category>
		<category><![CDATA[setter]]></category>
		<category><![CDATA[__get]]></category>
		<category><![CDATA[__set]]></category>

		<guid isPermaLink="false">http://johnwyles.com/?p=123</guid>
		<description><![CDATA[As many know PHP have dynamic methods (or magic methods) for producing an environment that, at run-time, is much different than one conceives at first blush.  It is largely the inclusion of these magic methods that brought PHP forward and lead to many elegant and inventive solutions.  These can be found in nearly [...]]]></description>
			<content:encoded><![CDATA[<p>As many know PHP have dynamic methods (or <a href="http://php.net/manual/en/language.oop5.magic.php">magic methods</a>) for producing an environment that, at run-time, is much different than one conceives at first blush.  It is largely the inclusion of these magic methods that brought PHP forward and lead to many elegant and inventive solutions.  These can be found in nearly every major framework and library that scatter the PHP landscape.  Indeed, they let you do very crafty things; take, for example, allowing for the custom <a href="http://framework.zend.com/code/browse/Zend_Framework/trunk/library/Zend/Controller/Action.php?r=8235#l463">dispatch of controller actions</a> in Zend Framework or how Doctrine uses them to <a href="http://trac.doctrine-project.org/browser/trunk/lib/Doctrine/ORM/Mapping/ClassMetadata.php?annotate=blame&#038;rev=7100#L311">perform serialized caching</a> for objects.  These examples really can really show off what PHP&#8217;s best intentions are.  However, like any tool, what it was intended for, and what others are using it for, in practice, can often be at odds.  My beef is with the magic accessors and the way I see them employed in many scenarios.</p>
<p>The use of the magic accessors (__get and __set) have allowed for the rapid growth and expansion of objects beyond anyones wildest dreams and now we are paying severely for the bloat and overhead.  On top of that, often coupled with this, is the lack of validation of values following overly optimistic assumptions about the values being set.  Let me show an example of such a class to make this more clear:</p>
<pre class="brush:php">
class User
{
    protected $_data=array();

    public function &#038;__get($key)
    {
        $value = null;
        if (isset($this->_data[$key])) {
            $value = $this->_data[$key];
        }

        return $value;
    }

    public function __set($key, $value)
    {
        $this->_data[$key] = $value;
    }

    public function __isset($key)
    {
        return isset($this->_data[$key]);
    }

    public function __unset($key)
    {
        unset($this->_data[$key]);
    }
}
</pre>
<p>What this now affords developers is the ability to, anywhere in code where they have a User object instance, create arbitrary invalidated values on the User object:</p>
<pre class="brush:php">
for($i=0; $i<1000000; $i++) {
    array_push($user->foo, new Foo($i));
}
$user->bar = 45.352135;
$user->baz = 'I CAN HAZ ANY VALUE I WANT! MUHAHAHA!';
$user->bat = memcache_get('some_invalid_value_from_mc');
// ...
var_dump(strlen(serialize($user))); // => 134523592
</pre>
<p>My argument centers around the misuse of these magic accessors, particularly in the case where you are persisting the object (as would most likely be the case for a User object). If you have a value you are putting into an object you should be able to, in a very straightforward manner, validate it (see my post <a href="/2010/01/21/a-tailored-approach-to-object-validation">A Tailored Approach to Object Validation</a>).  What better way than to explicitly specify an instance variable and a getter and setter method for it?  You can still use the magic accessors but perhaps as a catch all for values which seemed to appear out of thin air.  Take, for example, the way I think most setups should be done or modeled to closely resemble:</p>
<pre class="brush:php">
class User
{
    protected $_name;
    protected $_age;
    /* ... */

    public function getAge()
    {
        return $this->_age;
    }

    public function getName()
    {
        return $this->_name;
    }

    public function setAge($age)
    {
        $minimumAge = 0;
        $maximumAge = 130;
        $validator = new Validator_Integer_Between($minimumAge, $maximumAge);
        if (!$validator->valid($age)) {
            throw new ValidationException('The age attribute must be between the values [' . $minimumAge . '] and [' . $maximumAge . ']');
        }

        $this->_age = $age;
    }

    public function setName($name)
    {
        $regEx = "/^[A-Za-z]+$/";
        $validator = new Validator_String_Matches($regEx);
        if (!$validator->valid($name)) {
            throw new ValidationException('The name attribute must match the regular expression pattern [' . $regEx . ']');
        }

        $this->_name = $name;
    }

    public function __get($key)
    {
        throw new Exception('User::__get(' . $key . '): Attempt to get a non-existent attribute [' . $key . ']');
    }

    public function __set($key, $value)
    {
        throw new Exception('User::__set(' . $key . ', ' . $value . '): Attempt to set a non-existent attribute [' . $key . '] to value [' . $value . ']');
    }

    public function __isset($key)
    {
        throw new Exception('User::__isset(' . $key . '): Attempt to check for non-existent attribute [' . $key . ']');
    }

    public function __unset($key)
    {
        throw new Exception('User::__unset(' . $key . '): Attempt to unset a non-existent attribute [' . $key . ']');
    }
}
</pre>
<p>As you can see any value that &#8220;falls through the cracks&#8221; will be caught and dealt with.  In this way we are able to implement any craziness in the magic accessors, should we ever need do anything &#8220;magical&#8221;, and use concrete getters and setters so we are able to more readily (and cleanly) allow for the validation of every value set into our object, not to mention its also faster.  If you have a million values in your user object you should have at least two million accessor methods (1 million gets, and 1 million sets).  Adding a new attribute to the class, creating its getter method, and its setter method forces you to think about what you are doing and whether you need the value or not.</p>
<iframe src="http://www.facebook.com/plugins/like.php?href=http%3A%2F%2Fjohnwyles.com%2F2010%2F02%2F10%2Fphp-magic-accessors-make-me-want-to-punch-babies%2F&amp;layout=button_count&amp;&amp;width=200&amp;action=like&amp;colorscheme=light" scrolling="no" frameborder="0" allowTransparency="true" style="border:none; overflow:hidden; width:200px;height:40px;margin-top:5px;"></iframe>]]></content:encoded>
			<wfw:commentRss>http://johnwyles.com/2010/02/10/php-magic-accessors-make-me-want-to-punch-babies/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
