我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Laravel中服务容器绑定的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Laravel中服务容器绑定的示例分析

这篇文章给大家分享的是有关Laravel中服务容器绑定的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

Laravel 是什么

Laravel 是一套简洁、优雅的PHP Web开发框架。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。

关于服务容器

  手册上是这样介绍的:Laravel 服务容器是用于管理类的依赖和执行依赖注入的工具。依赖注入这个花俏名词实质上是指:类的依赖项通过构造函数,或者某些情况下通过「setter」方法「注入」到类中。。。。。。(真的看不懂啥意思)
  服务容器是用于管理类(服务)的实例化的机制。直接看看服务容器怎么用

  1.在服务容器中注册类(bind)

$this->app->bind('sender','MailSender');//$this->app成为服务容器。

  2.从服务容器生成类(make)

$sender = $this->app->make('sender');//从服务容器($this->app)创建一个sender类。在这种情况下,将返回MailSender的实例。

laravel容器基本认识

  一开始,index.php 文件加载 Composer 生成定义的自动加载器,然后从 bootstrap/app.php 脚本中检索 Laravel 应用程序的实例。Laravel 本身采取的第一个动作是创建一个 application/ service container 的实例。

$app = new Illuminate\Foundation\Application(    dirname(__DIR__));

  这个文件在每一次请求到达laravel框架都会执行,所创建的$app即是laravel框架的应用程序实例,它在整个请求生命周期都是唯一的。laravel提供了很多服务,包括认证,数据库,缓存,消息队列等等,$app作为一个容器管理工具,负责几乎所有服务组件的实例化以及实例的生命周期管理。当需要一个服务类来完成某个功能的时候,仅需要通过容器解析出该类型的一个实例即可。从最终的使用方式来看,laravel容器对服务实例的管理主要包括以下几个方面:

  • 服务的绑定与解析

  • 服务提供者的管理

  • 别名的作用

  • 依赖注入

先了解如何在代码中获取到容器实例,再学习上面四个关键

如何在代码中获取到容器实例

第一种是

$app = app();//app这个辅助函数定义在\vendor\laravel\framework\class="lazy" data-src\Illuminate\Foundation\helper.php里面,,这个文件定义了很多help函数,并且会通过composer自动加载到项目中。所以,在参与http请求处理的任何代码位置都能够访问其中的函数,比如app()。

第二种是

Route::get('/', function () {    dd(App::basePath());    return '';});//这个其实是用到Facade,中文直译貌似叫门面,在config/app.php中,有一节数组aliases专门用来配置一些类型的别名,第一个就是'App' => Illuminate\Support\Facades\App::class,具体的Google一下laravel有关门面的具体实现方式

第三种是

  在服务提供者里面直接使用$this->app。服务提供者后面还会介绍,现在只是引入。因为服务提供者类都是由laravel容器实例化的,这些类都继承自Illuminate\Support\ServiceProvider,它定义了一个实例属性$app:

abstract class ServiceProvider{    protected $app;

  laravel在实例化服务提供者的时候,会把laravel容器实例注入到这个$app上面。所以我们在服务提供者里面,始终能通过$this->$app访问到laravel容器实例,而不需要再使用app()函数或者App Facade了。

如何理解服务绑定与解析

