首页 > 编程 > PHP > 正文

如何在yii2框架的di容器源码中了解反射的作用

2020-03-22 19:06:24
字体:
来源:转载
供稿:网友
这篇文章主要介绍了关于如何在yii2框架的di容器源码中了解反射的作用,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

反射简介

参考官方简介的话,PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释

YII2框架中示例

对于yii2框架,应该都知道di容器,对于di容器的源码这里也主要讲明Container类,先看看平时怎么使用di,就用yii2框架中注释的示例代码来展示;

container调用示例
namespace app/models;use yii/base/BaseObject;use yii/db/Connection;use yii/di/Container;interface UserFinderInterface function findUser();html' target='_blank'>class UserFinder extends BaseObject implements UserFinderInterface public $db; public function __construct(Connection $db, $config = []) $this- db = $db; parent::__construct($config); public function findUser() class UserLister extends BaseObject public $finder; public function __construct(UserFinderInterface $finder, $config = []) $this- finder = $finder; parent::__construct($config); $container = new Container; $container- set( yii/db/Connection , [ dsn = ... , $container- set( app/models/UserFinderInterface , [ class = app/models/UserFinder , $container- set( userLister , app/models/UserLister  $lister = $container- get( userLister  // 上述操作相当于下列实现 $db = new /yii/db/Connection([ dsn = ...  $finder = new UserFinder($db); $lister = new UserLister($finder);

上面的示例代码只是实例化了Container类,然后调用set方法注入了其他对象,最后获取到了依赖与其他对象创建的lister对象,既然只调用了set方法与get方法,那就先从调用最多的set开始看Container代码。

set方法
public function set($class, $definition = [], array $params = []) $this- _definitions[$class] = $this- normalizeDefinition($class, $definition); $this- _params[$class] = $params; unset($this- _singletons[$class]); return $this;}

上面的代码比较简洁,调用了类的normalizeDefinition方法,这个一会再说,先说明在该方法中出现的三个属性的含义

_definitions数组,保存依赖定义

_params数组,保存构造函数的参数

_singletons,保存单例

再看normalizeDefinition方法,该方法主要作用是规范类定义

protected function normalizeDefinition($class, $definition) if (empty($definition)) { // 为空 return [ class = $class]; } elseif (is_string($definition)) { // 为字符串 return [ class = $definition]; } elseif (is_callable($definition, true) || is_object($definition)) { // 检验是否为可调用函数或者对象 return $definition; } elseif (is_array($definition)) { // 检测是否为数组 if (!isset($definition[ class ])) { if (strpos($class, // ) !== false) { $definition[ class ] = $class; } else { throw new InvalidConfigException( A class definition requires a class member.  return $definition; throw new InvalidConfigException( Unsupported definition type for / $class/ : . gettype($definition));}

上述代码中已做了一些判断注释,不难发现最后需要返回的definition变量需要为数组格式,或者可调用函数与对象,注意回到刚开始的调用示例代码,definition变量分别有数组格式不带class键,
数组格式带class键,与字符串类型。到底set方法调用已完毕,从源码中分析基本上看不到反射的影子,也就是些传入参数格式兼容处理再写入类属性,接着来看下示例代码中的get方法吧。

get 方法
public function get($class, $params = [], $config = []) if (isset($this- _singletons[$class])) { // 直接返回单例 return $this- _singletons[$class]; } elseif (!isset($this- _definitions[$class])) { // 调用bulid return $this- build($class, $params, $config); $definition = $this- _definitions[$class]; if (is_callable($definition, true)) { // 可调用函数情况 $params = $this- resolveDependencies($this- mergeParams($class, $params)); $object = call_user_func($definition, $this, $params, $config); } elseif (is_array($definition)) { // 数组 $concrete = $definition[ class  unset($definition[ class  $config = array_merge($definition, $config); $params = $this- mergeParams($class, $params); if ($concrete === $class) { $object = $this- build($class, $params, $config); } else { $object = $this- get($concrete, $params, $config); } elseif (is_object($definition)) { // 对象直接保存到单例属性集合中去 return $this- _singletons[$class] = $definition; } else { throw new InvalidConfigException( Unexpected object definition type: . gettype($definition)); if (array_key_exists($class, $this- _singletons)) { // singleton $this- _singletons[$class] = $object; return $object;}

上述代码,简要划分一下,请稍作浏览,后面会继续讲述,先说明属性_definitions集合中不存在的情况,即调用build,这个一会说明,再看如果存在相关class键的情况,下面会做几种情况的处理,

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表