3.25周 一周拾遗

PHP设计模式

自动加载

__autoload();

魔术方法,当加载不存在的类的时候会使用这个方法,每个文件中只能存在一次,而且抛出的Exception是不可catch的。

spl_autoload_register();

可以调用用户自己的ClassLoader, Composer就是使用这种方法实现类的自动加载

每个文件中可有多个spl_autoload_register();方法,调用更加灵活;

抛出的Exception可以catch;

而且可以使用 spl_autoload_unregister();进行自动加载关闭,节省内存空间.

  • 自动加载不可用于CLI模式

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。数据库连接

要求:

  1. $_instance必须为静态私有变量

  2. 构造函数 析构函数 拷贝函数必须为私有 防止外界实例化对象

  3. 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 性能索引

索引数据结构

  1. B+ Tree

key放在叶子节点内的节点,叶子节点存放value 这样可以保证放更多的key,减少树的高度,树的高度的减少导致磁盘IO减少,可以优化性能。叶子节点处有相互链接的指针。InnoDB采用B+Tree可以将随机IO转换为顺序IO来提升效率。

  1. 搜索树

父节点大于左孩子节点,右孩子节点大于父节点

  1. 平衡二叉树

二叉树,但是要求任意一个节点的左右孩子节点高度差不大于1

  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请求,但是请求的顺序必须和返回的顺序一致

无状态性

指的是协议层无状态性 两次请求并没有任何关系。通过会话控制可以保证访问的状态。

posted @ 2018-09-10 23:31  guoguoqingzhe  阅读(95)  评论(0编辑  收藏  举报