The theory goes that forcibly overriding Class behaviour from outside its scope is bad practice. However, in the real world we developers often times find ourselves having to adapt to, or work on top of, existing code outside of our control. That’s where hacks like these come in handy, though you should really use them with caution, and always because there’s no other choice available.
The Array Cast Override
This is the conceptually simplest method I’ve found, and the only one I know that works on PHP versions previous to 5.3. It involves casting an Object as an Array, and looking through the Array elements for the property you need. When doing this, the index of the Array element corresponding to each property is named according to special rules, depending on its visibility inside the Object. The next pseudo-code snippet shows these rules:
switch ($visibility) {
case 'public':
$array_index = $property_name;
break;
case 'protected':
$array_index = "\0*\0" . $property_name;
break;
case 'private':
$array_index = "\0" . $class_name . "\0" . $property_name;
break;
}
This means that the way you access the property depends on its visibility. As you can see PHP sandwiches either an asterisk or the Class name (depending on if the visibility is protected or private, respectively) between two NULL bytes, and prepends this to the property name to form the Array index. You can thus access the hidden properties of an object as follows:
class MyExampleClass //example of a class with hidden properties
{
public $myPublicVar = "I'm public!";
protected $myProtectedVar = "I'm protected!";
private $myPrivateVar = "I'm private!";
}
$obj = new MyExampleClass();
$obj_array = (Array)$obj; //cast the object as an Array
echo $obj_array['myPublicVar']; //echoes: I'm public!
echo $obj_array["\0*\0" . 'myProtectedVar']; //echoes: I'm protected!
echo $obj_array["\0" . 'MyExampleClass' . "\0" . 'myPrivateVar']; //echoes: I'm private!
The type of the property doesn’t matter, I’ve even accessed resource handlers this way.
The Reflection Override (PHP >= 5.3)
When talking about overriding a property’s visibility, this is the method most seasoned developers know. Using the Reflection Class, you reflect an existing object and change the accessibility of each property you need by using the ReflectionProperty::setAccessible method. Here is an example:
class MyExampleClass //example of a class with hidden properties
{
public $myPublicVar = "I'm public!";
protected $myProtectedVar = "I'm protected!";
private $myPrivateVar = "I'm private!";
}
$obj = new MyExampleClass();
$refObj = new ReflectionObject($obj);
$refProp1 = $refObj->getProperty('myProtectedVar');
$refProp1->setAccessible(TRUE);
$refProp2 = $refObj->getProperty('myPrivateVar');
$refProp2->setAccessible(TRUE);
echo $refProp1->getValue($obj); //echoes: I'm protected!
echo $refProp2->getValue($obj); //echoes: I'm private!
Using Reflection is supposedly really slow, but the upside is that you can not only read the value of the property, but also change it using the ReflectionProperty::setValue method.
The Closure Bind Override (PHP >= 5.4)
This is the newest method I’ve come across, and it’s also the quickest and most painless one. It uses the bind static method of the Closure class to bind a Closure to our Object, which we’ll use to return the properties we want. The usage is really straightforward:
class MyExampleClass //example of a class with hidden properties
{
public $myPublicVar = "I'm public!";
protected $myProtectedVar = "I'm protected!";
private $myPrivateVar = "I'm private!";
}
$obj = new MyExampleClass();
$propGetter = Closure::bind( function($prop){return $this->$prop;}, $obj, $obj );
echo $propGetter('myProtectedVar'); //echoes: I'm protected!
echo $propGetter('myPrivateVar'); //echoes: I'm private!
It works almost like magic, the disadvantage being that most shared hosting providers are lazy and haven’t bothered to update their PHP versions since the Late Pleistocene. If you can use it, this is the method I would recommend the most.
Do you know any other methods to access hidden properties of objects? If so, I would love to read you comments below.
Acknowledgements and References