Violating OOP Encapsulation in PHP

So you NEED to access a protected or private variable in an instantiated object and you can’t just extend the class because of some sort of hard coded labyrinthine factory class made from thousands of lines of code.  Oh and for good measure it needs to be a installed as a plugin so modifying the base code is not possible.

Well sucks to be you!

Fortunately as of PHP 5.4 you can now break the OOP encapsulation protection and awaken Cthulhu from his sleep in Ry’leh… sort of.

Using those pretty things called Closures you can now bind a function into the scope of an instantiated object and access all those protected and private variables that the other developers worked so hard to keep away from you.

class A {
  private $secret;
  protected $hidden;
  function __constructor ($var1, $var2) {
    $this->secret = $var1;
    $this->hidden = $var2;
  }

  function showSecrets() {
    echo $this->secret;
  }
}

$a = new A("inside the llama\n", "are grand machinations\n");
$a->showSecrets();
$func1 = function($newSecret) {
  $this->secret = $newSecret;
};
//bind a new function into the scope of the
//instantiated object
$a->newFunc = $func1->bindTo($a, $a);
//Using the __invoke magic function because the objects
//doesn't recognise that the function is a callable
//because it isn't in the method table
$a->newFunc->__invoke("outside the llama\n");
$a->showSecrets();

$func2 = function($newHidden) {
  echo $this->hidden;
  $this->hidden = $newHidden;
  echo $this->hidden;
};

$func3 = function() {
  //Calling a method that doesn't even exist yet.
  $this->oldTownFunk->__invoke("get the func\n");
};
//Bind it to oldTownFunk just because we can.
$a->oldTownFunk = $func2->bindTo($a, $a);
$a->func3 = $func3->bindTo($a, $a);
//Summon Cthulhu
$a->func3->__invoke();

print_r($a);

Here is what the console outputs:

inside the llama
outside the llama
are grand machinations
get the func
A Object
(
    [secret:A:private] => outside the llama
    [hidden:protected] => get the func
    [newFunc] => Closure Object
        (
            [this] => A Object
 *RECURSION*
            [parameter] => Array
                (
                    [$newSecret] => 
                )
        )
    [oldTownFunk] => Closure Object
        (
            [this] => A Object
 *RECURSION*
            [parameter] => Array
                (
                    [$newHidden] => 
                )
        )
    [func3] => Closure Object
        (
            [this] => A Object
 *RECURSION*
        )
)

So what is happening? Well when you call bindTo on a Closure you get a clone of it with the $this of the function set to whatever object you passed in. The function doesn’t actually exist in the method table but as its independent object. This returned Closure can be called after it is bound and will be executed in the scope defined. But if you want to chain multiple methods(e.g. in a foreach loop etc) then you can set a property of the instantiated object to the new Closure and call it from inside another Closure using the magical __invoke function while passing the variables you would pass to the Closure through it.

Warning using this may sacrifice your first born to Yog-Sothoth or break everything in your program or library so use with caution.

Posted in PHP

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s