Я хочу получить доступ к частным методам и переменным извне классов в очень редких случаях.
Я видел, что это невозможно, хотя интроспекция используется.
Конкретный случай следующий:
Я хотел бы иметь что-то вроде этого:
class Console { final public static function run() { while (TRUE != FALSE) { echo "\n> "; $command = trim(fgets(STDIN)); switch ($command) { case 'exit': case 'q': case 'quit': echo "OK+\n"; return; default: ob_start(); eval($command); $out = ob_get_contents(); ob_end_clean(); print("Command: $command"); print("Output:\n$out"); break; } } } }
Этот метод должен быть введен в код следующим образом:
Class Demo { private $a; final public function myMethod() { // some code Console::run(); // some other code } final public function myPublicMethod() { return "I can run through eval()"; } private function myPrivateMethod() { return "I cannot run through eval()"; } }
(это просто одно упрощение: реальный идет через сокет и реализует кучу других вещей …)
Так…
Если вы создаете экземпляр класса Demo и вы вызываете $ demo-> myMethod (), вы получите консоль: эта консоль может получить доступ к первому методу, написав команду:
> $this->myPublicMethod();
Но вы не можете успешно запустить второй:
> $this->myPrivateMethod();
Есть ли у вас какие-либо идеи или существует ли какая-либо библиотека для PHP, которая позволяет вам это делать?
Большое спасибо!
Просто сделайте этот метод общедоступным. Но если вы хотите запутаться, вы можете попробовать это (PHP 5.3):
class LockedGate { private function open() { return 'how did you get in here?!!'; } } $object = new LockedGate(); $reflector = new ReflectionObject($object); $method = $reflector->getMethod('open'); $method->setAccessible(true); echo $method->invoke($object);
Первый вопрос, который вы должны задать, если вам нужно получить доступ к нему из-за пределов класса, почему вы объявили его закрытым? Если это не ваш код, у создателя, вероятно, есть веская причина объявить его закрытым, и доступ к нему напрямую – очень плохая (и в значительной степени не поддающаяся контролю) практика.
EDIT : Как указывает Адам В. в комментариях, вы должны сделать доступный метод доступным до его вызова. Обновлен образец кода, чтобы включить это. Я еще не протестировал его, просто добавив сюда, чтобы сохранить ответ.
Чтобы сказать это, вы можете использовать Reflection для этого. getMethod
ReflectionClass
, вызовите getMethod
для метода, который вы хотите вызвать, а затем вызовите вызов на возвращаемом ReflectionMethod
.
Пример кода (хотя я его не тестировал, поэтому могут быть ошибки) может выглядеть так:
$demo = new Demo(); $reflection_class = new ReflectionClass("Demo"); $reflection_method = $reflection_class->getMethod("myPrivateMethod"); $reflection_method->setAccessible(true); $result = $reflection_method->invoke($demo, NULL);
Ниже приведены варианты других ответов, которые можно использовать для создания таких вызовов в одной строке:
public function callPrivateMethod($object, $methodName) { $reflectionClass = new \ReflectionClass($object); $reflectionMethod = $reflectionClass->getMethod($methodName); $reflectionMethod->setAccessible(true); $params = array_slice(func_get_args(), 2); //get all the parameters after $methodName return $reflectionMethod->invokeArgs($object, $params); }
У меня тоже есть эти проблемы, но я обойдусь этим по моим стандартам кодирования. Частные или защищенные функции обозначаются символом подчеркивания префикса, т.е.
private function _myPrivateMethod()
Затем я просто делаю функцию общедоступной.
public function _myPrivateMethod()
Таким образом, хотя функция является общедоступной, соглашение об именах дает уведомление о том, что публикация является частной и ее не следует использовать.
Начиная с PHP 5.4 , вы можете использовать предопределенный класс Closure
для привязки метода / свойства класса к дельта-функциям, имеющим доступ даже к частным членам.
Класс Closure
Например, у нас есть класс с частной переменной, и мы хотим получить к нему доступ за пределами класса:
class Foo { private $bar = "Foo::Bar"; }
PHP 5.4+
$foo = new Foo; $getFooBarCallback = function() { return $this->bar; }; $getFooBar = $getFooBarCallback->bindTo($foo, 'Foo'); echo $getFooBar(); // Prints Foo::Bar
Начиная с PHP 7, вы можете использовать новый метод Closure::call
для привязки любого метода / свойства объекта obect к функции обратного вызова даже для частных членов:
PHP 7+
$foo = new Foo; $getFooBar = function() { return $this->bar; } echo $getFooBar->call($foo); // Prints Foo::Bar
Я думаю, что mirrorClass является единственной альтернативой, если вы действительно хотите выполнить некоторые частные методы. Во всяком случае, если вам просто нужен доступ для чтения к приватным или защищенным свойствам, вы можете использовать этот код:
<?php class Demo { private $foo = "bar"; } $demo = new Demo(); // Will return an object with public, private and protected properties in public scope. $properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo))); ?>
Если вы можете добавить метод в класс, где этот метод определен, вы можете добавить метод, который использует call_user_method () внутренне. Это также работает с PHP 5.2.x
<?php class SomeClass { public function callprivate($methodName) { call_user_method(array($this, $methodName)); } private function somePrivateMethod() { echo 'test'; } } $object = new SomeClass(); $object->callprivate('somePrivateMethod');
Ответ ставится общедоступным для метода. Какой бы трюк вы ни делали, это было бы непонятно другим разработчикам. Например, они не знают, что в каком-то другом коде эта функция была доступна как общедоступная, посмотрев класс Demo.
Еще кое-что. эта консоль может получить доступ к первому методу, написав команду, например:. Как это возможно? Консоль не может получить доступ к функциям демонстрационного класса, используя $ this.
Почему вы не используете защищенные? И расширьте его