一、PHP常用的四种数据结构
简介:spl是php的一个标准库。
官方文档:http://php.net/manual/zh/book.spl.php
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
|
<?php
$stack = new SplStack();
$stack ->push( ‘data1‘ );
$stack ->push( ‘data2‘ );
$stack ->push( ‘data3‘ );
echo $stack ->pop();
echo $stack ->pop();
echo $stack ->pop();
$queue = new SplQueue();
$queue ->enqueue( ‘data4‘ );
$queue ->enqueue( ‘data5‘ );
$queue ->enqueue( ‘data6‘ );
echo $queue ->dequeue();
echo $queue ->dequeue();
echo $queue ->dequeue();
echo $queue ->dequeue();
$heap = new SplMinHeap();
$heap ->insert( ‘data8‘ );
$heap ->insert( ‘data9‘ );
$heap ->insert( ‘data10‘ );
echo $heap ->extract();
echo $heap ->extract();
echo $heap ->extract();
$array = new SplFixedArray(15);
$array [ ‘0‘ ] = 54;
$array [ ‘6‘ ] = 69;
$array [ ‘10‘ ] = 32;
var_dump( $array );
|
二、PHP链式操作的实现(原理)
1、入口文件 index.php
1
2
3
4
5
6
7
8
9
10
11
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
$db = new \Extend\Database();
$db ->where( ‘uid < 100000‘ )->->order( ‘uid desc‘ )->limit(100);
|
2、自动加载类 Loader.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?php
namespace Extend;
class Loader
{
static function autoload( $class )
{
require BASEDIR. ‘/‘ . str_replace ( ‘\\‘ , ‘/‘ , $class ). ‘.php‘ ;
}
}
|
3、数据库类Database.php
注:只是原理,并没有对方法进行具体的封装,具体的封装还是看个人喜好去定链式查询的风格。
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
|
<?php
namespace Extend;
class Database
{
function where( $where )
{
return $this ;
}
function order( $order )
{
return $this ;
}
function limit( $limit )
{
return $this ;
}
}
|
其实就是对传过来的条件进行重新的底层封装,然后再把当前对象返回,使得可以不断的链式查询。
三、PHP魔术方法的使用
在php设计模式中,会涉及到很多魔术方法的使用,这里也对经常会用到的魔术方法进行简单总结。
1、框架入口文件 index.php
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
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
# 实例化Object类
$obj = new \Extend\Object();
# __set 和 __get 对不存在的属性进行接管
$obj ->title = ‘xiaobudiu‘ ;
echo $obj ->title;
# __call 和 __callStatic 对不存在或者权限不够的类方法进行接管
$obj ->getUserInfo( ‘1000068‘ );
\Extend\Object::getOpenId( ‘1000068‘ );
# echo 或 print 对象时,由__toString 接管
echo $obj ;
# 在php中,如果我们把一个对象当成函数用,则由__invoke()接管
$obj ( ‘xiaobudiu‘ );
|
2、 Extend/Object.php
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
62
63
64
65
66
67
68
69
|
<?php
namespace Extend;
class Object
{
protected $array = array ();
function __set( $name , $value )
{
echo "this is __set func" ;
}
function __get( $name )
{
echo "this is __get func" ;
}
function __call( $name , $arguments )
{
var_dump( $name , $arguments );
}
function __callStatic( $name , $arguments )
{
var_dump( $name , $arguments );
}
function __toString()
{
echo "this is __toString func" ;
}
function __invoke( $param )
{
echo $param . "<br>this is __invoke func" ;
}
}
|
四、三种基础设计模式
1、工厂模式
通过传入参数的不同,来实例化不同的类。
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
$config = array (
‘host‘ => ‘127.0.0.1‘ ,
‘pass‘ => ‘myRedis&&&‘
);
$cache = Extend\CacheFactory::getCacheObj( ‘redis‘ , $config );
var_dump( $cache );
|
Extend/CacheFactory.php
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
|
<?php
namespace Extend;
class CacheFactory
{
const FILE = 1;
const MEMCACHE = 2;
const REDIS = 3;
static $instance ;
static function getCacheObj( $type , array $options )
{
switch ( $type ) {
case ‘file‘ :
case self::FILE:
self:: $instance = new FileCache( $options );
break ;
case ‘memcache‘ :
case self::MEMCACHE:
self:: $instance = new Memcache( $options );
break ;
case ‘redis‘ :
case self::REDIS:
self:: $instance = new RedisCache( $options );
break ;
default :
self:: $instance = new FileCache( $options );
break ;
}
return self:: $instance ;
}
}
|
2、单例模式
保证一个类只实例化一个类对象,进而减少系统开销和资源的浪费
index.php
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
$obj = Extend\SingleObject::getInstance();
$obj2 = Extend\SingleObject::getInstance();
var_dump( $obj , $obj2 );
|
Extend/SingleObject.php
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
|
<?php
namespace Extend;
class SingleObject
{
private static $instance = null;
private function __construct(){}
private function __clone(){}
public static function getInstance()
{
if ( is_null (self:: $instance )){
self:: $instance = new self;
}
return self:: $instance ;
}
}
|
3、注册树模式
将我们用到的对象注册到注册树上,然后在之后要用到这个对象的时候,直接从注册树上取下来就好。(就和我们用全局变量一样方便)
Extend/RegisterTree,php
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
|
<?php
namespace Extend;
class RegisterTree
{
static protected $objects ;
static function setObject( $alias , $object )
{
self:: $objects [ $alias ] = $object ;
}
static protected function getObject( $alias )
{
return self:: $objects [ $alias ];
}
public function unsetObject( $alias )
{
unset(self:: $objects [ $alias ]);
}
}
|
五、其他常见的8种PHP设计模式
1、适配器模式
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
常见的有两种适配器,分别是类适配器和对象适配器,这里拿更看好的对象适配器举例:
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
<?php
namespace Extend;
interface Target
{
public function simpleMethod1();
public function simpleMethod2();
}
class Adaptee
{
public function simpleMethod1()
{
echo ‘Adapter simpleMethod1‘ . "<br>" ;
}
}
class Adapter implements Target
{
private $adaptee ;
function __construct()
{
$adaptee = new Adaptee();
$this ->adaptee = $adaptee ;
}
public function simpleMethod1()
{
echo $this ->adaptee->simpleMethod1();
}
public function simpleMethod2()
{
echo ‘Adapter simpleMethod2‘ . "<br>" ;
}
}
$adapter = new Adapter();
$adapter ->simpleMethod1();
$adapter ->simpleMethod2();
|
2、策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式,策略模式可以实现依赖倒置以及控制反转。
实例举例:假如一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示展示不同的广告。
index.php
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
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
class Home
{
protected $userType ;
function index()
{
echo "AD:" ;
$this ->userType->showAd();
echo "Category:" ;
$this ->userType->showCategory();
}
function setUserType(\Extend\UserType $userType )
{
$this ->userType = $userType ;
}
}
$obj = new Home();
if ( $_GET [ ‘userType‘ ] == ‘female‘ ){
$userType = new \Extend\FemaleUserType();
} else {
$userType = new \Extend\MaleUserType();
}
$obj ->setUserType( $userType );
$obj ->index();
|
Extend/userType.php(定义的接口)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
<?php
namespace Extend;
interface UserType
{
function showAd();
function showCategory();
}
|
MaleUserType.php、FemaleUserType.php(具体实现的类 )
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
|
<?php
namespace Extend;
class MaleUserType implements UserType
{
function showAd()
{
echo "this is 男性’s 广告条目数据" ;
}
function showCategory()
{
echo "this is 男性’s 商品类目数据" ;
}
}
|
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
|
<?php
namespace Extend;
class FemaleUserType implements UserType
{
function showAd()
{
echo "this is 女性’s 广告条目数据" ;
}
function showCategory()
{
echo "this is 女性’s 商品类目数据" ;
}
}
|
显示效果:
3、数据对象映射模式
将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作。
下面在代码中实现数据对象映射模式,我们将实现一个ORM类,将复杂的sql语句映射成对象属性的操作。并结合使用数据对象映射模式、工厂模式、注册模式。
-----(1)数据库映射模式简单实例实现
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
$user = new Extend\User(25);
$user ->name = ‘小卜丢饭团子‘ ;
$user ->salary = ‘20000‘ ;
$user ->city = ‘浙江省‘ ;
|
Extend/User.php
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
|
<?php
namespace Extend;
class User
{
public $id ;
public $name ;
public $salary ;
public $city ;
protected $pdo ;
public $data ;
function __construct( $id )
{
$this ->id = $id ;
$this ->pdo = new \PDO( ‘mysql:host=127.0.0.1;dbname=test‘ , ‘root‘ , ‘123456‘ );
}
function __destruct()
{
$this ->pdo->query( "update user set name = ‘{$this->name}‘,salary = ‘{$this->salary}‘,city = ‘{$this->city}‘ where id=‘{$this->id}‘" );
}
}
|
这样,执行index.php文件,数据库就会发生相应的操作,也就实现了基本的数据对象映射。
-------(2)数据库映射模式复杂案例实现
index.php
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
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
class EX
{
function index()
{
$user = Extend\Factory::getUserObj(25);
$user ->name = ‘小卜丢饭团子‘ ;
$user ->salary = ‘20000‘ ;
$user ->city = ‘浙江省‘ ;
}
function test()
{
$user = Extend\Factory::getUserObj(25);
$user ->city = ‘广东省‘ ;
}
}
$ex = new EX();
$ex ->index();
|
Extend/Factory.php
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
|
<?php
namespace Extend;
class Factory
{
static function CreateDatabaseObj()
{
$db = Database::getInstance();
return $db ;
}
static function getUserObj( $id )
{
$key = ‘user‘ . $id ;
$user = RegisterTree::getObject( $key );
if (! $user ) {
$user = new User( $id );
RegisterTree::setObject( $key , $user );
}
return $user ;
}
}
|
Extend/Register.php
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
|
<?php
namespace Extend;
class RegisterTree
{
static protected $objects ;
static function setObject( $alias , $object )
{
self:: $objects [ $alias ] = $object ;
}
static function getObject( $alias )
{
return self:: $objects [ $alias ];
}
public function unsetObject( $alias )
{
unset(self:: $objects [ $alias ]);
}
}
|
Extend/User.php
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
|
<?php
namespace Extend;
class User
{
public $id ;
public $name ;
public $salary ;
public $city ;
protected $pdo ;
public $data ;
function __construct( $id )
{
$this ->id = $id ;
$this ->pdo = new \PDO( ‘mysql:host=127.0.0.1;dbname=test‘ , ‘root‘ , ‘123456‘ );
}
function __destruct()
{
$this ->pdo->query( "update user set name = ‘{$this->name}‘,salary = ‘{$this->salary}‘,city = ‘{$this->city}‘ where id=‘{$this->id}‘" );
}
}
|
这样,就实现了稍复杂的数据对象映射模式和工厂模式、注册树模式相结合的案例。
4、观察者模式
当一个对象状态发生改变时,依赖它的对象会全部收到通知,并自动更新。
场景:一个事件发生后,要执行一连串更新操作。传统的编程方式就是在事件的代码之后直接加入处理逻辑,当更新的逻辑增多之后,代码会变的难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码。观察者模式实现了低耦合,非侵入式的通知与更新机制。
4.1、传统模式举例:
<?php
/**
* 框架入口文件
*/
define(‘BASEDIR‘,__DIR__);//项目根目录
include BASEDIR.‘/Extend/Loader.php‘;//引入项目自动加载类文件
spl_autoload_register(‘\\Extend\\Loader::autoload‘);//执行自动加载函数,完成类的自动加载
/**
* 一个事件的逻辑控制器
* Class Event
*/
class Event
{
/**
* 用户确认订单
*/
function firmOrder()
{
//这里假设一个事件发生了,比如用户已经完成下单
echo "用户已下单<br>";
//传统方式是在发生一个事件之后直接进行一系列的相关处理,耦合度比较高,比如写入日志,给用户发邮件等等
echo "在用户下单之后进行的一系列操作<br>";
}
}
$event = new Event();
$event->firmOrder();
4.2、观察者模式典型实现方式:
(1)定义2个接口:观察者(通知)接口、被观察者(主题)接口
(2)定义2个类,观察者类实现观察者接口、被观察者类实现被观察者接口
(3)被观察者注册自己需要通知的观察者
(4)被观察者类某个业务逻辑发生时,通知观察者对象,进而每个观察者执行自己的业务逻辑。
代码示例:
test.php
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
<?php
interface TicketObserver
{
function buyTicketOver( $sender , $args );
}
interface TicketObserved
{
function addObserver( $observer );
}
class BuyTicket implements TicketObserved
{
private $observers = array ();
public function addObserver( $observer )
{
$this ->observers[] = $observer ;
}
public function buyTicket( $ticket )
{
foreach ( $this ->observers as $observe ) {
$observe ->buyTicketOver( $this , $ticket );
}
}
}
class buyTicketMSN implements TicketObserver
{
public function buyTicketOver( $sender , $ticket )
{
echo ( date ( ‘Y-m-d H:i:s‘ ) . " 短信日志记录:购票成功:$ticket<br>" );
}
}
class buyTicketLog implements TicketObserver
{
public function buyTicketOver( $sender , $ticket )
{
echo ( date ( ‘Y-m-d H:i:s‘ ) . " 文本日志记录:购票成功:$ticket<br>" );
}
}
class buyTicketCoupon implements TicketObserver
{
public function buyTicketOver( $sender , $ticket )
{
echo ( date ( ‘Y-m-d H:i:s‘ ) . " 赠送优惠券:购票成功:$ticket 赠送10元优惠券1张。<br>" );
}
}
$buy = new BuyTicket();
$buy ->addObserver( new buyTicketMSN());
$buy ->addObserver( new buyTicketLog());
$buy ->addObserver( new buyTicketCoupon());
$buy ->buyTicket ( "7排8号" );
|
浏览器显示结果:
5、原型模式
原型模式与工厂模式的作用类似,都是用来创建对象的。但是实现方式是不同的。原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样,就免去了类创建时重复的初始化操作。
原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次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
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
62
63
64
65
66
67
68
69
70
|
<?php
interface Prototype
{
public function copy ();
}
class ConcretePrototype implements Prototype
{
private $_name ;
public function __construct( $name )
{
$this ->_name = $name ;
}
public function setName( $name )
{
$this ->_name = $name ;
}
public function getName()
{
return $this ->_name;
}
public function copy ()
{
return clone $this ;
}
}
class Demo
{
public $array ;
}
$demo = new Demo();
$demo -> array = array (1, 2);
$object1 = new ConcretePrototype( $demo );
$object2 = $object1 -> copy ();
var_dump( $object1 ->getName());
echo ‘<br />‘ ;
var_dump( $object2 ->getName());
echo ‘<br />‘ ;
$demo -> array = array (3, 4);
var_dump( $object1 ->getName());
echo ‘<br />‘ ;
var_dump( $object2 ->getName());
echo ‘<br />‘ ;
|
浏览器显示结果:
6、装饰器模式
可以动态的添加或修改类的功能
一个类实现一个功能,如果要再修改或添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法。
使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性。
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
<?php
interface Decorator
{
public function beforeEcho();
public function afterEcho();
}
class ColorDecorator implements Decorator
{
protected $color ;
public function __construct( $color )
{
$this ->color = $color ;
}
public function beforeEcho()
{
echo "<dis style=‘color: {$this->color}‘>" ;
}
public function afterEcho()
{
echo "</p>" ;
}
}
class SizeDecorator implements Decorator
{
protected $size ;
public function __construct( $size )
{
$this ->size = $size ;
}
public function beforeEcho()
{
echo "<dis style=‘font-size: {$this->size}px‘>" ;
}
public function afterEcho()
{
echo "</p>" ;
}
}
class EchoText
{
protected $decorators = array ();
public function Index()
{
$this ->beforeEcho();
echo "你好,我是装饰器。" ;
$this ->afterEcho();
}
public function addDecorator(Decorator $decorator )
{
$this ->decorators[] = $decorator ;
}
protected function beforeEcho()
{
foreach ( $this ->decorators as $decorator )
$decorator ->beforeEcho();
}
protected function afterEcho()
{
$tmp = array_reverse ( $this ->decorators);
foreach ( $tmp as $decorator )
$decorator ->afterEcho();
}
}
$echo = new EchoText();
$echo ->addDecorator( new ColorDecorator( ‘yellow‘ ));
$echo ->addDecorator( new SizeDecorator( ‘22‘ ));
$echo ->Index();
|
7、迭代器模式
在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素而又不暴露该对象的内部表示,这就是PHP迭代器模式的定义。
相对于传统编程模式,迭代器模式可以隐藏遍历元素的所需的操作。
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
$users = new Extend\AllUser();
foreach ( $users as $user ) {
var_dump( $user );
}
|
Extend/AllUser.php
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
62
63
64
65
66
67
68
69
|
<?php
namespace Extend;
class AllUser implements \Iterator
{
protected $index = 0;
protected $ids = array ();
protected $pdo ;
function __construct()
{
$this ->pdo = new \PDO( ‘mysql:host=127.0.0.1;dbname=test‘ , ‘root‘ , ‘123456‘ );
$this ->ids = $this ->pdo->query( "select id from user" )->fetchAll(2);
}
public function rewind ()
{
$this ->index = 0;
}
public function current()
{
$id = $this ->ids[ $this ->index][ ‘id‘ ];
$user_data = $this ->pdo->query( "select * from user where id=‘{$id}‘" )->fetch(2);
return $user_data ;
}
public function key()
{
return $this ->index;
}
public function next()
{
$this ->index++;
}
public function valid()
{
return $this ->index < count ( $this ->ids);
}
}
|
8、代理模式
在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节。
典型的应用就是mysql的主从结构,读写分离。在mysql中,对所有读的操作请求从库,所有写的操作请求主库。
声明一个代理类,前台使用时只需创建一个代理类,调用对应方法即可。代码实例:
index.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
#查询操作使用从库
#增删改操作使用主库
$db_proxy = new Extend\Proxy();
$db_proxy ->getUserName(1);
$db_proxy ->setUserName(29, ‘xiaobudiu‘ );
|
Extend/Proxy.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<?php
namespace Extend;
class Proxy implements IUserProxy
{
function getUserName( $id )
{
$db = Factory::getDatabase( ‘slave‘ );
$db ->query( "select name from user where id =$id limit 1" );
}
function setUserName( $id , $name )
{
$db = Factory::getDatabase( ‘master‘ );
$db ->query( "update user set name = $name where id =$id limit 1" );
}
}
|
Extend/Factory.php
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
|
<?php
namespace Extend;
class Factory
{
static function getDatabase( $id )
{
$key = ‘database_‘ . $id ;
if ( $id == ‘slave‘ )
{
$slaves = Application::getInstance()->config[ ‘database‘ ][ ‘slave‘ ];
$db_conf = $slaves [ array_rand ( $slaves )];
} else {
$db_conf = Application::getInstance()->config[ ‘database‘ ][ $id ];
}
$db = Register::get( $key );
if (! $db ) {
$db = new Database\MySQLi();
$db ->connect( $db_conf [ ‘host‘ ], $db_conf [ ‘user‘ ], $db_conf [ ‘password‘ ], $db_conf [ ‘dbname‘ ]);
Register::set( $key , $db );
}
return $db ;
}
}
|
Extend/Application.php
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
|
<?php
namespace Extend;
class Application
{
public $base_dir ;
protected static $instance ;
public $config ;
protected function __construct( $base_dir )
{
$this ->base_dir = $base_dir ;
$this ->config = new Config( $base_dir . ‘/configs‘ );
}
static function getInstance( $base_dir = ‘‘ )
{
if ( empty (self:: $instance ))
{
self:: $instance = new self( $base_dir );
}
return self:: $instance ;
}
}
|
Extend/Config.php
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
|
<?php
namespace Extend;
class Config implements \ArrayAccess
{
protected $path ;
protected $configs = array ();
function __construct( $path )
{
$this ->path = $path ;
}
function offsetGet( $key )
{
if ( empty ( $this ->configs[ $key ]))
{
$file_path = $this ->path. ‘/‘ . $key . ‘.php‘ ;
$config = require $file_path ;
$this ->configs[ $key ] = $config ;
}
return $this ->configs[ $key ];
}
function offsetSet( $key , $value )
{
throw new \Exception( "cannot write config file." );
}
function offsetExists( $key )
{
return isset( $this ->configs[ $key ]);
}
function offsetUnset( $key )
{
unset( $this ->configs[ $key ]);
}
}
|
configs/database.php
<?php
$config = array(
‘master‘ => array(
‘type‘ => ‘MySQL‘,
‘host‘ => ‘127.0.0.1‘,
‘user‘ => ‘root‘,
‘password‘ => ‘123456‘,
‘dbname‘ => ‘test‘,
),
‘slave‘ => array(
‘slave1‘ => array(
‘type‘ => ‘MySQL‘,
‘host‘ => ‘127.0.0.1‘,
‘user‘ => ‘root‘,
‘password‘ => ‘123456‘,
‘dbname‘ => ‘test‘,
),
‘slave2‘ => array(
‘type‘ => ‘MySQL‘,
‘host‘ => ‘127.0.0.1‘,
‘user‘ => ‘root‘,
‘password‘ => ‘123456‘,
‘dbname‘ => ‘test‘,
),
),
);
return $config;
五、其余设计模式以及总结
六、面向对象编程的基本原则
1、单一职责原则:一个类只需要做好一件事情。不要使用一个类完成很多功能,而应该拆分成更多更小的类。
2、开放封闭原则:一个类写好之后,应该是可扩展而不可修改的。
3、依赖倒置原则:一个类不应该强依赖另外一个类,每个类对于另外一个类都是可替换的。
4、配置化原则:尽量使用配置,而不是硬编码。
5、面向接口编程原则:只需要关心某个类提供了哪些接口,而不需要关心他的实现。
七、自动加载配置类文件
1、php中使用ArrayAccess实现配置文件的加载(使得程序可以以数组的方式进行读取配置)
(1)定义Config.php,继承php自带的ArrayAccess接口,并实现相应的方法,用于读取和设置配置
Extend/Config.php
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
|
<?php
namespace Extend;
class Config implements \ArrayAccess
{
protected $path ;
protected $configs = array ();
function __construct( $path )
{
$this ->path = $path ;
}
function offsetGet( $key )
{
if ( empty ( $this ->configs[ $key ]))
{
$file_path = $this ->path. ‘/‘ . $key . ‘.php‘ ;
$config = require $file_path ;
$this ->configs[ $key ] = $config ;
}
return $this ->configs[ $key ];
}
function offsetSet( $key , $value )
{
throw new \Exception( "cannot write config file." );
}
function offsetExists( $key )
{
return isset( $this ->configs[ $key ]);
}
function offsetUnset( $key )
{
unset( $this ->configs[ $key ]);
}
}
|
(2)configs/database.php
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
|
<?php
$config = array (
‘master‘ => array (
‘type‘ => ‘MySQL‘ ,
‘host‘ => ‘127.0.0.1‘ ,
‘user‘ => ‘root‘ ,
‘password‘ => ‘123456‘ ,
‘dbname‘ => ‘test‘ ,
),
‘slave‘ => array (
‘slave1‘ => array (
‘type‘ => ‘MySQL‘ ,
‘host‘ => ‘127.0.0.1‘ ,
‘user‘ => ‘root‘ ,
‘password‘ => ‘123456‘ ,
‘dbname‘ => ‘test‘ ,
),
‘slave2‘ => array (
‘type‘ => ‘MySQL‘ ,
‘host‘ => ‘127.0.0.1‘ ,
‘user‘ => ‘root‘ ,
‘password‘ => ‘123456‘ ,
‘dbname‘ => ‘test‘ ,
),
),
);
return $config ;
|
(3)读取配置
index.php
1
2
3
4
5
6
7
8
9
10
|
<?php
define( ‘BASEDIR‘ ,__DIR__);
include BASEDIR. ‘/Extend/Loader.php‘ ;
spl_autoload_register( ‘\\Extend\\Loader::autoload‘ );
$config = new Extend\Config(__DIR__. ‘/configs‘ );
var_dump( $config [ ‘database‘ ]);
|
(4)浏览器显示:
到此,就可以在程序中随心所欲的加载配置文件了。
2、在工厂方法中读取配置,生成可配置化的对象
Extend/Factory.php
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
|
<?php
namespace Extend;
class Factory
{
static function getDatabase( $id )
{
$key = ‘database_‘ . $id ;
if ( $id == ‘slave‘ )
{
$slaves = Application::getInstance()->config[ ‘database‘ ][ ‘slave‘ ];
$db_conf = $slaves [ array_rand ( $slaves )];
} else {
$db_conf = Application::getInstance()->config[ ‘database‘ ][ $id ];
}
$db = Register::get( $key );
if (! $db ) {
$db = new Database\MySQLi();
$db ->connect( $db_conf [ ‘host‘ ], $db_conf [ ‘user‘ ], $db_conf [ ‘password‘ ], $db_conf [ ‘dbname‘ ]);
Register::set( $key , $db );
}
return $db ;
}
}
|
Extend/Application.php
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
|
<?php
namespace Extend;
class Application
{
public $base_dir ;
protected static $instance ;
public $config ;
protected function __construct( $base_dir )
{
$this ->base_dir = $base_dir ;
$this ->config = new Config( $base_dir . ‘/configs‘ );
}
static function getInstance( $base_dir = ‘‘ )
{
if ( empty (self:: $instance ))
{
self:: $instance = new self( $base_dir );
}
return self:: $instance ;
}
}
|
Extend/Config.php
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
|
<?php
namespace Extend;
class Config implements \ArrayAccess
{
protected $path ;
protected $configs = array ();
function __construct( $path )
{
$this ->path = $path ;
}
function offsetGet( $key )
{
if ( empty ( $this ->configs[ $key ]))
{
$file_path = $this ->path. ‘/‘ . $key . ‘.php‘ ;
$config = require $file_path ;
$this ->configs[ $key ] = $config ;
}
return $this ->configs[ $key ];
}
function offsetSet( $key , $value )
{
throw new \Exception( "cannot write config file." );
}
function offsetExists( $key )
{
return isset( $this ->configs[ $key ]);
}
function offsetUnset( $key )
{
unset( $this ->configs[ $key ]);
}
}
|
以上就是PHP开发自己的框架,你必须知道这些知识点!的详细内容,更多请关注php中文网其它相关文章!
PHP开发自己的框架,你必须知道这些知识点!