Last active
August 29, 2015 14:08
-
-
Save zburgermeiszter/13e1515b2dae86a41933 to your computer and use it in GitHub Desktop.
Access $this from Closure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* In PHP 5.3 you can't access $this from anonymous functions, even if you inject $this to them, you still can't access private functions. | |
* Here's the workaround. With this you can inject $this to anonymous function and after calling publishPrivate() | |
* You'll be able to call private member functions when you need. | |
* All of them would't be needed in PHP 5.4 (but fortunately compatible with php 5.4 :) | |
*/ | |
var_dump(phpversion()); | |
class C | |
{ | |
private $publicPrivate = false; | |
public function publishPrivate() | |
{ | |
$this->publicPrivate = true; | |
return $this; | |
} | |
private function func() | |
{ | |
return "Private result"; | |
} | |
/** | |
* PHP Magic method override to expose private methods. | |
* @param $name | |
* @param $arguments | |
* @return bool|mixed | |
*/ | |
public function __call($name, $arguments) | |
{ | |
$ro = new \ReflectionObject($this); | |
$methodExists = $ro->hasMethod($name); | |
if ($methodExists) { | |
$rm = new \ReflectionMethod($this, $name); | |
} else { | |
return false; | |
} | |
$callablePublic = $methodExists && is_callable(array($this, $name)) && !$rm->isPrivate() && !$rm->isProtected(); | |
$callablePrivate = $methodExists && $this->publicPrivate; | |
$callable = $callablePublic || $callablePrivate; | |
if ($callable) { | |
$this->publicPrivate = false; // unpublish private (!) | |
return call_user_func_array(array($this, $name), $arguments); | |
} else { | |
return new FatalErrorException("Error: Call to private method " . $name . "()"); | |
} | |
} | |
/** | |
* PHP magic method override to expose private properties. | |
* @param $name | |
* @throws FatalErrorException | |
* @return bool|mixed | |
*/ | |
public function __get($name) | |
{ | |
$ro = new \ReflectionObject($this); | |
$propertyExists = $ro->hasProperty($name); | |
if ($propertyExists) { | |
$rp = new \ReflectionProperty($this, $name); | |
} else { | |
return false; | |
} | |
$propertyPublic = $propertyExists && !$rp->isPrivate() && !$rp->isProtected(); | |
$propertyPrivate = $propertyExists && $this->publicPrivate; | |
$accessible = $propertyPublic || $propertyPrivate; | |
if ($accessible) { | |
$this->publicPrivate = false; // unpublish private (!) | |
return $this->$name; | |
} else { | |
throw new FatalErrorException("Error: Cannot access private property $" . $name); | |
} | |
} | |
public function callPrivateFunctionFromClosure() | |
{ | |
$self = $this; // Force inject $this | |
$callPrivate = function() use ($self) | |
{ | |
return $self->publishPrivate()->func(); | |
}; | |
return $callPrivate(); | |
} | |
} | |
$c = new C(); | |
echo $c->callPrivateFunctionFromClosure(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment