我正在用PHP编写api。
我有一个实现魔术函数__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);
}
}
和这样的子类:
class Child extends Controller
{
private function Test()
{
echo 'test called';
}
}
所以当我这样做时:
$child = new Child();
$child->Test();
并加载页面需要花费很多时间,过了一段时间,网络浏览器会打印出无法请求页面的内容。没有从php给出输出,只有Web浏览器错误。
apache错误日志(仅限最后一部分):
...
[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]
我无法找到错误,但如果功能Test受到保护,一切正常。
找到解决方案: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);
}
答案 0 :(得分:0)
此行为是documentation of method_exists()
中记录的问题(错误?):method_exists()
返回true,即使该方法是私有/受保护的,因此无法从类外部访问。这导致你的情况下无限递归,因为你的Child->Test()
调用调用Child::__call()
,它检查Test()
是否存在(确实存在,但无法调用),然后尝试调用它,再次利用__call()
被调用。评论建议使用get_class_methods()
可能会解决此问题。我不确定为什么将Test()
的可见性更改为private
会改变您所说的行为。
答案 1 :(得分:0)
提供Test()
公众可见度,它应该有效。
我不完全确定为什么私有可见性导致500错误(而不是Call to private method...
),但我怀疑它与涉及__call()
函数的递归有关。 PHP中的一些功能弊大于利 - 你真的需要吗?