views:

306

answers:

3

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!

+1  A: 

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: This approach will not work, because the PHP Reflection API doesn't support invoking private methods.

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");
$result = $reflection_method->invoke($demo, NULL);
Dathan
This should result in a ReflectionException ('Trying to invoke private method from scope ReflectionMethod').
webbiedave
Doh! You're right - my apologies.
Dathan
+2  A: 

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.

buggedcom
+3  A: 

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?!!';
    }
}

$reflector = new ReflectionClass('LockedGate');
$reflector->getMethod('open')->setAccessible(true);
$unlockedGate = $reflector->newInstance();
echo $unlockedGate->open();
webbiedave
+1 I agree with webbiedave
falomir
that's exactly what I was looking for. I'm currently using PHP 5.2.3 in the dev environment, but we're in the migration process so that helps me a lot!!+1
Pablo López Torres