如何将参数传递给PHP中的匿名函数?

时间:2015-02-03 09:18:16

标签: php anonymous-function phalcon

我有以下代码:

$evManager = $di->getShared('eventsManager');
$evManager->attach('dispatch', function($event, $dispatcher, $exception){
   $dispatcher = new \Phalcon\Mvc\Dispatcher();
   $dispatcher->setEventsManager($evManager);

   return $dispatcher;
})
$ evManager是一个对象,它有一个名为attach的方法,它接受两个参数,对我来说很清楚。第二个参数是一个匿名函数,它有三个参数($ event,$ dispatcher,$ exception)。

所以我的问题是这三个参数是什么?为什么他们不空?什么传递给匿名函数?我无法理解......

我知道匿名函数返回调度程序对象,方法attach对它做了一些事情。唯一的问题是关于参数。

2 个答案:

答案 0 :(得分:4)

将匿名函数视为具有方法的普通对象。您可以像这样编写代码:

class MyDispatcherHelper {
    public function handle($event, $dispatcher, $exception) {
        $dispatcher = new \Phalcon\Mvc\Dispatcher();
        $dispatcher->setEventsManager($evManager);

        return $dispatcher;
    }
}

$evManager = $di->getShared('eventsManager');
$evManager->attach('dispatch', new MyDispatcherHelper());

所以现在没有更多的匿名功能了。 “魔法”发生在$evManager->attach内。它的定义看起来像这样:

class EventsManager {
    public function attach($eventName, $handler) {
        // somehow listen for events named $eventName
        ...
        // and get an instance of the Event
        $myEvent = $listener->theEvent;

        // if it's an exception maybe set $exception to something usefull? 
        ...

        //_call_ $handler when event occurs
        call_user_func($handler, [$myEvent, $this, $exception]);
    }
}

您应该阅读call_user_func的文档。

现在,如果我们继续使用“用类示例替换匿名函数”,上面的代码将如下所示:

class EventsManager {
    public function attach($eventName, MyDispatcherHelper $handler) {
        // somehow listen for events named $eventName
        ...
        // and get an instance of the Event
        $myEvent = $listener->theEvent;

        // if it's an exception maybe set $exception to something usefull? 
        ...

        //_call_ $handler when event occurs
        $handler->handle($myEvent, $this, $exception);
    }
}

这就是匿名函数的作用。 您的代码与调用该函数无关。它不在你的控制之下,你不能告诉它用什么参数来调用匿名函数,这就是eventsManager所做的。 在您定义匿名函数时,被调用,您可以在其上定义任何数量的参数,并将它们命名为您喜欢的任何参数。

此外,匿名函数中的代码可能看起来像是对它之外的代码有一些魔力,但它$dispatcher->setEventsManager($evManager)也是错误的,我在任何地方都没有看到global $evManager

答案 1 :(得分:2)

在使用类似插件的架构时,这些参数通常会提供一些额外的信息。例如,如果您有一个依赖注入容器,例如

$di->register('translator', function($di){
   // You can omit usage of $di here, because you don't need to grab from the container at right now
   return new Translator();
});

$di->register('Message', function($di){
    $translator = $di->get('translator');
    return new Message($translator);
});

然后在某些情况下,您可能需要获取依赖关系,而在某些情况下,您不需要。

它是如何工作的? 这很简单。

您只是假设参数将是一个函数,因此您在声明时将参数传递给它。例如,在$di类定义中,它看起来像这样:

class Di
{
     public function register($name, $provider)
     {
           // We will assume that $provider is a function
           // and therefore pass some data to it

           $this->data[$name] => $provider($this); // or another parameter (s)
     }
}