PHP 依赖注入和带有事件调度程序的依赖容器
阅读这篇关于依赖注入的精彩文章后: http://miller.limethinking.co.uk/2011/07/07/dependency-injection-moving-from-basics-to-container/
我意识到我的小框架已经准备好了大部分情况下使用 Denedency Injection Container。
我有一个应用程序类,可以管理所有服务数据库、配置、会话的创建,并且能够实例化不同的类。
但我意识到,有一个部分导致了问题,我将事件调度程序传递给框架中的许多基类,但每个类都使用调度程序,例如:
$this->dispatcher->fire(new FB_Event('FB.Database.Model.beforeUpdate', $this, array('pk' => $pk, 'row' => $row)));
所以如您所见,我在那里使用 new所以我无法对我的课程进行完整的单元测试。我不想将我的应用程序容器传递给所有应用程序,因为应用程序包含数据库、会话和其他类不需要的大量服务的实例,因此调试起来是一场噩梦。
解决这个问题的最佳方法是什么,因为我无法通过依赖注入传递 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 这样的小对象的依赖是否太过分了?
谢谢你的建议
After reading this great article on dependency injection : http://miller.limethinking.co.uk/2011/07/07/dependency-injection-moving-from-basics-to-container/
I realized that my small framework was alrready using a Denedency Injection Container for the most part.
I have an App class with manage creation of all services Database, Config, Session, and that is able to instanciate of diferent classes.
But I realised that one part was causing issues I pass an Event dispatcher to a lot of base classes in my framework, but each of theses classes use the dispatcher like:
$this->dispatcher->fire(new FB_Event('FB.Database.Model.beforeUpdate', $this, array('pk' => $pk, 'row' => $row)));
So as you see I use a new there so i'm not able to fully unit tests my classes. I don't want to pass my App container to all application because it's a nightmare to debug after since the App contains instances of the Database, Session and a multitude of services that the other classes don't need.
What is the best way of resolving this since I cannot pass an FB_Event through dependency injection, since the same function usually fire 2 event:
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();
}
One of my solution is to add a new function to the dispatcher called fireEvent wich will take care of creating the new FB_Event wich will remove the coupling everywhere. But will add coupling between the Dispatcher and the Event wich is less bad.
public function fireEvent($name, $target, $params = array()) {
return $this->fire(new FB_Event($name, $target, $params = array()));
}
Would you create some sort of EventFactory in the container and pass it to the Dispatcher ?
Is this overkill to remove dependency to a small object like Event ?
Thanks for your advice
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我实际上认为您建议的解决方案是最好的答案。您是对的,应避免在代码中实例化 FB_Event,因为它会使测试和耦合代码变得困难(-呃)。是的,在您的 fireEvent 方法中,Dispatcher 类和 Event 类之间存在耦合,但 Dispatcher 应该了解事件,因为这就是它正在分派的内容。是的,应该避免耦合,但有些类有时确实需要了解其他类;耦合总是无法避免。 fireEvent 方法的好处是它是一个接缝,因此可以在将来用于分解代码。
I actually think your suggested solution is the best answer. You're right in that instantiating an FB_Event in the code is to be avoided as it makes it hard(-er) to test and couples your code. Yes in your fireEvent method there is coupling between the Dispatcher class and the Event class but the Dispatcher should know about Events as that is what it is dispatching. Yes, coupling is to be avoided but some classes do need to know about other classes sometimes; coupling can't always be avoided. The good thing about your fireEvent method is that it's a seam and hence could be used to break code up in future.
您可以通过在
FB_Event
类中使用 setter 来解决此问题。例如,将FB_Event
(DI) 的实例传递给相关类,然后将其用作:You can work around this problem by using setters in your
FB_Event
class. For example, pass an instance ofFB_Event
(DI) to concerned class then use it as: