Вызовите приватные методы и приватные свойства извне класса в PHP - PullRequest
14 голосов
/ 29 апреля 2010

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

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

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

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

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

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

Ответы [ 9 ]

54 голосов
/ 29 апреля 2010

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

EDIT: Обновлено, чтобы включить примеры вызовов частных функций с параметрами.

Начиная с PHP 5.4 , вы можете использовать предопределенный класс Closure для привязки метода / свойства класса к дельта-функциям, которые имеют доступ даже к закрытым членам.

Класс закрытия

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

class Foo {
    private $bar = "Foo::Bar";
    private function add_ab($a, $b) {
        return $a + $b;
    }
}

PHP 5,4 +

$foo = new Foo;

// Single variable example
$getFooBarCallback = function() {
    return $this->bar;
};

$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');

echo $getFooBar(); // Prints Foo::Bar

// Function call with parameters example
$getFooAddABCallback = function() {
    // As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
    return call_user_func_array(array($this, 'add_ab'), func_get_args());
};

$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');

echo $getFooAddAB(33, 6); // Prints 39

Начиная с PHP 7, вы можете использовать новый метод Closure::call, чтобы связать любой метод / свойство объекта с функцией обратного вызова, даже для закрытых членов:

PHP 7 +

$foo = new Foo;

// Single variable example
$getFooBar = function() {
    return $this->bar;
};

echo $getFooBar->call($foo); // Prints Foo::Bar

// Function call with parameters example
$getFooAddAB = function() {
    return $this->add_ab(...func_get_args());
};

echo $getFooAddAB->call($foo, 33, 6); // Prints 39
4 голосов
/ 29 апреля 2010

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

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

При этом вы можете использовать Отражение для достижения этой цели. Создайте 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 голосов
/ 02 августа 2013

Вот вариант других ответов, которые можно использовать для таких вызовов в одну строку:

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);
}
2 голосов
/ 29 апреля 2010

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

private function _myPrivateMethod()

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

public function _myPrivateMethod()

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

1 голос
/ 20 декабря 2013

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

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

0 голосов
/ 05 ноября 2016

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

0 голосов
/ 02 декабря 2013

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

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

?>
...