我创建了不太复杂的测试代码(在PHP 5.5.12中测试):
<?php
class Test
{
private $cached = null;
public function __construct()
{
$this->cached = [];
$this->cached[0] = 12;
}
function wrap($function, $index)
{
if (isset($this->cached[$index])) {
return $this->cached[$index];
}
$result = call_user_func($function);
return $result;
}
}
class B
{
public function run()
{
$x = 6;
$obj = new Test();
$value = $obj->wrap(
function () use ($x) {
return $this->test($x);
},
1
);
echo $value."<br />";
}
protected function test($x)
{
echo "I'm running ";
return $x * $x;
}
}
class C extends B
{
public function run()
{
$x = 6;
$obj = new Test();
$myFunc = function () use ($x) {
return $this->test($x);
};
$value = $obj->wrap($myFunc, 1);
echo $value."<br />";
}
}
class D extends B
{
public function run()
{
$x = 6;
$obj = new Test();
$value = $obj->wrap(array($this, 'test'), 1);
echo $value."<br />";
}
}
$b = new B();
$b->run();
$c = new C();
$c->run();
$d = new D();
$d->run();
可能有些部分的代码你可以说可以做得更好,但重点是闭包函数和可调用的。这些类以一种非常简单的方式模拟缓存系统。如果数据在缓存中,则从缓存中返回数据,否则调用获取数据的函数(当然这个缓存系统不工作,因为它不需要工作-这只是一个示例代码)。
问题:
1)为什么当使用对象$d
时,我得到以下警告:
call_user_func() expects parameter 1 to be a valid callback, cannot access protected method D::test()
是否可以从父类启动protected方法?当我将这个方法从protected更改为public时,它可以毫无问题地启动
2)正如你可能注意到的,我想使用一些参数的函数,我使用call_user_sync
调用。不幸的是,当我调用call_user_func
时,我不知道这些参数,所以在B类和C类中,我使用闭包,在那里我可以使用/传递额外的参数。我还有两个问题:
这是闭包有用和常用的方式吗?
是否可以使用对象
$d
传递参数到测试方法,而不使用闭包,但不是在调用call_user_sync
时,而是在类D
内?
在执行时注意范围是很重要的。您正在在正确的范围内创建回调,但是您正在在另一个无法访问protected
方法的对象中执行回调(回调在class Test
中执行,而不是在class B
的父或子对象中执行)。
我在编写自己的调度程序类时遇到了这个问题。一种选择是在调度程序上设置"父",并将调度程序作为回调的参数之一传递。然后,回调检查与Dispatcher关联的=== $this
的"父",然后知道它具有访问权限并进入城镇。
你必须自己做访问检查,这是关键。