Last active
November 18, 2022 23:58
-
-
Save johnkary/904de9171396909c1842 to your computer and use it in GitHub Desktop.
Exposing protected and private object methods using \Closure::bindTo(). Code below requires PHP 5.6+ due to argument unpacking (...$args). Could probably be written for PHP 5.4+ but didn't want to reinvent argument unpacking, else could also just use the Reflection implementation.
This file contains hidden or 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 | |
| class User { | |
| private $firstname; | |
| private $lastname; | |
| public function __construct($f, $l) { | |
| $this->firstname = $f; | |
| $this->lastname = $l; | |
| } | |
| private function buildFullName() { | |
| return sprintf('%s %s', $this->firstname, $this->lastname); | |
| } | |
| private function greeting($say) { | |
| return sprintf('%s, %s', $say, $this->buildFullName()); | |
| } | |
| private function greetingToUser($say, User $user) { | |
| return sprintf('%s from %s', $this->greeting($say), $user->buildFullName()); | |
| } | |
| } | |
| /** | |
| * Exposes result of a protected/private method call outside the | |
| * object's scope. | |
| * | |
| * @param object $object Object on which to call method | |
| * @param string $method Method to call | |
| * @param array $args Arguments to be unpacked and passed to Method | |
| * @return mixed Result of invoking Method on Object given Arguments | |
| */ | |
| function xray($object, $methodToExpose, array $args = []) { | |
| $fn = function () use ($methodToExpose, $args) { | |
| return $this->$methodToExpose(...$args); | |
| }; | |
| $exposed = $fn->bindTo($object, $object); | |
| return $exposed(); | |
| }; | |
| // The traditional way | |
| function xray_reflection($object, $methodToExpose, array $args = []) { | |
| $m = new \ReflectionMethod($object, $methodToExpose); | |
| $m->setAccessible(true); | |
| return $m->invoke($object, ...$args); | |
| }; | |
| $john = new User('John', 'Kary'); | |
| $chris = new User('Chris', 'Escalante'); | |
| echo implode("\n", [ | |
| xray($john, 'greeting', ['Hello']), | |
| xray_reflection($chris, 'greetingToUser', ['Hello', $john]), | |
| ]); | |
| // Output: | |
| // Hello, John Kary | |
| // Hello, Chris Escalante from John Kary |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this!
I ran into the problem of the
(new ReflectionMethod($object, 'method'))->invoke(...)method not respectingdeclare(strict_types=1)whereas this Closure method does 👍