Slim研读笔记五之依赖注入容器(中)
来源:互联网 发布:淘宝的聚划算怎么抢 编辑:程序博客网 时间:2024/06/05 03:12
“一步一步走,心急吃不来热豆腐呦” —郭X村口大爷
这节我们继续读上节没读完的代码。上节我们说到,应用主体传入了一个属性container,属性值为容器实例。然后,我们又了解了该容器类继承自Pimple容器实现自ContainerInterface接口,且这个容器接口继承自PsrContainerInterface。所以,Slim默认容器是符合PSR7规范的。之后,我们又从Container类构造方法开始研读,
/** * 创建新容器 * Create new container * * @param array $values The parameters or objects. */ public function __construct(array $values = []) { // 继承父类的构造方法 parent::__construct($values); // 获取配置文件中settings配置项的值 $userSettings = isset($values['settings']) ? $values['settings'] : []; // 注册Slim需要的一些默认服务 $this->registerDefaultServices($userSettings); }第一行代码是parent::__construct($values);
继承了父类的构造方法,那我们就不得不了解其父类构造方法。
/** * 实例化容器 * Instantiates the container. * * Objects and parameters can be passed as argument to the constructor. * * @param array $values The parameters or objects */ public function __construct(array $values = array()) { // 实例化factories,protected属性,且赋值为\SplObjectStorage()实例化对象 // SplObjectStorage提供了从对象到数据的映射,或者忽略数据提供对象集 $this->factories = new \SplObjectStorage(); $this->protected = new \SplObjectStorage(); // 将传入的配置项整合到容器对象 foreach ($values as $key => $value) { $this->offsetSet($key, $value); } }
下面,我们继续研读之后的代码...
该$values存储着组合之后默认配置与用户配置。而由$this->offsetSet方法了解到这些配置项中的参数和值存储在$this->values数组中。父类构造方法我们已经了解,下面继续回到Container类构造方法中。
// 注册Slim需要的一些默认服务$this->registerDefaultServices($userSettings);
查看之...
private function registerDefaultServices($userSettings) { $defaultSettings = $this->defaultSettings; /** * settings属性赋值集合对象,该对象是defaultSettings和userSettings的合并数组经处理后产生的集合对象 * This service MUST return an array or an * instance of \ArrayAccess. * * @return array|\ArrayAccess */ $this['settings'] = function () use ($userSettings, $defaultSettings) { return new Collection(array_merge($defaultSettings, $userSettings)); }; // 注册Slim默认服务 $defaultProvider = new DefaultServicesProvider(); $defaultProvider->register($this); }$this['settings']赋值为Slim\Collection类实例。
DefaultServicesProvider 类作用是注册一些默认服务,譬如环境模拟服务(将php全局变量集成到服务)、Request服务、Response服务、Router服务、各种异常错误处理服务以及CallableResolver服务(该类将格式为“class:method”字符串解析为一个闭包)。这些服务我们暂且了解下,下面继续往下研读。
我们跳到index.php页面,了解到:// 依赖注入容器$container = $app->getContainer();/** * Enable access to the DI container by consumers of $app * * @return ContainerInterface */public function getContainer(){ return $this->container;}getContainer()方法返回Container类对象,然后
// 在容器中注册Monolog日志组件$container['logger'] = function($c) { $logger = new \Monolog\Logger('my_logger'); $file_handler = new \Monolog\Handler\StreamHandler('../logs/app.log'); $logger->pushHandler($file_handler); return $logger;};可看到以闭包形式传递一个对象给容器对象数组$container['logger']。且我们在之后使用时,可直接以属性方式调用该logger对象。这步是如何完成的呢?
$this->logger->addInfo("发生了一件有趣的事,并把它记录了下来”);这和\ArrayAccess接口相关,并非实现了\ArrayAccess接口的类,只要给他的实例对象传入$test['a'] = 'hello',$test->a属性就可以获取到hello的,如果你要实现的话,会很遗憾的发现Undefined property: Test::$a…,而且即使你这样定义
Class Test implements ArrayAccess { ... }$test = new Test;$test['a'] = 'hello’;echo $test['a’];若没做任何处理,也不会有任何输出的。
这是由于我们的类实现了\ArrayAccess接口之后还要实现它的一些方法。让我们查看容器具体是如何实现的吧。
实现\ArrayAccess必须实现这四个方法:
offsetExists($offset) //判断是否存在偏移位置
offsetGet($offset) //获取偏移量
offsetSet($offset, $value) //设置偏移量
offsetUnset($offset) //去除偏移量
之前我们已经了解到,它在处理一些配置项时,使用$this->values数组存储键值对,使用$this->keys数组存储判断值,记录该id是否已被values存储。
/** * 设置参数或闭包对象 * Sets a parameter or an object. * * Objects must be defined as Closures. * * Allowing any PHP callable leads to difficult to debug problems * as function names (strings) are callable (creating a function with * the same name as an existing parameter would break your container). * * @param string $id The unique identifier for the parameter or object * @param mixed $value The value of the parameter or a closure to define an object * * @throws FrozenServiceException Prevent override of a frozen service */ public function offsetSet($id, $value) { if (isset($this->frozen[$id])) { throw new FrozenServiceException($id); } // 将赋值给values数组,并用keys数组记录 $this->values[$id] = $value; $this->keys[$id] = true; }offsetGet是比较重要的函数,学习之
/** * 得到一个参数或者对象 * Gets a parameter or an object. * $id是一个唯一标识符 * @param string $id The unique identifier for the parameter or object * 返回值为参数或对象 * @return mixed The value of the parameter or an object * * @throws UnknownIdentifierException If the identifier is not defined */ public function offsetGet($id) { // 不存在则抛出异常 if (!isset($this->keys[$id])) { throw new UnknownIdentifierException($id); } // raw数组尚不知何时赋值,但!is_object($this->values[$id])可知,若非对象则直接返回值。 if ( isset($this->raw[$id]) || !is_object($this->values[$id]) || isset($this->protected[$this->values[$id]]) || !method_exists($this->values[$id], '__invoke') ) { return $this->values[$id]; } // factories也不知有何作用 if (isset($this->factories[$this->values[$id]])) { return $this->values[$id]($this); } // 下面这几句解释了之前的疑惑,若值为闭包则将执行后的值赋给$val // raw数组存储原生闭包函数,并在获取过程中冻结该$id,即fronzen数组存储冻结的id // 最后返回闭包执行结果 $raw = $this->values[$id]; $val = $this->values[$id] = $raw($this); $this->raw[$id] = $raw; $this->frozen[$id] = true; return $val; }
由此知,在第一次执行闭包后,会将执行结果存储在raw数组中,下次就无需再次执行,直接根据id调用raw[]中的值。
/** * 检查参数或对象是否设置 * Checks if a parameter or an object is set. * * @param string $id The unique identifier for the parameter or object * * @return bool */ public function offsetExists($id) { return isset($this->keys[$id]); } /** * 去除参数或对象 * Unsets a parameter or an object. * * @param string $id The unique identifier for the parameter or object */ public function offsetUnset($id) { if (isset($this->keys[$id])) { if (is_object($this->values[$id])) { unset($this->factories[$this->values[$id]], $this->protected[$this->values[$id]]); } unset($this->values[$id], $this->frozen[$id], $this->raw[$id], $this->keys[$id]); } }
阅读全文
0 0
- Slim研读笔记五之依赖注入容器(中)
- Slim研读笔记五之依赖注入容器(上)
- Slim研读笔记五之依赖注入容器(下)
- Slim研读笔记五之依赖注入容器(补)
- Slim研读笔记七乱入篇之Monolog(中)
- Slim研读笔记六之应用主体(中)
- Slim研读笔记八之路由(中)
- Slim研读笔记三之Composer(上)
- Slim研读笔记六之应用主体(上)
- Slim研读笔记七乱入篇之Monolog(上)
- Slim研读笔记七乱入篇之Monolog(下)
- Slim研读笔记六之应用主体(下)
- Slim研读笔记七之应用程序中间件(上)
- Slim研读笔记七之应用程序中间件(下)
- Slim研读笔记八之路由(上)
- Slim研读笔记七乱入篇之Monolog(补)
- Slim研读笔记四之Composer(下)
- Slim研读笔记二之造一款Slim应用
- order by与group by与时间同时存在问题
- LeetCode-009 Palindrome Number
- junit并发访问数据库引发的问题
- 二叉树前序,中序,后序遍历详解
- C++知识总结思维导图
- Slim研读笔记五之依赖注入容器(中)
- LeetCode 115. Distinct Subsequences
- Yii中的安全防护
- HDU 5775 Bubble Sort(归并排序+逆序数)
- 20171206_工作记录
- Excel在统计分析中的应用—第九章—非参数检验-x2检验-拟合优度检验
- Linux 最常用的命令和功能总结
- vue-cli搭建中遇到的chromedriver安装失败问题解决
- 如何在局域网内设置多个网段