带有事件调度程序的PHP依赖注入和依赖容器

时间:2011-11-02 12:15:16

标签: php dependency-injection

阅读有关依赖注入的精彩文章后:http://miller.limethinking.co.uk/2011/07/07/dependency-injection-moving-from-basics-to-container/

我意识到我的小框架在很大程度上已经使用了一个Denedency Injection Container。

我有一个App类,可以管理创建所有服务Database,Config,Session,并且能够实现不同的类。

但是我意识到一个部分导致了我将框架中的事件调度程序传递给很多基类的问题,但是每个类都使用调度程序,如:

$this->dispatcher->fire(new FB_Event('FB.Database.Model.beforeUpdate', $this, array('pk' => $pk, 'row' => $row)));

因此,当你看到我使用 new 时,我无法对我的课程进行完全单元测试。我不想将我的App容器传递给所有应用程序,因为它是调试后的噩梦,因为App包含数据库,会话和其他类不需要的大量服务的实例。

解决此问题的最佳方法是什么,因为我无法通过依赖注入传递FB_Event,因为相同的函数通常会触发2事件:

public function delete($pk) {
    $e = $this->dispatcher->fire(new FB_Event('FB.Database.Model.beforeDelete', $this, array('pk' => $pk)));
    $pk = $e->params['pk'];
    if ($e->preventDefault()) {
        return false;
    }

    $this->requirePK();
    list ( $where, $params ) = $this->pkParts(null, $pk);
    $sql = "DELETE FROM {$this->name} WHERE $where";
    $stm = $this->db->execute($sql, $params);

    $this->dispatcher->fire(new FB_Event('FB.Database.Model.afterDelete', $this, array('pk' => $pk)));
    return!(bool) $stm->errorCode();
}

我的一个解决方案是向调度程序添加一个名为fireEvent的新函数,它将负责创建新的FB_Event,它将删除各处的耦合。但是会在调度程序和事件之间添加耦合,这样会更糟糕。

public function fireEvent($name, $target, $params = array()) {
    return $this->fire(new FB_Event($name, $target, $params = array()));
}

您是否会在容器中创建某种EventFactory并将其传递给Dispatcher? 这种过度杀伤是否会删除对像Event这样的小对象的依赖?

感谢您的建议

2 个答案:

答案 0 :(得分:1)

  

解决此问题的最佳方法是什么,因为我无法传递FB_Event   通过依赖注入,因为相同的功能通常会引发2   事件:

您可以使用FB_Event课程中的setter来解决此问题。例如,将FB_Event(DI)的实例传递给相关类,然后将其用作:

public function delete($pk) {

    $this->fb_event->setName('FB.Database.Model.beforeDelete');     
    $this->fb_event->setTarget($this);
    $this->fb_event->setParams(array('pk' => $pk));

    $e = $this->dispatcher->fire($this->fb_event);
    $pk = $e->params['pk'];
    if ($e->preventDefault()) {
        return false;
    }

    $this->requirePK();
    list ( $where, $params ) = $this->pkParts(null, $pk);
    $sql = "DELETE FROM {$this->name} WHERE $where";
    $stm = $this->db->execute($sql, $params);

    $this->fb_event->reset();
    $this->fb_event->setName('FB.Database.Model.afterDelete'); 
    $this->fb_event->setTarget($this);
    $this->fb_event->setParams(array('pk' => $pk));    

    $this->dispatcher->fire($this->fb_event);
    return!(bool) $stm->errorCode();
}

答案 1 :(得分:1)

我实际上认为您建议的解决方案是最佳答案。你应该避免在代码中实例化FB_Event,因为它很难(-er)测试和耦合你的代码。在您的fireEvent方法中,是的,Dispatcher类和Event类之间存在耦合,但Dispatcher应该知道事件,因为它就是它的调度。是的,要避免耦合,但有些课程有时需要了解其他课程;不能总是避免耦合。 fireEvent方法的好处在于它是一个接缝,因此可以用来在将来破解代码。