PHP设计模式
自动加载
__autoload();
魔术方法,当加载不存在的类的时候会使用这个方法,每一个文件中只能存在一次,并且抛出的Exception是不可catch的。php
spl_autoload_register();
能够调用用户本身的ClassLoader, Composer就是使用这种方法实现类的自动加载mysql
每一个文件中可有多个spl_autoload_register();方法,调用更加灵活;sql
抛出的Exception能够catch;数据库
并且可使用 spl_autoload_unregister();进行自动加载关闭,节省内存空间.canvas
PSR-0规范
PSR-0 (Autoloading Standard) 自动加载标准设计模式
PSR-1 (Basic Coding Standard) 基础编码标准数组
PSR-2 (Coding Style Guide) 编码风格向导浏览器
PSR-3 (Logger Interface) 日志接口缓存
PSR-4 (Improved Autoloading) 自动加载的加强版,能够替换掉PSR-0了。服务器
一个彻底合格的namespace和class必须符合这样的结构:“\< Vendor Name>(< Namespace>)*< Class Name>”
每一个namespace必须有一个顶层的namespace(”Vendor Name”提供者名字)
每一个namespace能够有多个子namespace
当从文件系统中加载时,每一个namespace的分隔符(/)要转换成 DIRECTORY_SEPARATOR(操做系统路径分隔符)
在类名中,每一个下划线(_)符号要转换成DIRECTORY_SEPARATOR(操做系统路径分隔符)。在namespace中,下划线(_)符号是没有(特殊)意义的。
当从文件系统中载入时,合格的namespace和class必定是以 .php 结尾的
verdor name,namespaces,class名能够由大小写字母组合而成(大小写敏感的)
PSR-4 规范
废除了支持PHP5.3代码之前的规范,而且去掉的下划线的意义。
八个经常使用设计模式
单例模式 Eg。数据库链接
要求:
-
$_instance必须为静态私有变量
-
构造函数 析构函数 拷贝函数必须为私有 防止外界实例化对象
-
getInstance()方法必须公有,返回实例一个引用。
节省内存 避免频繁new
工厂模式:生产对象使用
工厂模式能够避免类更名字以后,其余生成对象的代码都要一一修改,使用工厂能够避免频繁修改。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
Test1.php <?php class Test1{ static function test(){ echo __FILE__; } }
Factory.php <?php class Factory{ /* * 若是某个类在不少的文件中都new ClassName(),那么万一这个类的名字 * 发生变动或者参数发生变化,若是不使用工厂模式,就须要修改每个PHP * 代码,使用了工厂模式以后,只须要修改工厂类或者方法就能够了。 */ static function createDatabase(){ $test = new Test1(); return $test; } }
Test.php <?php spl_autoload_register('autoload1');
$test = Factory::createDatabase(); $test->test(); function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; }
|
注册模式:解决全局局部共享对象使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
<?php
class Register { protected static $objects; function set($alias,$object)//将对象注册到全局的树上 { self::$objects[$alias]=$object;//将对象放到树上 } static function get($name){ return self::$objects[$name];//获取某个注册到树上的对象 } function _unset($alias) { unset(self::$objects[$alias]);//移除某个注册到树上的对象。 } }
|
适配器模式,相似于下面的决策模式
将各类不一样的操做封装成接口API 好比数据库操做有MySQL,MySQLi,PDO。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
|
接口 IDatabase <?php namespace IMooc; interface IDatabase { function connect($host, $user, $passwd, $dbname); function query($sql); function close(); }
MySQL <?php namespace IMooc\Database; use IMooc\IDatabase; class MySQL implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $conn = mysql_connect($host, $user, $passwd); mysql_select_db($dbname, $conn); $this->conn = $conn; }
function query($sql) { $res = mysql_query($sql, $this->conn); return $res; }
function close() { mysql_close($this->conn); } }
MySQLi <?php namespace IMooc\Database; use IMooc\IDatabase; class MySQLi implements IDatabase { protected $conn;
function connect($host, $user, $passwd, $dbname) { $conn = mysqli_connect($host, $user, $passwd, $dbname); $this->conn = $conn; }
function query($sql) { return mysqli_query($this->conn, $sql); }
function close() { mysqli_close($this->conn); } }
|
策略模式:IOC思想 DI实现
也就是控制反转 依赖注入
防止种类过多时候发生太多if致使代码维护艰难
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
UserStrategy.php <?php /* * 声明策略文件的接口,约定策略包含的行为。 */ interface UserStrategy { function showAd(); function showCategory(); }
MaleUser.php <?php require_once 'Loader.php'; class MaleUser implements UserStrategy { function showAd(){ echo "IPhone6s"; } function showCategory(){ echo "电子产品"; } }
Page.php//执行文件 <?php require_once 'Loader.php'; class Page { protected $strategy; function index(){ echo "AD"; $this->strategy->showAd(); echo "<br>"; echo "Category"; $this->strategy->showCategory(); echo "<br>"; } function setStrategy(UserStrategy $strategy){ $this->strategy=$strategy; } }
$page = new Page(); if(isset($_GET['male'])){ $strategy = new MaleUser(); }else { $strategy = new FemaleUser(); } $page->setStrategy($strategy); $page->index();
|
观察者模式
适用于一带多频繁更新的操做,好比业务逻辑中一个数据更改致使其余表的数据也要跟着更改,直接硬编码更改的操做的不太好的,并且后期的维护也很不利,使用观察者模式能够进行事件发布,而后进行foreach进行更新操做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
EventGenerator.php <?php require_once 'Loader.php'; abstract class EventGenerator{ private $observers = array(); function addObserver(Observer $observer){ $this->observers[]=$observer; } function notify(){ foreach ($this->observers as $observer){ $observer->update(); } } }
Observer.php <?php require_once 'Loader.php'; interface Observer{ function update();//这里就是在事件发生后要执行的逻辑 }
//一个实现了EventGenerator抽象类的类,用于具体定义某个发生的事件 require 'Loader.php'; class Event extends EventGenerator{ function triger(){ echo "Event<br>"; } } class Observer1 implements Observer{ function update(){ echo "逻辑1<br>"; } } class Observer2 implements Observer{ function update(){ echo "逻辑2<br>"; } } $event = new Event(); $event->addObserver(new Observer1()); $event->addObserver(new Observer2()); $event->triger(); $event->notify();
|
原型模式
和工厂模式相似,适合建立大对象的时候,能够节约一下内存开销
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
Index.php <?php require 'Loader.php'; $c = new Canvas(); $c->init(); / $canvas1 = new Canvas(); // $canvas1->init(); $canvas1 = clone $c;//经过克隆,能够省去init()方法,这个方法循环两百次 //去产生一个数组。当项目中须要产生不少的这样的对象时,就会new不少的对象,那样 //是很是消耗性能的。 $canvas1->rect(2, 2, 8, 8); $canvas1->draw(); echo "-----------------------------------------<br>"; // $canvas2 = new Canvas(); // $canvas2->init(); $canvas2 = clone $c; $canvas2->rect(1, 4, 8, 8); $canvas2->draw();
|
MySQL 性能索引
索引数据结构
- B+ Tree
key放在叶子节点内的节点,叶子节点存放value 这样能够保证放更多的key,减小树的高度,树的高度的减小致使磁盘IO减小,能够优化性能。叶子节点处有相互连接的指针。InnoDB采用B+Tree能够将随机IO转换为顺序IO来提高效率。
- 搜索树
父节点大于左孩子节点,右孩子节点大于父节点
- 平衡二叉树
二叉树,可是要求任意一个节点的左右孩子节点高度差不大于1
- Hash Struct
哈希结构仅能知足 Exist In 等查询,不能使用范围查询。没法进行排序查询。不支持部分索引
汇集索引和非汇集索引
汇集索引Primary
InnoDB的数据文件自己就是索引文件,B+Tree的叶子节点上的data就是数据自己,key为主键,这是聚簇索引
非聚簇索引,叶子节点上的data是主键(因此聚簇索引的key,不能过长)。
索引的优势
-
变随机IO为顺序IO
-
避免全表扫描
-
能够帮助服务器避免排序或者临时表
索引对中小型表会比较高效,大型表须要考虑一下分区。
索引的建立方法
1 2 3 4 5 6 7 8
|
create index `idx_img` on newuser(`img`);
alter table newuser add index `idx_extra_img` (`isDeleted`, `img`)
drop index `idx_img` on newuser;
// 强制走索引的方式 select * from newuser force index where xxxx;
|
索引的注意
-
不鼓励使用like 不能够所有模糊查询 能够 55kai% 这样查
-
不能够进行列上操做 好比count sum等都会全表扫描 性能不好
-
不适用Not in <> 操做。
-
尽量使用分解关联查询 这样分解后 sql简单,利于MySQL缓存、减小锁竞争 更好的扩展和维护性。
HTTP 超文本传输协议
协议格式
三部分:
请求起始行、消息头、消息体
分块传送
当浏览器想服务器请求一个资源,这个资源是一个动态资源,服务器没法预知资源的大小,就应该采用分块传送
服务器先生成一个thunk 发送这个chunk 再生成 在发送 直到发送完成。
分块发送须要在请求头增长一个transfer-encoding:thunked
持久连接
HTTP早期版本由于连接不可复用,性能不好,TCP1.5的RTT(三次握手)和慢启动会拖慢速度。
1.1版本引入keep-alive的connection头,若是服务器和客户端都肯定keep-alive的话,在一个TCP上面能够传送多个请求。
持久连接也不该该一直保持,每一个人都会占用服务器资源,若是PV过高,服务器资源也会jinzhang
应该配置KeepAliveTimeout和KeepAliveRequests两个参数 限时限量
PipeLine管线化
也就是一个TCP上面能够产送多个HTTP请求,可是请求的顺序必须和返回的顺序一致
无状态性
指的是协议层无状态性 两次请求并无任何关系。经过会话控制能够保证访问的状态。