How to get protected property of object in PHP

Solution 1:

Here's the really simple example (with no error checking) of how to use ReflectionClass:

function accessProtected($obj, $prop) {
  $reflection = new ReflectionClass($obj);
  $property = $reflection->getProperty($prop);
  $property->setAccessible(true);
  return $property->getValue($obj);
}

I know you said you were limited to 5.2, but that was 2 years ago, 5.5 is the oldest supported version and I'm hoping to help people with modern versions.

Solution 2:

Object can be typecasted into (associative) array and the protected members have keys prefixed with chr(0).'*'.chr(0) (see @fardelian's comment here). Using this undocummented feature you can write an "exposer":

function getProtectedValue($obj, $name) {
  $array = (array)$obj;
  $prefix = chr(0).'*'.chr(0);
  return $array[$prefix.$name];
}

Alternatively, you can parse the value from serialized string, where (it seems) protected members have the same prefix.

This works in PHP 5.2 without the overhead of ReflectionClass. However, there are reasons why some property is protected and hidden from client code. The reading or writing can make the data inconsistent or the author provides some other way to expose it in effort to make the interface as lean as possible. When there are reasons to read the protected property directly, the then-correct approach was to implement __get() magic method, so always check if there is any and see what it does. This counter intuitive lookup was finally solved in PHP 8.1 with readonly properties.

Since PHP 8.0, there also attributes metadata accessible by ReflectionClass, make sure to check them also before performing attempts to break into protected members. Attributes superseded "Annotations"1, so check them, too.

1: annotations are a very nasty surprise to client coders: they parse comments to add crazy fancy black-box useless confusing functionality, should not be used anymore, but they still exist

Solution 3:

That's what "protected" is meant for, as the Visibility chapter explains:

Members declared protected can be accessed only within the class itself and by inherited and parent classes.

If you need to access the property from outside, pick one:

  • Don't declare it as protected, make it public instead
  • Write a couple of functions to get and set the value (getters and setters)

If you don't want to modify the original class (because it's a third-party library you don't want to mess) create a custom class that extends the original one:

class MyFields_Form_Element_Location extends Fields_Form_Element_Location{
}

... and add your getter/setter there.