<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom"><title>Javascript Prototype Behaviour in PHP</title><author><name>Matt Read</name></author><link rel="alternate" href="https://mattread.com/javascript-prototype-behaviour-in-php"/><link rel="edit" href="https://mattread.com/javascript-prototype-behaviour-in-php/atom"/><id>tag:mattread.com,2008:javascript-prototype-behaviour-in-php/1222664109</id><updated>2008-09-29T00:55:09-04:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2013-04-20T12:43:28-04:00</app:edited><published>2008-09-29T02:01:57-04:00</published><category term="code"/><category term="php"/><category term="javascript"/><category term="prototype"/><content type="html">One of the "neat" things in Javascript is you are able to dynamically add or change methods of a class and automatically update every instance of that class. Some of the things I usually find useful are adding to the String class, like so: &#xD;
&#xD;
&lt;pre class="highlight javascript"&gt;&#xD;
&lt;![CDATA[&#xD;
String.prototype.htmlSpecialChars = function() {&#xD;
	return this.replace(/\&lt;/g,'&lt;').replace(/\&gt;/g,'&gt;');&#xD;
}&#xD;
String.prototype.trim = function() {&#xD;
	return this.replace(/^\s+|\s+$/g, '');&#xD;
}&#xD;
]]&gt;&#xD;
&lt;/pre&gt;&#xD;
&#xD;
Obviously we cannot do this in PHP, and why would we, right? However we can emulate this behaviour to a certain extent using my "neat" little [Prototype](https://gist.github.com/576295) class. With this Prototype class we can dynamically add properties and methods to any class, and they will be inherited by all instances of that class.&#xD;
&#xD;
Let's look at the following "normal" PHP code.&#xD;
&#xD;
&lt;pre class="highlight php"&gt;&#xD;
&lt;![CDATA[&#xD;
class Person extends Prototype&#xD;
{&#xD;
    public $name;&#xD;
    public $gender;&#xD;
   &#xD;
    public function gender()&#xD;
    {&#xD;
        printf("%s is %s\n", $this-&gt;name, $this-&gt;gender);&#xD;
    }&#xD;
}&#xD;
&#xD;
$matt = new Person;&#xD;
$matt-&gt;name = 'Matt';&#xD;
$matt-&gt;gender = 'male';&#xD;
$matt-&gt;gender();&#xD;
&#xD;
// Matt is male&#xD;
]]&gt;&#xD;
&lt;/pre&gt;&#xD;
&#xD;
Now, there is nothing magical or out-of-the-ordinary going on here. We just instantiate the Person class and setup some properties. Calling the &lt;code&gt;gender()&lt;/code&gt; method outputs a nice little string for us.&#xD;
&#xD;
However, you see that the Person class is actually a child of the Prototype class. This will allow us to do some of that "neat" Javascript stuff. Using Prototype, let us expand the Person class to add an &lt;code&gt;$age&lt;/code&gt; property and an &lt;code&gt;age()&lt;/code&gt; method to output a nice string. Like so:&#xD;
&#xD;
&lt;pre class="highlight php"&gt;&#xD;
&lt;![CDATA[&#xD;
Person::add_property('age');&#xD;
Person::add_method('age', 'printf("%s is a %d year old %s\n", $this-&gt;name, $this-&gt;age, $this-&gt;gender);');&#xD;
&#xD;
$matt-&gt;age = 28;&#xD;
$matt-&gt;age();&#xD;
&#xD;
// Matt is a 28 year old male&#xD;
]]&gt;&#xD;
&lt;/pre&gt;&#xD;
&#xD;
Now all instances of Person inherit the &lt;code&gt;$age&lt;/code&gt; property and &lt;code&gt;age()&lt;/code&gt; method. So we can create a new Person, Susie, and this object will now have the age stuff.&#xD;
&#xD;
&lt;pre class="highlight php"&gt;&#xD;
&lt;![CDATA[&#xD;
$susie = new Person;&#xD;
$susie-&gt;name = 'Susie';&#xD;
$susie-&gt;gender = 'female';&#xD;
$susie-&gt;age = 21;&#xD;
$susie-&gt;age();&#xD;
&#xD;
// Susie is a 21 year old female&#xD;
]]&gt;&#xD;
&lt;/pre&gt;&#xD;
&#xD;
One limitation of the Prototype class though, is you cannot overload a current method. So the following code, that attempts to overload the &lt;code&gt;gender()&lt;/code&gt; method, will not work.&#xD;
&#xD;
&lt;pre class="highlight php"&gt;&#xD;
&lt;![CDATA[&#xD;
Person::add_method('gender', 'printf("%s is a %d year old %s\n", $this-&gt;name, $this-&gt;age, $this-&gt;gender);');&#xD;
&#xD;
$matt-&gt;gender();&#xD;
&#xD;
// Matt is male&#xD;
]]&gt;&#xD;
&lt;/pre&gt;&#xD;
&#xD;
There are also many, many, many other problems with this Prototype class. Some of which are:&#xD;
&#xD;
- The '$this' keyword is reserved, so it actually does a string replace and uses '$self' instead.&#xD;
- You cannot access/add new methods or properties statically (until PHP 5.3 with __callStatic()).&#xD;
- It uses create_function, so every "method" is actually defined in the global namespace.&#xD;
- Iteration does not work, although it could possibly be done with Iterator, Countable, et al.&#xD;
- You cannot reference static variables/methods in your add method.&#xD;
- You cannot share methods between classes.&#xD;
- And so on and so forth...&#xD;
&#xD;
This class was just an experiment to see if it was at all possible to implement something like Javascript's prototype behaviour in PHP with out using the [Runkit PECL extension](http://pecl.php.net/package/runkit). I had no intention of actually making this usable in production, for many reasons ;), although it was fun. </content></entry>
