关于php:tp5源码分析第三步设计模式反射机制

36次阅读

共计 3671 个字符,预计需要花费 10 分钟才能阅读完成。

设计模式

1. 单例模式

单例模式首先要满足三个条件:1. 领有一个构造函数,并且为 private 2. 领有一个动态成员变量用来放弃类的实例 3. 领有一个拜访这个实例的静态方法。
单例模式一个类只有一个实例,并提供一个拜访它的全局拜访入口。单例模式是在你想管制实例数目,节俭系统资源的时候应用。例如以下场景中:
 1、一个党只能有一个书记。2、Windows 是多过程多线程的,在操作一个文件的时候,就不可避免地呈现多个过程或线程同时操作一个文件的景象,所以所有文件的解决必须通过惟一的实例来进行。3、一些设施管理器经常设计为单例模式,比方一个电脑有两台打印机,在输入的时候就要解决不能两台打印机打印同一个文件。
长处:1、在内存里只有一个实例,缩小了内存的开销,尤其是频繁的创立和销毁实例(比方治理学院首页页面缓存)。2、防止对资源的多重占用(比方写文件操作)。
咱们在 extend 目录下创立一个 Single.php 文件,以下是 Single 的内容。

咱们在 index.php 中创立一个 getSingle 办法

这时咱们发现,无论咱们调用多少次 Single,new 只执行一次。当 $instance 不存在的时候,就会 new 一个实例,当存在的时候就间接返回,最多执行一次 new。
tp5 框架用的单例模式在 Container.php 中,在 thinkphp\library\think 目录下。

2. 注册树模式

注册树模式通过将对象实例注册到一颗全局的对象树上,须要的时候从对象树上采摘下来应用。
单例模式解决的是如何在整个我的项目中创立惟一对象实例的问题,工厂模式解决的是如何不通过 new 建设实例对象的办法。那么注册树模式想解决什么问题呢?在思考这个问题前,咱们还是有必要思考下前两种模式目前面临的局限。首先,单例模式创立惟一对象的过程自身还有一种判断,即判断对象是否存在。存在则返回对象,不存在则创建对象并返回。每次创立实例对象都要存在这么一层判断。工厂模式更多思考的是扩大保护的问题。总的来说,单例模式和工厂模式能够产生更加正当的对象。怎么不便调用这些对象呢?而且在我的项目内如此建设的对象如同散兵游勇一样,不便兼顾治理安顿啊。因 而,注册树模式应运而生。不论你是通过单例模式还是工厂模式还是二者联合生成的对象,都通通给我“插到”注册树上。我用某个对象的时候,间接从注册树上取 一下就好。这和咱们应用全局变量一样的不便实用。而且注册树模式还为其余模式提供了一种十分好的想法。
接下来咱们进行注册树模式的实战解说,首先咱们在 extend 目录下创立一个 TestRegister.php 文件。在这个类外面咱们须要创立个注册树池子,而后创立几个办法,set()办法是把咱们的参数挂载在池子里,有两个参数,一个是 $key, 一个是 $object。set 办法的逻辑就是把 $object 填充到 $objects[$key]中去。

get 办法须要传入一个 $key 参数,咱们须要判断 $objects[$key]中是否存在,如果不存在,就填入;如果存在就返回。

_unset 办法同样传入 $key 参数,而后把 $objects[$key]清空。

这就是一个简略的注册树模式的代码。残缺代码是这样的:

而后咱们进行应用层逻辑编写,同样在 extend 目录下创立一个 A 类,轻易输入点内容。

而后咱们在 index.php 外面创立一个办法,实例化 A 类,把 A 类挂在注册池外面。

如果咱们有多个相似于 A 的类,咱们就能够通过下面 register 办法一样去把它们挂在连接池外面。

依赖注入

