最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Laravel 核心Ioc容器

    正文概述 转载于:掘金(Rocket)   2021-06-08   597

    Hello,我是Rocket

    这是我参与更文挑战的第3天,活动详情查看:更文挑战

    • 要说laravel框架最核心的那肯定要属Ioc容器了
    • 听着名字很高大上,你对它了解多少呢
    • 什么是依赖注入
    • Laravel bind、singleton 、instance 有什么区别呢
    • 服务解析是怎么处理的
    • 构建一个简单的容器加深大家对IOC容器的理解

    1、普通new对象

    <?php
    
    //阿里云短信
    class AliyunSms {
        public function __construct(){}
    
        public function send()
        {
            echo 'sms gateway by aliyun';
        }
    }
    //百度云短信
    class BaiduSms {
        public function __construct(){}
    
        public function send()
        {
            echo 'send gateway by baidu';
        }
    }
    
    
    //发短信
    class SMS {
    
        private $sms;
    
        public function __construct()
        {
            $this->sms= new AliyunSms ();
        }
    
        public function  send()
        {
             $this->sms->send();
        }
    }
    
    $pb = new SMS ();
    $pb->send();
    

    2、 依赖注入

    <?php
    
    //定义短信类接口
    interface Smsinferface{
        public function send();
    }
    
    //阿里云短信
    class AliyunSms implements Smsinferface{
        public function __construct(){}
    
        public function send()
        {
            echo 'sms gateway by aliyun';
        }
    }
    //百度云短信
    class BaiduSms implements Smsinferface{
        public function __construct(){}
    
        public function send()
        {
            echo 'send gateway by baidu';
        }
    }
    
    
    //发短信
    class SMS {
    
        private $sms;
    
        public function __construct(Smsinferface $sms)
        {
            $this->sms= $sms;
        }
    
        public function  send()
        {
             $this->sms->send();
        }
    }
    
    
    //生成依赖
    $aliyun = new AliyunSms();
    //注入依赖
    $a = new SMS ($aliyun);
    $a->send();
    
    $b = new SMS(new BaiduSms());
    $b->send();
    

    3、Laravel几个绑定实例的方法的区别

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

    4、解析服务的几种方式

            $abstract = $this->getAlias($abstract);
    
            $needsContextualBuild = ! empty($parameters) || ! is_null(
                $this->getContextualConcrete($abstract)
            );
          
            if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
                return $this->instances[$abstract];
            }
    
            $this->with[] = $parameters;
    
            $concrete = $this->getConcrete($abstract);
    
            if ($this->isBuildable($concrete, $abstract)) {
                $object = $this->build($concrete);
            } else {
                $object = $this->make($concrete);
            }
    
         
            foreach ($this->getExtenders($abstract) as $extender) {
                $object = $extender($object, $this);
            }
    
         
            if ($this->isShared($abstract) && ! $needsContextualBuild) {
                $this->instances[$abstract] = $object;
            }
    
            $this->fireResolvingCallbacks($abstract, $object);
    
            $this->resolved[$abstract] = true;
    
            array_pop($this->with);
    
            return $object;
    
    if (! function_exists('resolve')) {
       
        function resolve($name)
        {
            return app($name);
        }
    }
    
    function app($abstract = null, array $parameters = [])
    {
            if (is_null($abstract)) {
                return Container::getInstance();
            }
    
            return Container::getInstance()->make($abstract, $parameters);
    }
    
    

    5、构建一个简单的容器类

    实现IOC容器的基本功能,绑定、解析、依赖倒置以及控制翻转

    class Container
    {
        // 保存与接口绑定的闭包,
        // 闭包必须能够返回接口的实例。
        protected $bindings = [];
    
        //单例实例
        protected $instances = [];
    
        // 为某个接口绑定一个实现,有两种情况:
        // 
        // 第一种是绑定接口的实现的类名;
        // 第二种是绑定一个闭包,这个闭包应该返回接口的实例。
        // 
        // 不管哪种情况,实例化操作都是调用 build() 方法完成。
        // 
        // 第二种情况,主要是为了能够在实例化前后进行额外的操作,
        // 实例化的逻辑就书写在闭包中。
        public function bind($abstract, $concrete = null,$shared= false)
        {
            if (is_null($concrete)) {
                $concrete = $abstract;
            }
            // 如果提供的参数不是闭包,而是一个类,
            // 则构建一个闭包,直接调用 build() 方法进行实例化
            if (!$concrete instanceof Closure) {
                // 调用闭包时,传入的参数是容器本身,即 $this生成默认的
                $concrete = function ($c) use ($concrete) {
                    return $c->build($concrete);
                };
            }
    
            $this->bindings[$abstract] = compact('concrete','shared');
        }
    
        //单例绑定
        public function singleton($abstract, $concrete = null)
        {
            $this->bind($abstract, $concrete, true);
        }
    
        //获取对应的闭包
        public function getConcrete($abstract){
            if (isset($this->bindings[$abstract])) {
                return $this->bindings[$abstract]['concrete'];
            }
    
            return $abstract;
        }
    
        public function isShared($abstract)
        {
            return isset($this->instances[$abstract]) ||
                  (isset($this->bindings[$abstract]['shared']) &&
                   $this->bindings[$abstract]['shared'] === true);
        }
    
        // 生成指定接口的实例
        public function make($abstract)
        {
            if (isset($this->instances[$abstract])) {
                return $this->instances[$abstract];
            }
            // 取出闭包
            $concrete = $this->getConcrete($abstract);
            // 取得实例
            $object = $this->build($concrete);
            // 判断是否需要分享对象(单例)
            if ($this->isShared($abstract)) {
                $this->instances[$abstract] = $object;
            }
            return $object;
        }
    
        // 生成实例
        public function build($concrete)
        {
            //如果是闭包直接调用闭包函数
            if ($concrete instanceof Closure) {
                return $concrete($this);
            }
            // 取得类的反射
            $reflector = new ReflectionClass($concrete);
    
            // 检查类是否可实例化
            if (! $reflector->isInstantiable()) {
                // 如果不能,意味着接口不能正常工作,报错
                echo "Target [$concrete] is not instantiable";
            }
    
            // 取得构造函数的反射
            $constructor = $reflector->getConstructor();
    
            // 检查是否有构造函数
            if (is_null($constructor)) {
                // 如果没有,就说明没有依赖,直接实例化
                return new $concrete;
            }
    
            // 取得包含每个参数的反射的数组
            $parameters = $constructor->getParameters();
            // 返回一个真正的参数列表,那些被类型提示的参数已经被注入相应的实例
            $realParameters = $this->resolveDependencies($parameters);
    
            return $reflector->newInstanceArgs($realParameters);
        }
    
        //解析参数依赖
        protected function resolveDependencies($parameters)
        {
            $realParameters = [];
            foreach($parameters as $parameter) {
                // 如果一个参数被类型提示为类 foo,
                // 则这个方法将返回类 foo 的反射
                $dependency = $parameter->getClass();
                if(is_null($dependency)) {
                    $realParameters[] = NULL;
                } else {
                    $realParameters[] = $this->make($dependency->name);
                }
            }
    
            return (array)$realParameters;
        }
    }
    
    
    $app = new Container();
    
    $app->bind(Smsinferface::class, BaiduSms::class);
    
    $app->bind('sms', SMS::class);//可以理解成别名
    
    $sms = $app->make('sms');
    
    $sms->send();
    
    //单例绑定
    $app->singleton('newsms', SMS::class);
    $newsms = $app->make('newsms');
    
    $newsms2 = $app->make('newsms');
    
    
    var_dump($sms === $newsms);
    var_dump($newsms === $newsms2);
    

    6、结尾


    起源地下载网 » Laravel 核心Ioc容器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元