文章转自:https://learnku.com/laravel/t...作为开发者,我们一直在努力寻找新的设计模式使用方式,尝试新的健壮框架.编写设计良好且健壮的代码的方法。在本文中,我们将探索依赖注入设计模式与Laravel的IoC组件,并了解它如何改进我们的设计。依赖注入术语依赖注入是MartinFowler创造的一个术语,表示将组件注入应用程序的行为。正如WardCunningham所说:依赖注入是敏捷架构的关键要素。让我们看一个例子:classUserProvider{protected$connection;公共函数__construct(){$this->connection=newConnection;}publicfunctionretrieveByCredentials(array$credentials){$user=$this->connection->where('email',$credentials['email'])->where('密码',$credentials['密码'])->第一();返回$用户;如果你想测试或维护这个类,你必须访问数据库的一个实例来进行一些查询。为避免必须这样做,您可以将此类与其他类分离,您有以下三个选项之一,您可以注入Connection类而不需要直接使用它。将组件注入类时,可以使用以下三个选项之一:构造函数注入类UserProvider{protected$connection;公共函数__construct(Connection$con){$this->connection=$con;}...Setter方法注入类似的,我们也可以使用Setter方法来注入依赖:classUserProvider{protected$connection;publicfunction__construct(){...}publicfunctionsetConnection(Connection$con){$this->connection=$con;}...Interface注入接口ConnectionInjector{publicfunctioninjectConnection(Connection$con);}classUserProviderimplementsConnectionInjector{protected$connection;publicfunction__construct(){...}publicfunctioninjectConnection(Connection$con){$this->connection=$con;当一个类实现我们的接口时,我们定义了injectConnection方法来解决依赖关系。优点现在,在测试我们的类时,我们可以模拟依赖类并将它们作为参数传递。每个类都必须专注于一个特定的任务,而不应该关心解决它们的依赖关系。这样,您将拥有一个更加专注和可维护的应用程序。如果您想了解有关DI的更多信息,AlejandroGervassio在本系列文章中对其进行了广泛而专业的介绍,因此请务必阅读这些文章。那么,什么是国际奥委会?IoC(InversionofControl)不需要使用依赖注入,但它可以帮助你有效地管理依赖。InversionofControlIoc是一个简单的组件,可以更轻松地解决依赖关系。您可以将对象描述为容器,每次解析类时,都会自动注入依赖项。LaravelIoc在请求对象时LaravelIoc解析依赖关系的方式有点特殊:我们使用一个简单的示例,并将在本文中对其进行改进。SimpleAuth类依赖于FileSessionStorage,因此我们的代码可能如下所示:classFileSessionStorage{publicfunction__construct(){session_start();}publicfunctionget($key){return$_SESSION[$key];}publicfunctionset($key,$value){$_SESSION[$key]=$value;}}classSimpleAuth{受保护的$session;公共函数__construct(){$this->session=newFileSessionStorage;}}//创建一个SimpleAuth$auth=newSimpleAuth();这是一个经典的方法,让我们从使用构造函数注入开始。类SimpleAuth{受保护的$session;公共函数__construct(FileSessionStorage$session){$this->session=$session;}}现在我们创建一个对象:$auth=newSimpleAuth(newFileSessionStorage());现在我想用LaravelIoc来管理这一切。因为Application类继承自Container类,所以可以通过App门面访问容器。App::bind('FileSessionStorage',function(){returnnewFileSessionStorage;});bind方法的第一个参数是要绑定到容器的唯一ID,第二个参数是每当执行FileSessionStorage类时的回调函数实现,我们也可以传递一个表示类名的字符串,如下所示。注意:如果你查看Laravel包,你会发现绑定有时会像(view,view.finder...)这样分组。假设我们将会话存储转换为Mysql存储,我们的类应该如下所示:$value){//dosomething}}现在我们已经改变了我们的依赖关系,我们还需要改变SimpleAuth构造函数并将新对象绑定到容器中!高层模块不应该依赖低层模块,两者都应该依赖抽象对象。抽象不应该依赖于细节,细节应该依赖于抽象。RobertC.Martin我们的SimpleAuth类不应该关心我们的存储是如何完成的,相反它应该关心使用服务。因此,我们可以抽象地实现我们的存储:interfaceSessionStorage{publicfunctionget($key);publicfunctionset($key,$value);}这样我们就可以实现和请求SessionStorage接口的一个实例:{//...}publicfunctionset($key,$value){//...}}类MysqlSessionStorage实现SessionStorage{publicfunction__construct(){//...}publicfunctionget($key){//...}publicfunctionset($key,$value){//...}}classSimpleAuth{protected$session;公共函数__construct(SessionStorage$session){$this->session=$session;}}如果我们使用App::make('SimpleAuth')通过容器解析SimpleAuth类,容器会抛出BindingResolutionException,试图从绑定类解析之后,回到反射方法,解析所有的依赖.未捕获异常“Illuminate\Container\BindingResolutionException”,消息为“目标[SessionStorage]不可实例化。”容器正在尝试实例化接口。我们可以为这个接口做一个具体的绑定。应用程序:绑定('SessionStorage','MysqlSessionStorage');现在,每次我们尝试从容器中解析该接口时,我们都会得到一个MysqlSessionStorage实例。如果我们想切换我们的存储服务,我们只需要改变这个绑定。注意:如果你想检查一个类是否已经绑定在容器中,你可以使用App::bound('ClassName'),或者你可以使用App::bindIf('ClassName')注册一个没有的类尚未注册过去的绑定。LaravelIoc还提供了App::singleton('ClassName','resolver')来处理单例绑定。您还可以使用App::instance('ClassName','instance')为单例创建绑定。如果容器无法解析依赖项,则会抛出ReflectionException,但我们可以使用App::resolvingAny(Closure)方法以回调函数的形式解析任何指定类型。注意:如果你注册了某个类型的解析方法,resolvingAny方法还是会被调用,但是会直接返回bind方法的返回值。Tips写这些绑定的地方:如果只是一个小应用,可以写在全局启动文件global/start.php中,但是如果项目越来越大,就需要使用ServiceProvider了。测试:当你需要快速简单的测试时,可以考虑使用phpartisantinker,它非常强大,可以帮助你改进你的Laravel测试过程。反射API:PHP的反射API非常强大。如果你想深入了解LaravelIoc,你需要熟悉ReflectionAPI。您可以先阅读本教程以获取更多信息。最后,与往常一样,学习或理解某些东西的最佳方式是查看源代码。LaravelIoc只是一个文件,它不会花费你太多的时间来完成所有的功能。你想了解更多关于LaravelIoc或Ioc的知识吗?那么请告诉我们!文章转自:https://learnku.com/laravel/t...更多文章:https://learnku.com/laravel/c...
