문제

I am writing an api in PHP. I have got a base class which implemets the magic function __call:

class Controller
{
    public function __call($name, $arguments)
    {
        if(!method_exists($this,$name))
            return false;
        else if(!$arguments)
            return call_user_func(array($this,$name));
        else
            return call_user_func_array(array($this,$name),$array);
    }
}

and a child class like this:

class Child extends Controller
{
    private function Test()
    {
        echo 'test called';
    }
}

so when i do this:

$child = new Child();
$child->Test();

and load the page it takes a lot of time and after a while the web browser prints that the page can't be requested. no output is given from php, only a web browser error.

apache error log (last part only):

...
[Tue Sep 24 12:33:14.276867 2013] [mpm_winnt:notice] [pid 1600:tid 452] AH00418: Parent: Created child process 3928
[Tue Sep 24 12:33:15.198920 2013] [ssl:warn] [pid 3928:tid 464] AH01873: Init: Session Cache is not configured [hint: SSLSessionCache]
[Tue Sep 24 12:33:15.287925 2013] [mpm_winnt:notice] [pid 3928:tid 464] AH00354: Child: Starting 150 worker threads.
[Tue Sep 24 12:38:43.366426 2013] [mpm_winnt:notice] [pid 1600:tid 452] AH00428: Parent: child process exited with status 3221225725 -- Restarting.
[Tue Sep 24 12:38:43.522426 2013] [ssl:warn] [pid 1600:tid 452] AH01873: Init: Session Cache is not configured [hint: SSLSessionCache]

i can't find the mistake, but if the function Test is protected everything works fine.

solution found:

public function __call($name, $arguments)
{
    if(!method_exists($this,$name))
        return false;
    $meth = new ReflectionMethod($this,$name);
    $meth->setAccessible(true);
    if(!$arguments)
        return $meth->invoke($this);
    else
        return $meth->invokeArgs($this,$arguments);
}
도움이 되었습니까?

해결책

This behavior is an issue (bug?) documented in the documentation of method_exists(): method_exists() returns true even if the method is private/protected and thus, not accessible from outside the class. This leads to infinite recursion in your case, as your Child->Test() call invokes Child::__call(), which checks whether Test() exists (it does, but can't be called), then tries to call it, which again leeds to __call() being invoked. Comments suggest using get_class_methods() might resolve the issue. I'm not sure why changing the visibility of Test() to private changes the behavior as you stated.

다른 팁

Give Test() public visibility, and it should work.

I'm not entirely sure why private visibility causes a 500 error (as opposed to Call to private method...), but I suspect it's to do with recursion involving the __call() function. Some features in PHP do more harm than good - do you really need it?

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top