  浅义层面理解,容器既然用来存储对象,那么就要有一个对象存入跟对象取出的过程。这个对象存入跟对象取出的过程在laravel里面称为服务的绑定与解析。

app()->bind('service', 'this is service1');app()->bind('service2', [    'hi' => function(){        //say hi    }]);class Service {}app()->bind('service3', function(){    return new Service();});

  还有一个单例绑定singleton,是bind的一种特殊情况(第三个参数为true),绑定到容器的对象只会被解析一次,之后的调用都返回相同的实例

public function singleton($abstract, $concrete = null){$this->bind($abstract, $concrete, true);}

  在绑定的时候,我们可以直接绑定已经初始化好的数据(基本类型、数组、对象实例),还可以用匿名函数来绑定。用匿名函数的好处在于,这个服务绑定到容器以后,并不会立即产生服务最终的对象,只有在这个服务解析的时候,匿名函数才会执行,此时才会产生这个服务对应的服务实例。
  实际上,当我们使用singleton,bind方法以及数组形式,(这三个方法是后面要介绍的绑定的方法),进行服务绑定的时候,如果绑定的服务形式,不是一个匿名函数,也会在laravel内部用一个匿名函数包装起来,这样的话, 不轮绑定什么内容,都能做到前面介绍的懒初始化的功能,这对于容器的性能是有好处的。这个可以从bind的源码中看到一些细节:

if (! $concrete instanceof Closure) {    $concrete = $this->getClosure($abstract, $concrete);}

看看bind的底层代码

public function bind($abstract, $concrete = null, $shared = false)

  第一个参数服务绑定名称,第二个参数服务绑定的结果(也就是闭包,得到实例),第三个参数就表示这个服务是否在多次解析的时候,始终返回第一次解析出的实例(也就是单例绑定singleton)。

  服务绑定还可以通过数组的方式:

app()['service'] = function(){    return new Service();};

绑定大概就这些,接下来看解析,也就是取出来用

$service= app()->make('service');

  这个方法接收两个参数,第一个是服务的绑定名称和服务绑定名称的别名,如果是别名,那么就会根据服务绑定名称的别名配置,找到最终的服务绑定名称,然后进行解析;第二个参数是一个数组,最终会传递给服务绑定产生的闭包。

看源码:

public function make($abstract, array $parameters = []){    return $this->resolve($abstract, $parameters);}protected function resolve($abstract, $parameters = []){    $abstract = $this->getAlias($abstract);    $needsContextualBuild = ! empty($parameters) || ! is_null(        $this->getContextualConcrete($abstract)    );    // If an instance of the type is currently being managed as a singleton we'll    // just return an existing instance instead of instantiating new instances    // so the developer can keep using the same objects instance every time.    if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {        return $this->instances[$abstract];    }    $this->with[] = $parameters;    $concrete = $this->getConcrete($abstract);    // We're ready to instantiate an instance of the concrete type registered for    // the binding. This will instantiate the types, as well as resolve any of    // its "nested" dependencies recursively until all have gotten resolved.    if ($this->isBuildable($concrete, $abstract)) {        $object = $this->build($concrete);    } else {        $object = $this->make($concrete);    }    // If we defined any extenders for this type, we'll need to spin through them    // and apply them to the object being built. This allows for the extension    // of services, such as changing configuration or decorating the object.    foreach ($this->getExtenders($abstract) as $extender) {        $object = $extender($object, $this);    }    // If the requested type is registered as a singleton we'll want to cache off    // the instances in "memory" so we can return it later without creating an    // entirely new instance of an object on each subsequent request for it.    if ($this->isShared($abstract) && ! $needsContextualBuild) {        $this->instances[$abstract] = $object;    }    $this->fireResolvingCallbacks($abstract, $object);    // Before returning, we will also set the resolved flag to "true" and pop off    // the parameter overrides for this build. After those two things are done    // we will be ready to return back the fully constructed class instance.    $this->resolved[$abstract] = true;    array_pop($this->with);    return $object;}
$needsContextualBuild = ! empty($parameters) || ! is_null(    $this->getContextualConcrete($abstract));

  该方法主要是区分,解析的对象是否有参数,如果有参数,还需要对参数做进一步的分析,因为传入的参数,也可能是依赖注入的,所以还需要对传入的参数进行解析;这个后面再分析。

if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {    return $this->instances[$abstract];}

  如果是绑定的单例,并且不需要上面的参数依赖。我们就可以直接返回 $this->instances[$abstract]。

$concrete = $this->getConcrete($abstract);...protected function getConcrete($abstract){    if (! is_null($concrete = $this->getContextualConcrete($abstract))) {        return $concrete;    }    // If we don't have a registered resolver or concrete for the type, we'll just    // assume each type is a concrete name and will attempt to resolve it as is    // since the container should be able to resolve concretes automatically.    if (isset($this->bindings[$abstract])) {        return $this->bindings[$abstract]['concrete'];    }    return $abstract;}

  这一步主要是先从绑定的上下文找,是不是可以找到绑定类;如果没有,则再从 $bindings[] 中找关联的实现类;最后还没有找到的话,就直接返回 $abstract 本身。

// We're ready to instantiate an instance of the concrete type registered for// the binding. This will instantiate the types, as well as resolve any of// its "nested" dependencies recursively until all have gotten resolved.if ($this->isBuildable($concrete, $abstract)) {    $object = $this->build($concrete);} else {    $object = $this->make($concrete);}...protected function isBuildable($concrete, $abstract){    return $concrete === $abstract || $concrete instanceof Closure;}

  如果之前找到的 $concrete 返回的是 $abstract 值,或者 $concrete 是个闭包,则执行 $this->build($concrete),否则,表示存在嵌套依赖的情况,则采用递归的方法执行 $this->make($concrete),直到所有的都解析完为止。

$this->build($concrete)

public function build($concrete){    // If the concrete type is actually a Closure, we will just execute it and    // hand back the results of the functions, which allows functions to be    // used as resolvers for more fine-tuned resolution of these objects.    // 如果传入的是闭包,则直接执行闭包函数,返回结果    if ($concrete instanceof Closure) {        return $concrete($this, $this->getLastParameterOverride());    }    // 利用反射机制,解析该类。    $reflector = new ReflectionClass($concrete);    // If the type is not instantiable, the developer is attempting to resolve    // an abstract type such as an Interface of Abstract Class and there is    // no binding registered for the abstractions so we need to bail out.    if (! $reflector->isInstantiable()) {        return $this->notInstantiable($concrete);    }    $this->buildStack[] = $concrete;    // 获取构造函数    $constructor = $reflector->getConstructor();    // If there are no constructors, that means there are no dependencies then    // we can just resolve the instances of the objects right away, without    // resolving any other types or dependencies out of these containers.    // 如果没有构造函数,则表明没有传入参数,也就意味着不需要做对应的上下文依赖解析。    if (is_null($constructor)) {        // 将 build 过程的内容 pop,然后直接构造对象输出。        array_pop($this->buildStack);        return new $concrete;    }    // 获取构造函数的参数    $dependencies = $constructor->getParameters();    // Once we have all the constructor's parameters we can create each of the    // dependency instances and then use the reflection instances to make a    // new instance of this class, injecting the created dependencies in.    // 解析出所有上下文依赖对象,带入函数,构造对象输出    $instances = $this->resolveDependencies(        $dependencies    );    array_pop($this->buildStack);    return $reflector->newInstanceArgs($instances);}

感谢各位的阅读!关于“Laravel中服务容器绑定的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Laravel中服务容器绑定的示例分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Laravel中服务容器绑定的示例分析

这篇文章给大家分享的是有关Laravel中服务容器绑定的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Laravel 是什么Laravel 是一套简洁、优雅的PHP Web开发框架。它可以让你从面条一样杂
2023-06-14

Laravel服务容器绑定与解析的示例

这篇文章将为大家详细讲解有关Laravel服务容器绑定与解析的示例,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。关于服务容器  手册上是这样介绍的:Laravel 服务容器是用于管理类的依赖和执行依赖注入
2023-06-14

Vue.js中Class与Style绑定的示例分析

这篇文章主要介绍了Vue.js中Class与Style绑定的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Vue.js Class与Style绑定对于数据绑定,一个常
2023-06-26

angular双向绑定的示例分析

这篇文章主要为大家展示了“angular双向绑定的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“angular双向绑定的示例分析”这篇文章吧。双向绑定原理双向绑定将属性绑定与事件绑定结合
2023-06-22

Flex绑定机制的示例分析

这篇文章给大家分享的是有关Flex绑定机制的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Flex绑定机制在我们了解了事件机制后,那么理解Flex绑定就不难了,Flex绑定其实也是事件机制的运用。1.什么
2023-06-17

Canvas事件绑定的示例分析

这篇文章主要介绍Canvas事件绑定的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!我先来讲下实现原理:其实就是canvas绑定相关事件,在通过记录图片所在canvas的坐标,判断事件作用于哪个图片中。这样讲
2023-06-09

Laravel Hprose RPC服务的示例分析

这篇文章主要介绍了Laravel Hprose RPC服务的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。Laravel Hprose RPC 服务开源地址:http
2023-06-14

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录