今日目标
- 能够掌握面向对象的高级特性
- 能够具备设计纯面向对象框架和系统的能力
- 能够遵循PSR-0规范开发一个基础框架
- 能够掌握单例模式
- 能够掌握工厂模式
- 能够掌握注册树模式
一、什么是设计模式?
1.概念
设计模式(英语 design pattern)是对面向对象设计中反复出现的问题的解决方案。
2.举例
如果我们把面向对象编程当成一本武功秘籍,设计模式就是其中的每一招每一式,如果我们可以把设计模式式活学活用,那在面向对象编程方面那一定是一个非常厉害的高手了!
二、开发环境准备
一、编辑器的选址
1.下载PHPStorm
2.选择编程字体
- 必须选择等宽字体
- 常见的等宽变成自提包括Courier Nes,Consolas
- 个人推荐大家使用Soure Code Pro,是由Adobe公司专为程序员设计,免费开源
默认字体展示出来的效果:
设置等宽字体:
设置玩字体展示出来的效果:
三、命名空间与类自动载入
一、 命名空间的介绍
概念:
namespace即“命名空间”,也称“名称空间” 。各种语言使用的一种代码组织的形式 通过名称空间来分类,区别不同的代码功能
基本介绍:
命名空间是用来组织和重用代码的。如同名字一样的意思,NameSpace(名字空间),之所以出来这样一个东西,是因为人类可用的单词数太少,并且不同的人写的程序不可能所有的变量都没有重名现象,对于库来说,这个问题尤其严重,如果两个人写的库文件中出现同名的变量或函数(不可避免),使用起来就有问题了。为了解决这个问题,引入了名字空间这个概念,通过使用 namespace xxx;你所使用的库函数或变量就是在该名字空间中定义的,这样一来就不会引起不必要的冲突了。
2.命名空间的使用
==a)不使用命名空间,案例演示==
运行报错(无法重新声明方法)
==b)使用命名空间案例演示==
正常运行(输出当前的文件名称)
3.Phpstorm在控制台中输出运行结果
参考链接:blog.csdn.net/weixin_3718…
1、先打开菜单Run->Edit Configurations选项
2、然后在打开的窗口中点击左上角的+号
3、在打开的菜单中选择PHP Script
4、在打开的界面中找到Configuration->File
5、选择你要在控制台运行的文件
6、填入工作目录的路径(可填可不填),完成配置后点击右下角的OK
7、回到主界面,点击菜单Run->Run
二、类自动载入
1.概念
在编写面向对象(OOP) 程序时,很多开发者为每个类新建一个 PHP 文件。 这会带来一个烦恼:每个脚本的开头,都需要包含(include)一个长长的列表(每个类都有个文件)。
spl_autoload_register() 函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
==Note==
尽管 __autoload() 函数也能自动加载类和接口,但更建议使用 spl_autoload_register() 函数。 spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载(同一个应用中,可以支持任意数量的加载器,比如第三方库中的)。因此,不再建议使用 __autoload() 函数,在以后的版本中它可能被弃用。
三、开发一个PRS-0的基础框架
1.PRS-0规范
- 命名空间必须与绝对路径一致
- 类名首字母必须大写
- 除入口文件外,其他".php"必须只有一个类
2.开发符合PSR-0规范的基础框架
- 全部使用命名空间
- 所有PHP文件必须自动载入,不能有include/require
3.进行开发框架
进行带领同学们共同封装一个基础框架
进行测试框架
入口文件自动加载所有的类文件
五、PHP面向对象高级特性
一、SPL库的使用(PHP标准库)
参考链接:www.php.net/spl
==SPL库的使用(PHP标准库)==
- SplStack、SplQueue、SplHeap、SplFixedArray等数据结构
- ArrayItertor、AppendIterator、Countable、ArrayObject
- SPL提供的函数
1.栈操作
概念:SplStack类通过使用一个双向链表来提供栈的主要功能。
特性:先进后出
$stack = new SplStack(); $stack->push("data1\n"); $stack->push("data2\n"); echo $stack->pop(); echo $stack->pop(); 复制代码
2.队列操作
概念:SplQueue 类通过使用一个双向链表来提供队列的主要功能。
特性:先进先出
$queue = new SplQueue(); $queue->enqueue("data1\n"); $queue->enqueue("data2\n"); echo $queue->dequeue(); echo $queue->dequeue(); 复制代码
3.最小堆
概念:SplMinHeap类提供堆的主要功能,将最小值保持在顶部。
$heap = new SplMinHeap(); $heap->insert("data1\n"); $heap->insert("data2\n"); echo $heap->extract(); echo $heap->extract();
4.最小长度的数组 固定尺寸数组
概念:SplFixedArray类提供了数组的主要功能。SplFixedArray与普通PHP数组之间的主要区别在于,必须手动调整SplFixedArray的大小,并且只允许范围内的整数作为索引。优点是它比标准阵列使用更少的内存。
$array = new SplFixedArray(10); $array[0] = 123; $array[9] = 1234; var_dump($array); 复制代码
二、PHP链式操作的实现
1.如何实现数据库链式操作
==$db->where()->limit()->order();==
2.实现代码
文件:Vendor/Database.php
<?php namespace Vendor; class Database { function where($where) { return $this; //链式操作的核心就是返回当前对象 } function order($order) { return $this; } function limit($limit) { return $this; } } 复制代码
文件:index.php
//不是链式操作 //$db = new Vendor\Database(); //$db->where("id=1"); //$db->where("name=1"); //$db->where("id desc"); //$db->limit(10); //链式操作 $db->where("id=1")->where("name=2")->order("id desc")->limit(10); 复制代码
三、PHP魔术方法的使用
1.常见的魔术方法
- __get/__set
- __call/__callStatic
- __toString
- __invoke
2.魔术方法的实现
==__get/__set==
- __set 当对对象不存在的属性进行赋值时会进行调用该方法
- __get 当读取一个对象不存在的属性时会调用该方法
index.php
文件
//$obj = new Vendor\Obj(); //调用对象不存在的属性时 //$obj->title = 'hello'; //echo $obj->title; 复制代码
Vendor/Obj.php
文件
protected $array = []; //当对对象不存在的属性进行赋值时会进行调用该方法 function __set($key, $value) { var_dump(__METHOD__); $this->array[$key] = $value; } //当读取一个对象不存在的属性时会调用该方法 function __get($key) { var_dump(__METHOD__); return $this->array[$key]; } 复制代码
==__call/__callStatic==
- __call 当调用对象中不存在的方法时自动调用
- __callStatic 当调用对象中不存在的静态方法时自动调用
index.php
文件
//调用对象不存在的方法时 //echo $obj->test('hello',123); //调用对象不存在的静态方法时 //echo $obj::test('hello',123); 复制代码
Vendor/Obj.php
文件
//当调用一个不存在的方法是会自动调用 function __call($name, $arguments) { // TODO: Implement __call() method. var_dump($name,$arguments); return "magic function\n"; } //当调用不存在的静态方法时会自动调用 public static function __callStatic($name, $arguments) { // TODO: Implement __callStatic() method. var_dump($name,$arguments); return "magic static function\n"; } 复制代码
==__toString==
当把对象当成字符串使用时,会自动调用该方法
index.php
文件
//将对象转成成字符串,会自动调用该方法 //echo $obj; 复制代码
Vendor/Obj.php
文件
//将对象转成成字符串,会自动回调该方法 public function __toString() { // TODO: Implement __toString() method. //返回一个字符串 return __CLASS__; } 复制代码
==__invoke==
index.php
文件
echo $obj('test1'); 复制代码
Vendor/Obj.php
文件
//把对象当成一个函数去用,会调用该方法 public function __invoke($params) { var_dump($params); // TODO: Implement __invoke() method. return 'invoke'; } 复制代码
四、三种基础设计模式
一、基础设计模式简介
- 工厂模式(工厂方法或者类生成对象,而不是代码中直接new)
- 单例模式(使某个类的对象仅允许创建一个)
- 注册模式(全局共享和交换对象)
二、[php]工厂模式
1. 概念
工厂模式是我们最常用的实例化对象模式,是用工厂方法代替new操作的一种模式。
2.那么何为工厂模式?
从名字来看,似乎看不出什么端倪。工厂模式,和生产有关?还是和生产流程有关?难道还和工厂领导有关?和领导秘书有关?秘书... 好了不卖关子了,所谓工厂模式还真和生产有关。生产什么呢?生产出来的是一个实例对象。通过什么设备生产?通过一个工厂类生产。怎么生产呢?工厂类调用自身静态方法来生产对象实例。
工厂模式有一个关键的构造,根据一般原则命名为Factory的静态方法,然而这只是一种原则,虽然工厂方法可以任意命名这个静态还可以接受任意数据的参数,必须返回一个对象。
3. 为什么要用工厂模式?
很多没接触过工厂模式的人会不禁问,为啥我要费那么大的劲儿去构造工厂类去创建对象呢?不去套用那些易维护,可扩展之类的话,我们可以考虑这样 一个简单的问题。如果项目中,我们通过一个类创建对象。在快完成或者已经完成,要扩展功能的时候,发现原来的类类名不是很合适或者发现类需要添加构造函数 参数才能实现功能扩展。我靠!我都通过这个类创建了一大堆对象实例了啊,难道我还要一个一个去改不成?我们现在才感受到了“高内聚低耦合”的博大精深。没 问题,工厂方法可以解决这个问题。
==如果类名发生变化,或者方法的参数发生变化,需要修改所有引入该类的文件,不易于维护,紧耦合。我们要解决这个问题,所以要使用工厂方法。==
==工厂模式更多的是解决后期拓展(大部分是文件命名修改后)的问题。==
3.工厂模式如何实现?
相对于单例模式,上面我们提供了足够的信息,工厂类,工厂类里面的静态方法。静态方法里面new一下需要创建的对象实例就搞定了。当然至于考虑 上面的第二个问题,根据工厂类静态方法的参数,我们简单做个判断就好了。管你用if..else..还是switch..case..,能快速高效完成判 断该创建哪个类的工作就好了。最后,一定要记得,工厂类静态方法返回一个对象。不是两个,更不是三个。
index.php
文件
//工厂模式 //$db = new Vendor\Database(); //$db = Vendor\Factory::createDatabase(); //var_dump($db); 复制代码
Vendor/Factory.php
文件
<?php namespace Vendor; class Factory { static function createDatabase() { //统一进行实例化数据库连接 $db = new Database(); return $db; } } 复制代码
==总结:工厂模式是其设计模式惯用的基础模式,其它高级的设计模式都是依赖于工厂 模式==