zoukankan      html  css  js  c++  java
  • lumen-ioc容器测试 (6)

    lumen-ioc容器测试 (1)

    lumen-ioc容器测试 (2)

    lumen-ioc容器测试 (3)

    lumen-ioc容器测试 (4)

    lumen-ioc容器测试 (5)

    lumen-ioc容器测试 (6)

    问题四、我们现在遇到的问题是构建对象的时候需要明确构造函数的参数类型、数量。并且增加程序的透明度

    # class Container# 复制上面的代码
    class Person{
        private $name;
        public function __construct($param) {
            $this->name = $param['name'] ?? 'unknown';
        }
    
        public function getName() {
            return $this->name;
        }
    }
    

      

    我们上一个版本的解决方案显然不是很理想。我们不能要求每个类的构造函数都传一个$param数组,这样不透明也不现实
    那么如果我们要这样使用一个容器呢?

    class Person{
        private $name;
        private $isProgrammer;
        public function __construct($name,$isProgrammer = true) {
            $this->name = $name;
            $this->isProgrammer = $isProgrammer;
        }
    
        public function me() {
    $message = $this->isProgrammer ? ',Ta是一个程序员' :''; return "姓名: {$this->name} $message"; } } $container = new Container(); $container->bind('Person'); $p1 = $container->make('Person',[ 'name' => 'lilei', ]); echo $p1->me();

      

    接下来我们来解决上述问题

    class Container {
    
        private $bindings = [];
        private $instances = [];
    
        public function getClosure($concrete) {
            return function($parameter = []) use($concrete) {
                # 在这里我们找到了判断初始化函数的契机,利用反射我们可以做很多事,包括我们的问题
                # 1.获得一个$concrete类反射
                $reflector = new ReflectionClass($concrete);
                # 2.判断这个类能否被实例化,例如 private function __construct(){}
                if(!$reflector->isInstantiable()) {
                    throw new Exception("{$concrete} 无法被实例化");
                }
    
                # 3.获取构造函数反射方法
                $constructor = $reflector->getConstructor();
    
                # 4.获取参数列表
                $parameters = $constructor->getParameters();
    
                # 5.遍历参数列表
                $instances = [];
                foreach ($parameters as $_parameter) {
                    # 如果已经$parameter中已经设置了对应的参数
                    if(isset($parameter[$_parameter->name])) {
                        $instances[] = $parameter[$_parameter->name];
                        continue;
                    }
                    # 如果没设置判断一下这个参数是否存在默认值
                    if(!$_parameter->isDefaultValueAvailable()) {
                        throw new Exception("{$concrete} 无法被实例化,缺少参数{$_parameter->name}");
                    }
    
                    $instances[] = $_parameter->getDefaultValue();
                }
    
                # 这里就需要通过反射来构建对象了
    //            return new $concrete($parameter);
                return $reflector->newInstanceArgs($instances);
            };
        }
    
    
        public function bind($abstract , $concrete=null, $shared = false)
        {
            if (is_null($concrete)) {
                $concrete = $abstract;
            }
    
            if (!$concrete instanceof Closure) {
                $concrete = $this->getClosure($concrete);
            }
    
            $this->bindings[$abstract] = [
                'concrete' => $concrete,
                'shared' => $shared
            ];
        }
    
        public function make($abstract ,array $parameters = []) {
            if (!isset($this->bindings[$abstract])) {
                return false;
            }
    
            if (isset($this->instances[$abstract])) {
                return $this->instances[$abstract];
            }
    
            # 先获取到具体的类型
            $concrete = $this->bindings[$abstract]['concrete'];
            # 这里需要思考一下
            # 到目前为止我们的$this->bindings[$abstract]['concrete']里存储的都是通过getClosure方法生成的闭包。
            # 那么直接在这里判断类型肯定行不通,所以我们跳到getClosure里面去看看
            $object = $concrete($parameters);
            if($this->bindings[$abstract]['shared']) {
                $this->instances[$abstract] = $object;
            }
    
            return $object;
        }
    }
    
    class Person{
        private $name;
        private $isProgrammer;
        public function __construct($name,$isProgrammer = true) {
            $this->name = $name;
            $this->isProgrammer = $isProgrammer;
        }
    
        public function me() {
            $message = $this->isProgrammer ? ',Ta是一个程序员' :'';
            return "姓名: {$this->name} $message";
        }
    }
    $container = new Container();
    $container->bind('Person');
    $p1 = $container->make('Person',[
        'name' => 'lilei',
    ]);
    
    echo $p1->me();
  • 相关阅读:
    Kruskal重构树学习笔记
    亚洲和欧洲的分界线是谁划分的?
    代码目录 (App_Code 目录)及namespace的理解
    Events解惑——来自MSDN
    HttpContext.Current.Response和Response有什么区别?
    Ramdisk 内存盘的使用
    MVC模式 介绍
    关于Windows Workflow Foundation 调试时的经验小解(不断添加)
    关于类成员变量的声明和实例化的时机
    软件名称备份
  • 原文地址:https://www.cnblogs.com/brady-wang/p/13733994.html
Copyright © 2011-2022 走看看