tp5源码分析第三步------设计模式、反射机制

设计模式

1.单例模式

单例模式首先要满足三个条件:1.拥有一个构造函数,并且为private 2.拥有一个静态成员变量用来保持类的实例 3.拥有一个访问这个实例的静态方法。
单例模式一个类只有一个实例,并提供一个访问它的全局访问入口。单例模式是在你想控制实例数目,节省系统资源的时候使用。例如以下场景中:
 1、一个党只能有一个书记。 2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。 3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
优点: 1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。 2、避免对资源的多重占用(比如写文件操作)。
我们在extend目录下创建一个Single.php文件,以下是Single的内容。
image.png
我们在index.php中创建一个getSingle方法
image.png
这时我们发现,无论我们调用多少次Single,new只执行一次。当$instance不存在的时候,就会new一个实例,当存在的时候就直接返回,最多执行一次new。
tp5框架用的单例模式在Container.php中,在thinkphp\library\think目录下。
image.png

2.注册树模式

注册树模式通过将对象实例注册到一颗全局的对象树上,需要的时候从对象树上采摘下来使用。
单例模式解决的是如何在整个项目中创建唯一对象实例的问题,工厂模式解决的是如何不通过new建立实例对象的方法。 那么注册树模式想解决什么问题呢? 在考虑这个问题前,我们还是有必要考虑下前两种模式目前面临的局限。 首先,单例模式创建唯一对象的过程本身还有一种判断,即判断对象是否存在。存在则返回对象,不存在则创建对象并返回。 每次创建实例对象都要存在这么一层判断。 工厂模式更多考虑的是扩展维护的问题。 总的来说,单例模式和工厂模式可以产生更加合理的对象。怎么方便调用这些对象呢?而且在项目内如此建立的对象好像散兵游勇一样,不便统筹管理安排啊。因 而,注册树模式应运而生。不管你是通过单例模式还是工厂模式还是二者结合生成的对象,都统统给我“插到”注册树上。我用某个对象的时候,直接从注册树上取 一下就好。这和我们使用全局变量一样的方便实用。 而且注册树模式还为其他模式提供了一种非常好的想法。
接下来我们进行注册树模式的实战讲解,首先我们在extend目录下创建一个TestRegister.php文件。在这个类里面我们需要创建个注册树池子,然后创建几个方法,set()方法是把我们的参数挂载在池子里,有两个参数,一个是$key,一个是$object。set方法的逻辑就是把$object填充到$objects[$key]中去。
image.png

get方法需要传入一个$key参数,我们需要判断$objects[$key]中是否存在,如果不存在,就填入;如果存在就返回。
image.png

_unset方法同样传入$key参数,然后把$objects[$key]清空。
image.png
这就是一个简单的注册树模式的代码。完整代码是这样的:
image.png
然后我们进行应用层逻辑编写,同样在extend目录下创建一个A类,随便输出点内容。
image.png
然后我们在index.php里面创建一个方法,实例化A类,把A类挂在注册池里面。
image.png

如果我们有多个类似于A的类,我们就可以通过上面register方法一样去把它们挂在连接池里面。

依赖注入

依赖注入主要用来减少代码间的耦合 有效分离对象和它所需的外部资源,接下来我们通过代码来对它进行理解。
首先我们在extend目录下创建一个di目录,di目录里创建一个Person类,然后创建一个buy方法。接着再创建一个Car类,在里面创建一个pay方法,然后返回价格。在buy方法里面调用Car类里面的pay方法。
image.png
image.png
然后我们在入口文件里面创建一个方法,然后调用Person类的buy方法。
image.png
这样就可以把Car类里面的pay方法调用了。这就是一个简单的依赖注入例子了。
其中Person类依赖于Car类,然后Car类注入到Person类中,因为person去买东西,不一定要买Car,还有其他物品,这时就要把买的物品注入到Person类中去。这个时候问题来了,如果我们buy的东西是其他物品,而不是Car,那我们就要对代码进行修改了。修改如下:
首先把Person类里面的buy方法修改,之前我们写的是指定的Car,这个时候我们就要把指定的Car换成需要购买的物品,代码如下,直接传入对象,然后通过传入的对象进行调用。
image.png
在入口文件的方法中,我们直接创建一个需要用到的实例,然后传给Person的方法。
image.png
这里我new了一个Car类,如果我们需要的不是Car类,而是其他的类,那我们就把Car换成需要的类。

反射机制

反射机制是在php5.0之后的版本增加的一个特性,这个特性给我们提供了一个强大的API,允许我们在php运行环境中去访问和使用类、方法、属性、参数和注释,它的功能是非常强大的,经常用于高扩展的php框架,自动加载插件、生成文档。比如说我们进行生成php里面的注释等,就是通过php里的反射机制进行的,甚至可以用来扩展php语言。反射机制里面有许多方法,我们可以根据文档去查看各种方法的用途,文档链接:php反射机制链接。在我们使用反射机制的时候,首先要对类进行实例化,然后实例化类的反射机制,接下来进行调用这些方法。
image.png

容器类简单实战

接下来我们对上面的知识进行综合性的实践,创建一个简单的容器类。
我们进行操作的文件有以下几个文件,首先是容器类Container,然后是Person类和Car类,最后是应用层index.php入口文件。
首先是容器类Container代码:

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代码

obj = $obj;
 $this->a = $a;
 }
 /*
 * 依赖:Person类依赖于Car * 注入  Car类注入到Person * */ public function buy(){
 return $this->a . "|" . $this->obj->pay();
 }
}

Car代码

然后是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目录中。

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

你可能感兴趣的:(php后端)