依赖注入次要用来缩小代码间的耦合 无效拆散对象和它所需的内部资源,接下来咱们通过代码来对它进行了解。
首先咱们在 extend 目录下创立一个 di 目录,di 目录里创立一个 Person 类,而后创立一个 buy 办法。接着再创立一个 Car 类,在外面创立一个 pay 办法,而后返回价格。在 buy 办法外面调用 Car 类外面的 pay 办法。


而后咱们在入口文件外面创立一个办法,而后调用 Person 类的 buy 办法。

这样就能够把 Car 类外面的 pay 办法调用了。这就是一个简略的依赖注入例子了。
其中 Person 类依赖于 Car 类,而后 Car 类注入到 Person 类中,因为 person 去买货色,不肯定要买 Car,还有其余物品,这时就要把买的物品注入到 Person 类中去。这个时候问题来了,如果咱们 buy 的货色是其余物品,而不是 Car,那咱们就要对代码进行批改了。批改如下:
首先把 Person 类外面的 buy 办法批改,之前咱们写的是指定的 Car,这个时候咱们就要把指定的 Car 换成须要购买的物品,代码如下,间接传入对象,而后通过传入的对象进行调用。

在入口文件的办法中,咱们间接创立一个须要用到的实例,而后传给 Person 的办法。

这里我 new 了一个 Car 类,如果咱们须要的不是 Car 类,而是其余的类,那咱们就把 Car 换成须要的类。

反射机制

反射机制是在 php5.0 之后的版本减少的一个个性,这个个性给咱们提供了一个弱小的 API,容许咱们在 php 运行环境中去拜访和应用类、办法、属性、参数和正文,它的性能是十分弱小的,常常用于高扩大的 php 框架,主动加载插件、生成文档。比如说咱们进行生成 php 外面的正文等,就是通过 php 里的反射机制进行的,甚至能够用来扩大 php 语言。反射机制外面有许多办法,咱们能够依据文档去查看各种办法的用处, 文档链接:php 反射机制链接。在咱们应用反射机制的时候,首先要对类进行实例化,而后实例化类的反射机制,接下来进行调用这些办法。

容器类简略实战

接下来咱们对下面的常识进行综合性的实际,创立一个简略的容器类。
咱们进行操作的文件有以下几个文件,首先是容器类 Container,而后是 Person 类和 Car 类,最初是应用层 index.php 入口文件。
首先是容器类 Container 代码:

<?php
namespace di;
class Container
{
 /*
 * 存放数据的容器 * */ public $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 set($key,$value){$this->instances[$key] = $value;
 }
 /*
 * 获取容器外面的实例  会用到反射机制 * */ public function get($key){if(!empty($this->instances[$key]))
 {$key = $this->instances[$key];
 }
 $reflect = new ReflectionClass($key);
 // 获取类的构造函数
 $c = $reflect->getConstructor();
 if (!$c){return new $key;}
 $params = $c->getParameters();
//        dump($params);exit();
 if (empty($params)){return new $key;}else{foreach ($params as $param){$class = $param->getClass();
 if (!$class){ }else{$args[] = $this->get($class->name);
 }
 } } return $reflect->newInstanceArgs($args);
 }
}

而后是 Person 代码

<?php
namespace di;
class Person
{public function __construct(Car $obj,$a = 124)
 { $this->obj = $obj;
 $this->a = $a;
 }
 /*
 * 依赖:Person 类依赖于 Car * 注入  Car 类注入到 Person * */ public function buy(){return $this->a . "|" . $this->obj->pay();
 }
}

Car 代码

<?php
namespace di;
class Car
{public  function pay(){return 123;}
}

而后是 index 入口文件的办法代码:

public function buy(){Container::getInstance()->set("person","diPerson");
 Container::getInstance()->set("car","diCar");
 $obj = Container::getInstance()->get("person");
 dump($obj->buy());
}

其中 Person、Car、Container 都在 extend 目录下的 di 目录中。

以上就是容器类的简略实现。

正文完
 0