DEV Community

Cover image for Private parts exposed in public

Private parts exposed in public

belinde profile image Franco Traversaro ・2 min read

It's said that a good object keeps private or protected his properties, so nobody can harm the business logic. It's a wise advice, indeed, but sometimes we want to break things: maybe we need to gain access of a private connection managed by an external library, maybe we just want to see the world burn. An example of the first case happened to me a lot of years ago, when I was working on a strange Wordpress integration: I needed the underlying mysqli connection, but it was stored in a dbh property of the $wpdb singleton of class \wpdb. I couldn't edit the class to make dbh property public, but I needed the connection. What to do? We all know that a private or protected properties cannot be accessed from outside the instance through -> operator! A $object->privateProp will always fail!

That's not entirely true. Quite, but not entirely. There's a little detail that I think it's not so known: the access control to methods and properties is done checking the context from which we are working. So, if we are inside a method of the class, we can access private or protected properties of any instance of that class.

Enough talk, let's do some code. Imagine that we have a third-party library, that we cannot modify, that do this kind of things:

// begin read only code

class DeepThought {
    protected $theAnswer = 42;
    private $theQuestion = 'How many roads...';

$singleton = new DeepThought();

// end read only code
Enter fullscreen mode Exit fullscreen mode

We disperately want to know theAnswer: we know that is protected, so we can work on it. We know that a protected property can be accessed from extended classes, so we write this piece of code:

class Towel extends DeepThought {
    public static function getTheAnswer(DeepThought $instance): int
        return $instance->theAnswer;

echo Towel::getTheAnswer($singleton);
Enter fullscreen mode Exit fullscreen mode

Do you see the magic? Towel extends DeepThought, so can legitimately access his protected properties. When we call Towel::getTheAnswer() we are in the Towel context, so $instance->theAnswer is also legit.

But theAnswer is merely protected, and we also want to know theQuestion, that's private. Extending the class we still have not access to private properties... we need a bigger towel! :-)

Reflection comes to the rescue:

$refl = new ReflectionProperty(DeepThought::class, 'theQuestion');

echo $refl->getValue($singleton);
Enter fullscreen mode Exit fullscreen mode

Note that Reflection works also on protected properties, but I've presented it last for the sake of narration. We just instantiate a ReflectionProperty for theQuestion: that's like a tool that can inspect or edit some attributes without changing the code. After we use the reflection to make the property accessible, and lastly we apply our edited property description to the original object. It's like .call() in JavaScript.

That's all! With these two techniques you can tear apart any class to extract the gems inside. But stay wise! Objects with private properties often have good reasons to be designed that way. No developer take care of backward compatibility for private properties: as in real life, if you play with other's private parts without consent you can get in trouble!

Discussion (2)

Editor guide
itsasine profile image
ItsASine (Kayla)

I don't know a lick of PHP, I just want to commend you for the best title ever.

pkristiancz profile image
Patrik Kristian

Hey i like this trick. did not know :)