Web Designing, Web Development, Website Design, Website Development, SEO

0091 98233 72069

COGS: CUSTOMISED, OPTIMISED, GENERALISED WEB DESIGN & WEB DEVELOPMENT SOLUTIONS

Partial Classes in PHP

Partial Classes in PHP

One of my favorite features of C# is Partial Classes. For the uninitiated, it is a way of defining a class in two separate locations. Very useful when you have code generation utilities such as LINQ.

Unfortunately, PHP has no such feature (though if anyone’s listening it would be a great feature to add to the PHP6 feature list), however thanks to the magic of __call($method, $args), __get($key), and __set($key, $value) overload functions as well as passing by reference (aah the good ol’ &) we can imitate partial classes.

The idea behind this partial class hack is to instance a copy of the partial class in question and have our magic functions forward any undefined requests to the partial class.

The partial class (probably with the naming convention Partial_CLASSNAME) will contain a reference to the main class and also have magic functions forwarding undefined requests to the main class. The reason why we have our magic functions in the partial class is so that any internal references can still be made (methods in Partial_CLASSNAME must have access to the methods and members in CLASSNAME).

The constructor in the main class will automatically seek out the partial class (and additional coding can be done to seek out more than 1 partial class as well as do some integrity checking) so that the programmer does not have to intervene to form the ‘full class’.

Here’s some sample code:

class MainClass
{
private $_partial;

public $a = ‘a’;

public function __construct()
{
if( class_exists(“Partial_” . __CLASS__) )
{
$partial = “Partial_” . __CLASS__;
$this->_partial = new $partial($this);
}
}

public function __call($method, $args)
{
return call_user_func_array( array($this->_partial, $method), $args );
}

public function __get($key)
{
return $this->_partial->$key;
}

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

class Partial_MainClass
{
private $_parent;

public $b = ‘b’;

public function __construct(&$parent)
{
$this->_parent = $parent;
}

public function foo()
{
$this->a = ‘c’;
return ‘foo called’;
}

public function __call($method, $args)
{
if( function_exists( array($this->_parent, $method) ) )
return call_user_func_array( array($this->_parent, $method), $args );
else
trigger_error(“Call to undefined method ” . get_class($this->_parent) . “::” . $method, E_USER_ERROR);
}

public function __get( $key )
{
if( isset($this->_parent->$key) )
return $this->_parent->$key;
}

public function __set( $key, $value )
{
if( isset($this->_parent->$key) )
$this->_parent->$key = $value;
}
}

$tmp = new MainClass();

echo “$tmp->a: ” . $tmp->a . “”;
echo “$tmp->b: ” . $tmp->b . “”;
echo “$tmp->foo(): ” . $tmp->foo() . “”;
echo “$tmp->a: ” . $tmp->a . “”;
echo “$tmp->b: ” . $tmp->b . “”;

And the output is going to look something like:

$tmp->a: a
$tmp->b: b
$tmp->foo(): foo called
$tmp->a: c
$tmp->b: b

Performing a var_dump() on $tmp gives us:

object(MainClass)[1]
protected ‘_partial’ =>
object(Partial_MainClass)[2]
protected ‘_parent’ =>
&object(MainClass)[1]
public ‘b’ => string ‘b’ (length=1)

public ‘a’ => string ‘c’ (length=1)

If you call a function that doesn’t exist in either class, the trigger_error() in the Partial_MainClass will throw an error message. This is, of course, to prevent having an infinite loop of having each class call each other to find the non-existant function.

The big limitation is accessing private and protected members and methods, however with a small amount of time, the PHP5 Reflection API should replace the call_user_func_array() and provide access to the private and protected members and methods.

Ignoring the limitations, the sample code above achieves what it sets out to accomplish: combines two classes so that the rest of the code sees it as a unified object.

Reference/ original post : http://www.toosweettobesour.com/2008/05/01/partial-classes-in-php