romanitalian notes / Using a private method in PHP - "outside"

В PHP нет способа вызвать "извне" метод объекта или класса с модификатором доступа "private". Но есть несколько не очень красивых, но рабочих способа обойти эти ограничения.

Возможные случаи практического применения, на рабочих проектах, этих подходов - единицы.

А также:

Вот эти несколько вариантов использования:

-----------------------

Вариант 1:

source: http://php.net/manual/ru/closure.bindto.php#111379

use_trait.php
<?php

trait DynamicDefinition
{

    public function __call($name, $args) {
        if(is_callable($this->$name)) {
            return call_user_func($this->$name, $args);
        } else {
            throw new \RuntimeException("Method {$name} does not exist");
        }
    }

    public function __set($name, $value) {
        $this->$name = is_callable($value) ?
            $value->bindTo($this, $this) :
            $value;
    }
}

class Foo
{
    use DynamicDefinition;
    private $privateValue = 'I am private';
}

$foo = new Foo;
$foo->bar = function () {
    return $this->privateValue;
};

var_dump($foo->bar()); // 'I am private'


string 'I am private' (length=12)



Вариант 2:

source: http://rmcreative.ru/blog/post/vyzvat-private-metod-klassa-v-php

use_ReflectionClass.php
<?php

class MyClass
{
    private function privateMethod($args) {
        return $args;
    }
}

function callPrivateMethod($object, $method, $args) {
    $classReflection = new \ReflectionClass(get_class($object));
    $methodReflection = $classReflection->getMethod($method);
    $methodReflection->setAccessible(true);
    $result = $methodReflection->invokeArgs($object, $args);
    $methodReflection->setAccessible(false);
    return $result;
}

$t = callPrivateMethod(new MyClass(), 'privateMethod', ['world with ReflectionClass']);
var_dump($t);

string 'world with ReflectionClass' (length=26)



Вариант 3:

use_Closure_bindTo.php
<?php

class MyClass
{
    private function privateMethod($args) {
        return $args;
    }

    function callPrivate($object, $method, $args) {
        $caller = function ($method, $args) {
            return call_user_func_array([$this, $method], $args);
        };
        $caller->bindTo($object, $object);
        return $caller($method, $args);
    }
}

$privacyViolator = new MyClass();
$t = $privacyViolator->callPrivate(new stdClass(), 'privateMethod', ['world use_Closure_bindTo']);
var_dump($t);

string 'world use_Closure_bindTo' (length=24)



Вариант 4:

source: http://rmcreative.ru/blog/post/vyzvat-private-metod-klassa-v-php-bez-reflection#c9851

use_ReflectionClass2.php

<?php

class PrivacyViolator
{
    public function callPrivateMethod($object, $method, array $args = array()) {
        if(!is_object($object)) {
            throw new \InvalidArgumentException('The $object param must be object');
        }
        $className = get_class($object);
        $method = new \ReflectionMethod($className, $method);
        $method->setAccessible(true);
        return $method->invokeArgs($object, $args);
    }
}

class MyClass
{
    private function hello($name) {
        return 'Hello '.$name;
    }
}

$myObject = new MyClass();
$privacyViolator = new PrivacyViolator();

$result = $privacyViolator->callPrivateMethod($myObject, 'hello', array('World'));

echo $result;
assert('Hello World' === $result);

Hello World