1

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

我使用 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');
                            }
                    );
?>

它会毫无错误地执行吗?我会自己测试它,但我目前无法测试。

4

2 回答 2

2

如果您使用 编写处理程序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.

于 2012-12-10T17:34:17.663 回答
0

为什么不将您的实例传递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每个命令类别。

于 2012-12-10T17:32:48.797 回答