使用闭包处理事件而不是使用eval()会更好吗



我正在为一个类制作一个事件处理程序,但我想知道使用闭包而不是评估代码是否更好?

我使用eval()的唯一原因只是因为它能够访问类中的所有内容(而且它真的非常不安全:D),但我不知道闭包是否可以。

如果我做了这样的事情:

<?php
class SomethingCool {
protected $handlers;
public function addHandler($cmd, closure $func) {
$this->handlers[$cmd][] = $func;
}
public function handle($cmd) {
if(!isset($this->handlers[$cmd]))
return false;
foreach($this->handlers[$cmd] as $func)
$func();
}
}
?>
<?php
$wut = new SomethingCool();
$wut->addHandler('lol', function() use($wut) {
$wut->handle('lol');
}
);
?>

它会执行时没有错误吗?我想自己测试一下,但目前我做不到。

如果使用eval编写处理程序,则最终会编写如下代码:

$wut->addHandler('lol', '$this->handle('lol');');

除了在编辑器中转义引号和突出显示语法错误等明显可怕的问题外,这还引入了不明确的依赖关系问题。$this在您的代码中指的是什么?它并不像代码中那样实际工作,它取决于在特定的上下文中进行评估。这使得代码变得一团糟。

另一种选择是依赖注入:

$wut->addHandler('lol', function (SomethingCool $sc) {
$sc->handle('lol');
});

当调用此处理程序时,SomethingCool将把自己作为函数参数注入。这要稳健得多。这意味着你可以将这个回调传递给其他上下文,并在幕后做任何你想做的事情,回调不再依赖于在特定上下文中进行评估。

或者,使用闭包:

$wut->addHandler('lol', function () use ($wut) {
$wut->handle('lol');
});

这有同样的好处,你可以确定你的依赖来自哪里,并知道你可以依赖它

所以是的,任何都比eval好。

为什么不将SomethingCool的实例传递给每个处理程序?

public function handle($cmd) 
{
if (!isset($this->handlers[$cmd])) {
return;
}
foreach ($this->handlers[$cmd] as $func)
$func($this); // pass ourself to each handler
}
}
$wut->addHandler('lol', function(SomethingCool $obj) {
// $obj refers to the SomethingCool instance
});
$wut->handle('lol');

顺便说一句,如果您还希望能够删除处理程序,也可以对每个命令类别使用SplObjectStorage

相关内容

  • 没有找到相关文章

最新更新