当前位置: 首页 > 后端技术 > PHP

使用traits实现简单的依赖注入

时间:2023-03-30 01:37:10 PHP

这里假设一个场景:有一个工厂(Factory),工人(Worker)需要使用某台机器(Machine)来生产某个产品,有这样一个依赖:Factory-->Worker-->Machine不使用注入代码,看起来像这样:classMachine{functionrun(){echo'machinestart';}}classWorker{functionwork(){echo"worker启动机器->";$机器=新机器();$机器->运行();}}classFactory{functionproduce(){echo"工厂叫工人开始工作->";$工人=新工人();$工人->工作();}}$factory=newFactory();$factory->produce();可以看出,这里依赖的对象都是类自己在内部实例化的,属于强耦合,不利于测试和维护。比如我要换另一种工人做生产,我就得换工厂内部,这是不合理的。手动注入所谓注入就是把类所依赖的对象的实例化操作放在类之外,用Interface做约束:InterfaceMachine{publicfunctionrun();}InterfaceWorker{publicfunctionwork();}classMachine1implementsMachine{functionrun(){echo'Machine1starts';}}classMachine2implementsMachine{functionrun(){echo'Machine2starts';}}classWorker1实现Worker{private$machine;公共函数__construct(机器$machine){$this->machine=$machine;}functionwork(){echo"Worker1启动机器->";$this->机器->运行();}}classWorker2实现Worker{private$machine;公共函数__construct(机器$machine){$this->machine=$machine;}functionwork(){echo"Worker2启动机器->";$this->机器->运行();}}classFactory{private$worker;公共函数__construct(Worker$worker){$this->worker=$worker;}functionproduce(){echo"工厂叫工人Worker->";$this->worker->work();}}$machine=newMachine1();$worker=newWorker2($machine);$factory=newFactory($worker);$factory->produce();可见这样做的好处是解耦,比如:worker1可以启动机器2生产,或者worker2可以启动机器1生产,以后随时可以使用新的worker(只要能工作),Worker也可以随时换到其他机器(只要能运行)进行生产,这种转换不需要修改工厂或Worker的代码。那么问题来了,现在把实例化从里面移到外面就好了,但是如果依赖的东西太多,也很麻烦,这就需要一个自动注入机制,也就是平时经常听到的注入容器次。常见的容器都是通过反射实现的,必须在构造函数中声明类型注入,比较麻烦。在这个文章,我尝试用另一种方式来实现它。自动注入traits可以简单理解为一种可重用的方法。下面看看如何使用traits实现自动注入。思路是利用trait实现魔术方法__get,通过__get自动生成依赖对象,先看完整代码traitDI{private$map=['Worker'=>'Worker1','Machine'=>'机器2'];函数__get($k){if(preg_match('/^[A-Z]/',$k)){$obj=new$this->map[$k];如果($objinstanceof$k){返回$obj;}else{exit("不符合协议");}}}}InterfaceMachine{publicfunctionrun();}InterfaceWorker{publicfunctionwork();}classMachine1implementsMachine{functionrun(){echo'Machine1starts';}}classMachine2implementsMachine{functionrun(){echo'Machine2starts';}}classWorker1implementsWorker{使用DI;functionwork(){echo"Worker1启动机器->";$this->机器->运行();}}classWorker2实现Worker{使用DI;functionwork(){echo"Worker2启动机器->";$this->机器->运行();}}classFactory{使用DI;函数产生(){echo"工厂叫工人开工->";$this->工人->工作();}}$工厂=新工厂();$工厂->生产();trait中的map用于演示类和接口的实现类型约束的绑定关系,在实际应用中可以通过配置或其他方式实现。在类中使用依赖注入时,需要声明useDI,同时注入的对象要大写(也可以使用其他规则,相应修改trait中的判断)当然,这只是一个很粗略的演示,只实现了基本的自动注入,还是有很多问题,比如原来的类也有__get方法,会被覆盖。有兴趣的可以尝试改进一下,看看能不能在项目中实际使用。