Как известно, в (наверное) любом ООП-языке поддерживаются области видимости переменных и методов класса (public, protected, private). И, разумеется, получить доступ напрямую к protected и тем более private извне не получится в штатном режиме.
Но, как говорится, если нельзя, но очень хочется, то можно. Можно к ним получить доступ. И есть тут «два путя»: первый широко известен, и называется он Reflection, его я описывать не буду. А вот второй мне открылся совершенно внезапно, когда я читал официальную документацию по замыканиям.
Суть проста до банальности: создавая замыкание, мы можем привязать его к абсолютно любому объекту, таким образом, что $this в этом замыкании будет ссылаться на привязанный объект. При этом при желании, все protected и private поля/методы этого объекта тоже могут быть доступны.
Практика
Для теста напишем простой класс-«интроверт», который решил все закрыть от внешнего мира.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class A { private $name; public function __construct($name) { $this->name = $name; } private function writeName() { echo "CONFIDENTIAL:: name == " . $this->name . PHP_EOL; } } $a = new A("Amegatron"); |
Как видно, его можно только создать, передав имя в конструкторе. И все … Ни получить имя обратно, ни вызвать его методы уже не получится, так как всё private.
Но мы пойдем по грязному пути и получим эти данные при помощи замыкания. Для начала получим доступ к закрытой переменной $name :
1 2 3 4 5 |
$getter = Closure::bind(function($var) { return $this->{$var}; }, $a, $a); $name = $getter("name"); |
Теперь $name содержит «Amegatron» 🙂
С приватными методами все аналогично:
1 2 3 4 5 |
$caller = Closure::bind(function($method, $args = []) { return call_user_func_array([$this, $method], $args); }, $a, $a); $caller("writeName"); |
На экран выведется:
1 |
CONFIDENTIAL:: name == Amegatron |
Заключение
Как видим, получить доступ к приватным элементам объекта можно и без рефлексии. Какой в этом смысл? А никакого 🙂 Поскольку приватные данные — это приватные данные. Просто, интересная возможность. Да, бывает иногда хочется получить доступ к закрытым данным какой-то библиотеки. Но я бы все равно не рекомендовал так поступать. В крайнем случае лучше форкнуть эту библиотеку и раскрывать нужные вам данные и методы. Да и в конце концов, рефлексию никто не отменял 🙂
Cheers 🙂