• 【thinkphp6源码分析三】 APP类之父, 容器Container类


    上一篇关于APP类的构造函数 最后还有三句话

    1   static::setInstance($this);
    
    2   $this->instance('app', $this);
    3   $this->instance('thinkContainer', $this);
     1  /**
     2      * 绑定一个类实例到容器
     3      * @access public
     4      * @param string $abstract 类名或者标识
     5      * @param object $instance 类的实例
     6      * @return $this
     7      */
     8     public function instance(string $abstract, $instance)
     9     {
    10         $abstract = $this->getAlias($abstract);
    11 
    12         $this->instances[$abstract] = $instance;
    13 
    14         return $this;
    15     }
    View Code

    这里基本都涉及到APP的父类Container[tp6vendor opthinkframeworksrc hinkContainer.php]了

    第一句话 是设置了Container类的$instance属性 把这个属性设置为APP类的实例
    这里可以理解为 Container是一个比较抽象的容器类,它可以作用于任何框架,而APP类则相当于这个抽象容器的实现,也就是适合TP框架的一个容器类
    [对应前面说过的注册树模式 这里是实例化一个适用于TP框架的 TP容器注册树]

    第二句和第三句 是设置容器里面的东西 将具体的类实例放到容器中仔细看 它们是设置了一个叫

     instances数组(这里多了一个s)的内容
    [对应前面说过的注册树模式 这里是开始给这棵树挂苹果了 目前挂了两个苹果
    一个叫app 一个叫thinkContainer 俩苹果的内容是相同的 后面 框架一定会给这棵树挂更多的苹果 如db config cache等等]

    我们继续看Container类

    Container类本身代码并不复杂 但是看得相当懵逼,因为太抽象了 ,光看这个代码根本不知道这些代码干嘛的?

    但实际上 这个基本 可以说是所有框架的基石不为过

    它的细节作用 其实从它的第一句话可以看出来

    class Container implements ContainerInterface, ArrayAccess, IteratorAggregate, Countable

    它分别实现了ContainerInterface(容器) ;ArrayAccess(数组式访问); IteratorAggregate(聚合迭代器);Countable(可计数的)

    上面()里面的中文只是这些单词的翻译,实际上也的确就是这些翻译的字面意思

    第一个ContainerInterface先放一放 它自己都叫容器 那么容器接口的实现当然是它最主要的功能

    我们看第二个ArrayAccess

    这东西叫数组式访问 那么是把啥当数组式访问呢 也就对象了

    我们在用TP框架的时候 应该没少写或者见过这样的东西

    $user=new UserModel()

    $user['username']  =  "卢小霏";

    按照我们正统语法 这样写是错误的  $user 是个对象 要使用它的属性 应该用$user->username呀?

    但由于数组和对象这俩有比较多的共同点,PHP就提供了ArrayAccess接口  只要我们实现它 上面例子 UserModel就实现了ArrayAccess  就能把对象当做数组来使用了

    ArrayAccess类我们可以看一下 实际很简短

    interface ArrayAccess {
    
        public function offsetExists($offset);
    
        public function offsetGet($offset);
    
        public function offsetSet($offset, $value);
    
        public function offsetUnset($offset);
    }

    就这么四个方法  分别是判断是否存在,获取,设置,删除,(也数组的增删改查)

    那么我们想一下一个对象,肯定可有对一个对象的属性进行增删改查的行为吧

    在这里Container这个类里面  这四个方法 对应的实现是

      public function offsetExists($key)
        {
            return $this->exists($key);
        }
    
        public function offsetGet($key)
        {
            return $this->make($key);
        }
    
        public function offsetSet($key, $value)
        {
            $this->bind($key, $value);
        }
    
        public function offsetUnset($key)
        {
            $this->delete($key);
        }

    其中 $this->bind我们前面说过 它有两个作用 关于第二个作用 就是把一个类实例塞到容器中, 也就是一开始那个instances数组里面插入一条 以便后面使用

    make暂不解释,delete和exists比较简单,分别从instances数组里面删除一个元素;判断instances数组里面是否存在等

    这里既然Contaner类实现了ArrayAccesss 且给四个方法实现了具备自己特色的功能 那么在实际场景中 我们该如何去使用呢

    我们可以在TP原来的index控制器 [tp6appcontrollerIndex.php]文件下 写点测试代码

     1    public function index()
     2     {
     3         $app = new App();
     4 
     5         $app['user']  = new User();
     6 
     7         $app['user2']  = new User2();
     8         dump($app);
     9         unset($app['user2']);
    10         dump($app);
    11 
    12         die;
    13     }
    View Code

    由于APP这个类继承了Container Container这个类又实现了ArrayAccess

    那么我们就可以像玩数组一样去 玩$app类

    $app[] =  xxx ====》这样就等同于去执行$app类里面的bind方法 最终效果是$instances 里面 会多出user 和user2 两个对象实例

    然后既然是数组 unset这个函数也可以使用  

    unset($app['user2'])   ===>这个就等同于去执行$app类里面的delete方法  最终就是把$instances里面的对应元素进行删除

    这样使用的话 是不是就发现很方便呢

    第三个IteratorAggregate(聚合迭代器) 这个目前框架上的应用不是很多 配合yield关键字 可以达到一种省内存的目的,一般可以用于Excel大数据导出之类

    如果以后遇到例子再细讲

    第四个Countable(可计数的) 对象里面的统计功能,在Container类里面 它统计了instaces里面的元素个数,也就是有多少“东西”已经在容器中

    最后 我们再回到容器类的核心部分   它首先实现了ContainerInterface这个接口 这个接口的作用很简单 一个get 一个has

    get 的实现  实际我们第一章就遇到过  它们通过make函数 来创建容器里面的实例(存在就直接读取 不重复创建)    has则是判断容器里面某个实例是否存在

    [关于make函数我们先大体上了解它的作用记性 

    极其简单的可以先认为 它等同于New关键字  即实例化一个类从而获得一个对象; 

    它有些其它的功能相当复杂 主要是涉及到依赖注入和反射相关知识 这个后面的章节会仔细讲到的]

    make函数里面有 $this->instances[$abstract] = $object;  这一句话

    这玩意那实际就和bind函数一样了 

    这里就是make先创建出一个实例 然后塞到容器里面

     关于bind和make 我们可以在index控制 随意写点测试代码

     1   public function index()
     2     {
     3         $app =new App();
     4 
     5         $userModel =new User();
     6         //先注释之前 先捋一下类 和实例的关系  appmodelUser是类  new appmodelUser()是实例
     7         //给appmodelUser 加一个别名 myUserClass  这个别名会在app-> $bind属性里面
     8         $app->bind("myUserClass","appmodelUser");
     9 
    10         //将User类的实例 $userModel 放到容器中 并且给个别名 myUser 这个myUser会在app -> $instances里面
    11         $app->bind("myUser",$userModel);
    12 
    13         //利用make函数 去实例化User类  这里完全等同于 new appmodelUser()
    14         $userModel1 =$app->make("appmodelUser");
    15         //由于 appmodelUser 类有个别名 myUserClass 所以这里可以直接这样去make
    16         $userModel2 =$app->make("myUserClass");
    17         //由于上面的类实例 $userModel 也有别名了 这里也可以直接使用myUser 相当于去$instances数组里面 直接找到它来使用
    18         $userModel3 =$app->make("myUser");
    19 
    20         dump($app);
    21         dump($userModel1);
    22         dump($userModel2);
    23         dump($userModel3);die;
    24         //return $str ;
    25 
    26     }

    可以观察下打印结果$app类里面 $bind 属性和  $instances 属性的变化

    ^ thinkApp {#50 ▼
      #appDebug: false
      #beginTime: null
      #beginMem: null
      #namespace: "app"
      #rootPath: "D:phpwamp64_3.17www	p6"
      #thinkPath: "D:phpwamp64_3.17www	p6vendor	opthinkframeworksrc"
      #appPath: "D:phpwamp64_3.17www	p6app"
      #runtimePath: "D:phpwamp64_3.17www	p6
    untime"
      #routePath: ""
      #configExt: ".php"
      #initializers: array:3 [▶]
      #services: []
      #initialized: false
      #bind: array:27 [▼
        "app" => "thinkApp"
        "cache" => "thinkCache"
        "config" => "thinkConfig"
        "console" => "thinkConsole"
        "cookie" => "thinkCookie"
        "db" => "thinkDb"
        "env" => "thinkEnv"
        "event" => "thinkEvent"
        "http" => "thinkHttp"
        "lang" => "thinkLang"
        "log" => "thinkLog"
        "middleware" => "thinkMiddleware"
        "request" => "thinkRequest"
        "response" => "thinkResponse"
        "route" => "thinkRoute"
        "session" => "thinkSession"
        "validate" => "thinkValidate"
        "view" => "thinkView"
        "filesystem" => "thinkFilesystem"
        "thinkDbManager" => "thinkDb"
        "thinkLogManager" => "thinkLog"
        "thinkCacheManager" => "thinkCache"
        "PsrLogLoggerInterface" => "thinkLog"
        "thinkRequest" => "appRequest"
        "thinkexceptionHandle" => "appExceptionHandle"
        "myRequest" => "appRequest"
        "myUserClass" => "appmodelUser"
      ]
      #instances: array:4 [▼
        "thinkApp" => thinkApp {#50}
        "thinkContainer" => thinkApp {#50}
        "myUser" => appmodelUser {#51}
        "appmodelUser" => appmodelUser {#53}
      ]
      #invokeCallback: []
    }
    ^ appmodelUser {#53}
    ^ appmodelUser {#53}
    ^ appmodelUser {#51}
    View Code


  • 相关阅读:
    2016年6月1日下午(传智Bootstrap笔记(Bootstrap标签、徽章、超大屏幕))
    2016年6月1日下午(传智Bootstrap笔记(Bootstrap分页))
    2016年6月1日下午(传智Bootstrap笔记(Bootstrap 导航栏元素))
    2016年5月31日上午(传智Bootstrap笔记(Bootstrap 导航元素))
    2016年5月31日上午(传智Bootstrap笔记(Bootstrap 布局组件输入框组))
    2016年5月30日下午(传智Bootstrap笔记八(Bootstrap 布局组件))
    2016年5月30日上午(传智Bootstrap笔记七(辅助类样式))
    c# 四舍五入、上取整、下取整
    C#索引器
    C#--使用Lock标记临界区
  • 原文地址:https://www.cnblogs.com/dk1988/p/14513837.html
Copyright © 2020-2023  润新知