Call private methods and private properties from outside a class in PHP

45,645

Solution 1

Just make the method public. But if you want to get tricky you can try this (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);

Solution 2

EDIT: Updated to include examples of private function calls with parameters.

As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.

The Closure class

For example we have a class with a private variable and we want to access it outside the class:

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

As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:

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

Solution 3

The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a very bad (and largely unmaintainable) practice.

EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.

That having been said, you can use Reflection to accomplish this. Instantiate ReflectionClass, call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod.

A code sample (though I haven't tested it, so there may be errors) might look like

$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);

Solution 4

Here's a variation of the other answers that can be used to make such calls one line:

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

Solution 5

I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie

private function _myPrivateMethod()

Then i simply make the function public.

public function _myPrivateMethod()

So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.

Share:
45,645
bastinald
Author by

bastinald

Updated on May 05, 2021

Comments

  • bastinald
    bastinald about 3 years

    I want to access private methods and variables from outside the classes in very rare specific cases.

    I've seen that this is not be possible although introspection is used.

    The specific case is the next one:

    I would like to have something like this:

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

    This method should be able to be injected in the code like this:

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

    (this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)

    So...

    If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:

    > $this->myPublicMethod();
    

    But you cannot run successfully the second one:

    > $this->myPrivateMethod();
    

    Do any of you have any idea, or if there is any library for PHP that allows you to do this?

    Thanks a lot!