IOC容器及Facade 深度解析
<h2>IOC</h2>
<ul>
<li>英文全称:Inversion of Control,</li>
<li>中文名称:控制反转,它还有个名字叫依赖注入(Dependency Injection,简称DI)。</li>
</ul>
<h2>单例模式</h2>
<ul>
<li>在一个进程里边,请求一次,不管使用多少次,只实例化一次,</li>
<li>解决在全局中创建唯一的一个全局实例</li>
<li>getInstance() thinkphp/library/think/Container.php</li>
</ul>
<h2>工厂模式</h2>
<ul>
<li>多个对象有同一个方法,再通过一个新的对象调用多个对象中的相同方法</li>
<li>如:解决配置文件调用不同类型时,如json、xml等,有利于扩展和维护,不需要在业务层改代码,只需要在底层增加代码</li>
<li>factory() thinkphp/library/think/Loader.php</li>
</ul>
<h2>注册树模式</h2>
<ul>
<li>将对象实例注册到一棵全局的对象树上,需要的时候从对象树上采摘下来使用</li>
<li>解决常用的一些类库挂载到注册树上,用到某个类时,不需要new,直接从注册树上获取到一个内容</li>
<li>容器就是用到了注册树的思想
<ul>
<li><a href="https://www.cnblogs.com/sgm4231/p/9849836.html">https://www.cnblogs.com/sgm4231/p/9849836.html</a></li>
</ul></li>
</ul>
<h2>依赖注入和控制反转</h2>
<ul>
<li>
<p>可以理解为同一个东西,是编程的一种思想,主要目的是减少代码之间的耦合,有效分离对象和它所需的外部资源</p>
<h2>依赖注入代码示例</h2>
</li>
<li><a href="https://www.cnblogs.com/phpper/p/6716375.html">https://www.cnblogs.com/phpper/p/6716375.html</a></li>
</ul>
<pre><code class="language-PHP"><?php
class Person {
/**
* 依赖:Person类依赖于Car类
* 注入:Car类注入到Pseron类中
*/
public function buy($obj) {
return $obj->pay();
}
}
class Car {
public function pay() {
return 50000;
}
}
class Iphone {
public function pay() {
return 6600;
}
}
$Person = new Person();
// echo $Person->buy(new Car()) . PHP_EOL;
// echo $Person->buy(new Iphone()) . PHP_EOL;</code></pre>
<h2>反射机制</h2>
<ul>
<li>在php5.0版本以后,增加反射机制特性</li>
<li>反射机制提供一个强大的反射api,允许在php运行环境中,去访问和使用类的方法、属性、参数和注释,这些都可以获取到</li>
<li>经常使用在高扩展的php框架,自动加载插件,自动生成文档。甚至可以扩展php语言</li>
<li>手册位置 函数参考->变量与类型相关扩展->反射</li>
</ul>
<h2>反射机制代码示例</h2>
<pre><code class="language-PHP"><?php
class A {
public $aa = 1;
private $bb = 2;
public static $instance = null;
/**
* A类的abc方法
* @param $a
* @param $b
* @return string
*/
public function adc($a, $b) {
return 'abcd';
}
/**
* type方法
* @param int $type
* @return string
*/
public function mf($type = 1) {
return 'type:' . $type;
}
}
// 正常实例化操作
$A = new A();
//var_dump($A);
// 使用反射类
$ReflectionClass = new ReflectionClass($A);
$newInstance = $ReflectionClass->newInstance(); // 相当于实例化这个类
$getMethods = $ReflectionClass->getMethods(); // 获取类中的所有方法
$getMethods = $ReflectionClass->getMethods();
foreach ($getMethods as $method) {
// 获取类中的所有注释
// var_dump($method->getDocComment());
}
$getProperties = $ReflectionClass->getProperties(); // 获取类中的所有属性,公有和私有的
</code></pre>
<h2>玩转自己的容器类</h2>
<ul>
<li>thinkphp/library/think/Container.php</li>
</ul>
<h2>代码示例</h2>
<pre><code class="language-PHP">class Person {
public function __construct(Car $obj, $a = 12) {
$this->obj = $obj;
$this->a = $a;
}
public function buy() {
return $this->a . ' | ' . $this->obj ->pay();
}
}
class Car {
public function pay() {
return 50000;
}
}
class Container {
protected $instances = []; // 存放容器的数据
protected static $instance; // 容器中的对象实例
private function __construct() {}
/**
* 获取当前容器的实例(单例)
*/
public static function getInstance() {
if (is_null(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}
public function get($key) {
if (!empty($this->instances[$key])) {
$key = $this->instances[$key];
}
$ReflectionClass = new ReflectionClass($key);
// 获取构造函数
$getConstructor = $ReflectionClass->getConstructor();
if (!$getConstructor) {
return new $key;
}
// 获取参数
$getParameters = $getConstructor->getParameters();
// 无参数,直接实例化
if (empty($getParameters)) {
return new $key;
}
foreach ($getParameters as $parameter) {
$getClass = $parameter->getClass();
if (!$getClass) {
} else {
$args[] = $this->get($getClass->name);
}
}
return $ReflectionClass->newInstanceArgs($args);
}
public function set($key, $value) {
$this->instances[$key] = $value;
}
}
Container::getInstance()->set('Person', 'Person');
$Person = Container::getInstance()->get('Person');
$buy = $Person->buy();
// var_dump($buy);
</code></pre>
<h2>Countable 巧用</h2>
<ul>
<li>Countable::count — 统计一个对象的元素个数</li>
<li>php手册位置->函数参考->其他基本扩展->SPL->接口->Countable</li>
</ul>
<h2>Countable代码示例</h2>
<pre><code class="language-PHP">class TestCountable implements Countable {
public function count() {
return 1234;
}
}
$TestCountable = new TestCountable();
// $count = $TestCountable->count();
// var_dump(count($TestCountable));
</code></pre>
<h2>门面模式</h2>
<ul>
<li>门面为容器中的类提供了一个静态调用接口,相比于传统的静态方法调用,带来了更好的可测试性和扩展性</li>
<li>门面模式结合容器思想,静态调用。门面模式的好处是通类的静态调用一些方法</li>
<li>父类 thinkphp/library/think/Facade.php</li>
<li>子类 thinkphp/library/think/facade</li>
</ul>
<pre><code class="language-php">class TestCallStatic {
/**
* 当调用的静态方法不存在或权限不足时,会自动调用__callStatic方法。
*/
public static function __callStatic($callback, array $param_arr) {
var_dump($callback); // getInfo
var_dump($param_arr); // array('100', 'zhangsan');
}
}
TestCallStatic::getInfo('100', 'zhangsan');</code></pre>
<h2>自定义门面模式实例</h2>
<ul>
<li>application/common/Facadetest.php</li>
</ul>
<pre><code class="language-php">namespace app\common;
class Facadetest {
public function getInfo() {
return __METHOD__;
}
}
// application/facade/Facadetest.php
namespace app\facade;
use think\Facade;
class Facadetest extends Facade {
// 从thinkphp/library/think/facade/目录中复制文件修改
protected static function getFacadeClass() {
return '\app\common\Facadetest'; //没有绑定类的别名,所以要返回全的命名空间
}
}</code></pre>
<ul>
<li>application/index/controller/Index.php</li>
</ul>
<pre><code class="language-php">namespace app\index\controller;
class Index {
public function facadeTest() {
echo \app\facade\Facadetest::getInfo();
}
}</code></pre>
<h2>自定义门面模式实例-绑定</h2>
<ul>
<li>application/common/Facadebindtest.php</li>
</ul>
<pre><code class="language-php">namespace app\common;
class Facadebindtest {
public function getInfo() {
return __METHOD__;
}
}
// application/facade/Facadebindtest.php
namespace app\facade;
use think\Facade;
class Facadebindtest extends Facade { }
// application/index/controller/Index.php
namespace app\index\controller;
class Index {
public function facadeBindTest() {
\think\facade::bind('app\facade\Facadebindtest', 'app\common\Facadebindtest');
echo \app\facade\Facadebindtest::getInfo();
}
}</code></pre>