源码-反转控制的理解
反转控制是什么,有什么用:反转控制为Ioc Container,简称ICO,解决各个类之间的依赖问题。主流框架(laravel、yii等)源码均有出现,若不能理解反转控制,对源码的理解就很难深入。
- 功能是什么
1、存储定义的类
2、实例化类
案例说明-简易案例
//容器类,封装的很简单,set方法用于存储类,get用于实例化类
Class Container
{
private $_definitions;
//定义类
public function set($class, $definition)
{
$this->_definitions[$class] = $definition;
}
//实例化类 call_user_func:第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
public function get($class, $params = [])
{
$definition = $this->_definitions[$class];
return call_user_func($definition, $params);
}
}
//构造赋值属性
class EmailSenderBy163
{
private $_name;
public function __construct($name = '')
{
$this->_name = $name;
}
public function send()
{
}
}
$container = new Container;
$container->set('EmailSenderBy163', function ($name = '') {
//函数追加new自己函数
return new EmailSenderBy163($name);
});
//启动new函数new自己
$emailSenderBy163 = $container->get('EmailSenderBy163', '163');
echo "<pre>";
print_r($emailSenderBy163);
//打印出来的结果
EmailSenderBy163 Object
(
[_name:EmailSenderBy163:private] => 163
)
上述不太好理解,我还用思维导图做了图让你理解,绝对贴心
案例说明-复杂案例
//没什么好说,一个类构造赋值属性
class EmailSenderBy163
{
private $_name;
public function __construct($name = '')
{
$this->_name = $name;
}
public function send()
{
}
}
class User
{
private $_emailSenderObject;
//构造赋值并限制$emailSenderObject为EmailSenderBy163 类和子类为
public function __construct(EmailSenderBy163 $emailSenderObject)
{
$this->_emailSenderObject = $emailSenderObject;
}
public function register()
{
$this->_emailSenderObject->send();
}
}
//容器
Class Container
{
private $_definitions;
public function set($class, $definition)
{
$this->_definitions[$class] = $definition;
}
public function get($class, $params = [])
{
//get方法在判断回调函数上更加严谨
if (isset($this->_definitions[$class]) && is_callable($this->_definitions[$class], true)) {
$definition = $this->_definitions[$class];
//$this是指这个容器
return call_user_func($definition, $this, $params);
} else {
throw new Exception("error");
}
}
}
$container = new Container;
$container->set('EmailSenderBy163', function ($container, $name = '') {
return new EmailSenderBy163($name);
});
$container->set('User', function ($container, $params = []) {
//$container对应上述的$this,这样拿到相对应参数,这里有点绕想想会明白的
return new User($container->get($params[0], $params[1]));
});
echo '<pre>';
print_r($container->get('EmailSenderBy163', ['163']));
print_r($container->get('User', ['EmailSenderBy163', '163']));
这就是反转控制,需要先把所有的类全部set进去,然后get的时候指定其所依赖的类,依然很麻烦。可以考虑使用反射,并做自动实例化处理。
反射类地址:http://php.net/manual/zh/book.reflection.php
利用反射增加容器类
Class Container
{
public function get($class, $params = [])
{
return $this->build($class, $params);
}
public function build($class, $params)
{
$dependencies = [];
//实例化反射类
$reflection = new ReflectionClass($class);
//获取类的构造函数
$constructor = $reflection->getConstructor();
if ($constructor !== null) {
//获取参数
foreach ($constructor->getParameters() as $param) {
//获得类的提示类型
$c = $param->getClass();
if ($c !== null) {
//获取类名
$dependencies[] = $this->get($c->getName(), $params);
}
}
}
foreach ($params as $index => $param) {
$dependencies[$index] = $param;
}
//从给出的参数创建一个新的类实例
return $reflection->newInstanceArgs($dependencies);
}
}
$container = new Container;
$user = $container->get('User');
echo '<pre>';
print_r($user);
输出结果
User Object
(
[_emailSenderObject:User:private] => EmailSenderBy163 Object
(
[_name:EmailSenderBy163:private] =>
)
)