Вызовите частные методы и частные свойства извне класса в PHP

Я хочу получить доступ к приватным методам и переменным извне классов в очень редких случаях.

Я видел, что это невозможно, хотя интроспекция используется.

Конкретный случай следующий:

Я хотел бы иметь что-то вроде этого:

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, которая позволяет вам это делать?

Спасибо большое!

Ответ 1

Просто сделайте этот метод общедоступным. Но если вы хотите запутаться, вы можете попробовать это (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);

Ответ 2

Первый вопрос, который вы должны задать, если вам нужно получить доступ к нему из-за пределов класса, почему вы объявили его закрытым? Если это не ваш код, у создателя, вероятно, есть веская причина объявить его конфиденциальным, а доступ к нему напрямую - очень плохая (и в значительной степени не поддающаяся контролю) практика.

РЕДАКТИРОВАТЬ. Как указывает Адам В., в комментариях вам нужно сделать доступным доступ к закрытому методу перед его вызовом. Обновлен образец кода, чтобы включить это. Я еще не протестировал его, просто добавив сюда, чтобы обновить ответ.

Чтобы сказать об этом, вы можете использовать Reflection. Создайте ReflectionClass, вызовите getMethod для метода, который вы хотите вызвать, а затем вызовите invoke в возвращаемом 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);

Ответ 3

Здесь варианты других ответов, которые могут быть использованы для того, чтобы сделать такие вызовы одной строкой:

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);
}

Ответ 4

Как и в случае с 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

Ответ 5

У меня тоже есть такие проблемы, но я обхожу это в своих стандартах кодирования. Частные или защищенные функции обозначаются символом подчеркивания префикса, т.е.

private function _myPrivateMethod()

Затем я просто делаю функцию общедоступной.

public function _myPrivateMethod()

Итак, хотя функция общедоступна, соглашение об именах дает уведомление о том, что публикация является частной и ее не следует использовать.

Ответ 6

Я думаю, что 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)));

?>

Ответ 7

Если вы можете добавить метод в класс, где этот метод определен, вы можете добавить метод, который использует 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');

Ответ 8

Ответ ставится общедоступным для метода. Какой бы трюк вы ни делали, это было бы непонятно другим разработчикам. Например, они не знают, что в каком-то другом коде эта функция была доступна как общедоступная, посмотрев класс Demo.

Еще одна вещь. , что консоль может получить доступ к первому методу, написав команду, например:. Как это возможно? Консоль не может получить доступ к функциям демонстрационного класса, используя $this.

Ответ 9

Почему вы не используете защищенные? И расширьте его