能够更好地组织代码,与Java中的包相似。php
Test1.php <?php namespace Test1;//命名空间Test1 function test(){ echo __FILE__; } Test2.php <?php namespace Test2; //命名空间Test2 function test(){ echo __FILE__;//打印当前文件所在的绝对路径。 } Test.php <?php require 'Test1.php'; require 'Test2.php'; Test1\test();//经过这种方式,使用命名空间下的方法或者类。Test1表示命名空间,test()表示该命名空间下的一个方法。 echo "<br>"; Test2\test();
运行结果
总结:经过以上代码,能够看到,在不一样的命名空间下,能够有相同的类名或者方法名。html
随着PHP项目的变大,会致使一个PHP文件的前面有不少的require去包含各类依赖的PHP文件。若是某个类删除,可是在别的文件里有导入的状况,就会致使致命错误。解决以上问题的方法,就是__autoload()函数。mysql
Test1.php <?php class Test1{ static function test(){ echo __FILE__; } } Test2.php <?php class Test2 { static function test(){ echo __FILE__; } } Test.php <?php Test1::test(); Test2::test(); function __autoload($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; }
PHP就是用这段代码,去动态的载入须要包含的文件。当使用某个类,而这个类没有包含到文件中时,就会调用__autoload()函数,去动态的加载这个文件。可是,当使用多个框架时,每一个框架都会有本身的__autoload()实现,因此,会致使文件重复导入。redis
<?php function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; } function autoload2($class){ $dir = __DIR__; $requireFile = $dir."\\".$class.".php"; require $requireFile; } //将加载函数注册到PHP中 spl_autoload_register('autoload1'); spl_autoload_register('autoload2'); //将实现自动导入的函数,以字符串的形式传入该函数中,便可解决重复导入文件致使的错误问题。 Test1::test(); Test2::test();
单例模式解决的是如何在整个项目中建立惟一对象实例的问题,工厂模式解决的是如何不经过new创建实例对象的方法。算法
class Single { private $name;//声明一个私有的实例变量 private function __construct(){//声明私有构造方法为了防止外部代码使用new来建立对象。 } static public $instance;//声明一个静态变量(保存在类中惟一的一个实例) static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象 if(!self::$instance) self::$instance = new self(); return self::$instance; } public function setname($n){ $this->name = $n; } public function getname(){ return $this->name; } } $oa = Single::getinstance(); $ob = Single::getinstance(); $oa->setname('hello world'); $ob->setname('good morning'); echo $oa->getname();//good morning echo $ob->getname();//good morning
单例模式,使某个类的对象仅容许建立一个。构造函数private修饰,
申明一个static getInstance方法,在该方法里建立该对象的实例。若是该实例已经存在,则不建立。好比只须要建立一个数据库链接。sql
工厂模式,工厂方法或者类生成对象,而不是在代码中直接new。
使用工厂模式,能够避免当改变某个类的名字或者方法以后,在调用这个类的全部的代码中都修改它的名字或者参数。数据库
<?php header('Content-Type:text/html;charset=utf-8'); /** *简单工厂模式(静态工厂方法模式) */ /** * Interface people 人类 */ interface people { public function say(); } /** * Class man 继承people的男人类 */ class man implements people { // 具体实现people的say方法 public function say() { echo '我是男人<br>'; } } /** * Class women 继承people的女人类 */ class women implements people { // 具体实现people的say方法 public function say() { echo '我是女人<br>'; } } /** * Class SimpleFactoty 工厂类 */ class SimpleFactoty { // 简单工厂里的静态方法-用于建立男人对象 static function createMan() { return new man(); } // 简单工厂里的静态方法-用于建立女人对象 static function createWomen() { return new women(); } } /** * 具体调用 */ $man = SimpleFactoty::createMan(); $man->say(); $woman = SimpleFactoty::createWomen(); $woman->say();
注册模式,解决全局共享和交换对象。已经建立好的对象,挂在到某个全局可使用的数组上,在须要使用的时候,直接从该数组上获取便可。将对象注册到全局的树上。任何地方直接去访问。编程
<?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。
PHP中的数据库操做有MySQL,MySQLi,PDO三种,能够用适配器模式统一成一致,使不一样的数据库操做,统一成同样的API。相似的场景还有cache适配器,能够将memcache,redis,file,apc等不一样的缓存函数,统一成一致。
首先定义一个接口(有几个方法,以及相应的参数)。而后,有几种不一样的状况,就写几个类实现该接口。将完成类似功能的函数,统一成一致的方法。canvas
接口 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); } }
PDO <?php namespace IMooc\Database; use IMooc\IDatabase; class PDO implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd); $this->conn = $conn; } function query($sql) { return $this->conn->query($sql); } function close() { unset($this->conn); } }
经过以上案例,PHP与MySQL的数据库交互有三套API,在不一样的场景下可能使用不一样的API,那么开发好的代码,换一个环境,可能就要改变它的数据库API,那么就要改写全部的代码,使用适配器模式以后,就可使用统一的API去屏蔽底层的API差别带来的环境改变以后须要改写代码的问题。数组
策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。
eg:假若有一个电商网站系统,针对男性女性用户要各自跳转到不一样的商品类目,而且全部的广告位展现不一样的广告。在传统的代码中,都是在系统中加入各类if else的判断,硬编码的方式。若是有一天增长了一种用户,就须要改写代码。使用策略模式,若是新增长一种用户类型,只须要增长一种策略就能够。其余全部的地方只须要使用不一样的策略就能够。
首先声明策略的接口文件,约定了策略的包含的行为。而后,定义各个具体的策略实现类。
UserStrategy.php <?php /* * 声明策略文件的接口,约定策略包含的行为。 */ interface UserStrategy { function showAd(); function showCategory(); }
FemaleUser.php <?php require_once 'Loader.php'; class FemaleUser implements UserStrategy { function showAd(){ echo "2016冬季女装"; } function showCategory(){ echo "女装"; } }
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();
执行结果图:
总结:
经过以上方式,能够发现,在不一样用户登陆时显示不一样的内容,可是解决了在显示时的硬编码的问题。若是要增长一种策略,只须要增长一种策略实现类,而后在入口文件中执行判断,传入这个类便可。实现了解耦。
实现依赖倒置和控制反转 (有待理解)
经过接口的方式,使得类和类之间不直接依赖。在使用该类的时候,才动态的传入该接口的一个实现类。若是要替换某个类,只须要提供一个实现了该接口的实现类,经过修改一行代码便可完成替换。
1:观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象所有会收到通知,并自动更新。
2:场景:一个事件发生后,要执行一连串更新操做。传统的编程方式,就是在事件的代码以后直接加入处理的逻辑。当更新的逻辑增多以后,代码会变得难以维护。这种方式是耦合的,侵入式的,增长新的逻辑须要修改事件的主体代码。
3:观察者模式实现了低耦合,非侵入式的通知与更新机制。
定义一个事件触发抽象类。
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();//这里就是在事件发生后要执行的逻辑 }
<?php //一个实现了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:与工厂模式的实现不一样,原型模式是先建立好一个原型对象,而后经过clone原型对象来建立新的对象。这样就免去了类建立时重复的初始化操做。
3:原型模式适用于大对象的建立,建立一个大对象须要很大的开销,若是每次new就会消耗很大,原型模式仅须要内存拷贝便可。
Canvas.php <?php require_once 'Loader.php'; class Canvas{ private $data; function init($width = 20, $height = 10) { $data = array(); for($i = 0; $i < $height; $i++) { for($j = 0; $j < $width; $j++) { $data[$i][$j] = '*'; } } $this->data = $data; } function rect($x1, $y1, $x2, $y2) { foreach($this->data as $k1 => $line) { if ($x1 > $k1 or $x2 < $k1) continue; foreach($line as $k2 => $char) { if ($y1>$k2 or $y2<$k2) continue; $this->data[$k1][$k2] = '#'; } } } function draw(){ foreach ($this->data as $line){ foreach ($line as $char){ echo $char; } echo "<br>;"; } } }
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();
执行结果:
1:装饰器模式,能够动态的添加修改类的功能 2:一个类提供了一项功能,若是要在修改并添加额外的功能,传统的编程模式,须要写一个子类继承它,并重写实现类的方法 3:使用装饰器模式,仅须要在运行时添加一个装饰器对象便可实现,能够实现最大额灵活性。