phpms框架源码 https://github.com/wuxiumu/ms
一、PHP常用的四种数据结构
简介:spl是php的一个标准库。
官方文档:http://php.net/manual/zh/book...
push('data1');//入栈(先进后出)
$stack->push('data2');//入栈
$stack->push('data3');//入栈
echo $stack->pop().PHP_EOL;//出栈
echo $stack->pop().PHP_EOL;//出栈
echo $stack->pop().PHP_EOL;//出栈
}
/**
*队列(先进先出)
*/
function duilie(){
$queue = new SplQueue();
$queue->enqueue('data4');//入队列
$queue->enqueue('data5');//入队列
$queue->enqueue('data6');//入队列
echo $queue->dequeue().PHP_EOL;//出队列
echo $queue->dequeue().PHP_EOL;//出队列
echo $queue->dequeue().PHP_EOL;//出队列
}
/**
* 堆
*/
function dui(){
$heap = new SplMinHeap();
$heap->insert('data8');//入堆
$heap->insert('data9');//入堆
$heap->insert('data10');//入堆
echo $heap->extract().PHP_EOL;//从堆中提取数据
echo $heap->extract().PHP_EOL;//从堆中提取数据
echo $heap->extract().PHP_EOL;//从堆中提取数据
}
/**
* 固定数组(不论使不使用,都会分配相应的内存空间)
*/
$array = new SplFixedArray(15);
$array['0'] = 54;
$array['6'] = 69;
$array['10'] = 32;
var_dump($array);
二、PHP链式操作的实现(原理)
1、入口文件
index.php
header("content-type:text/html;charset=utf-8");
define('PHPMSFRAME',__DIR__);
define('CORE',PHPMSFRAME.'/core');
define('APP',PHPMSFRAME.'/app');
define('MODULE','app');
define('DEBUG',true);
include "vendor/autoload.php";
if(DEBUG){
$whoops = new \Whoops\Run;
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
$whoops->register();
ini_set('display_error', 'On');
}else{
ini_set('display_error', 'Off');
}
include CORE.'/common/function.php';
include CORE.'/phpmsframe.php';
spl_autoload_register('\core\phpmsframe::load');
\core\phpmsframe::run();
2、自动加载类
corephpmsframe.php
ctrl;
$action = $route->action;
$ctrlfile = APP.'/ctrl/'.$ctrlClass.'Ctrl.php';
$ctrlClass = '\\'.MODULE.'\ctrl\\'.$ctrlClass.'Ctrl';
if(is_file($ctrlfile)){
include $ctrlfile;
$ctrl = new $ctrlClass();
$ctrl->$action();
}else{
$msg = "控制器 $ctrlClass 不存在\n";
self::reportingDog($msg);
}
}
static public function load($class)
{
if(isset($classMap[$class])){
return true;
}else{
$class = str_replace('\\', '/', $class);
$file = PHPMSFRAME.'/'.$class.'.php';
if(is_file($file)){
include $file;
self::$classMap[$class] = $class;
}else{
return false;
}
}
}
public function assign($name,$value){
$this->assign[$name]=$value;
}
public function display($file){
$file_path = APP.'/views/'.$file;
if(is_file($file_path)){
/***********twig模板***********/
$loader = new \Twig_Loader_Filesystem(APP.'/views');
$twig = new \Twig_Environment($loader, array(
'cache' => PHPMSFRAME.'/cache',
'debug'=>DEBUG,
));
$template = $twig->load($file);
$template->display($this->assign?$this->assign:'');
/***********twig模板end***********/
/***********原生模板***********/
//extract($this->assign);
//include $file_path;
/***********原生模板end***********/
}
}
static private function reportingDog($msg){
echo $msg."\n";
include 'smile/havefun.php';
$num = str_pad(rand(00,32),2,"0",STR_PAD_LEFT);
$num = "str_".$num;
$Parsedown = new \Parsedown();
echo $Parsedown->text($$num);
$num = "str_".rand(50,84);
echo $Parsedown->text($$num);
exit;
}
}
3、数据库类
注:只是原理,并没有对方法进行具体的封装,具体的封装还是看个人喜好去定链式查询的风格。
corelibmodel.php
corelibdrivedatabasemedooModel.php
三、PHP魔术方法的使用
在php设计模式中,会涉及到很多魔术方法的使用,这里也对经常会用到的魔术方法进行简单总结。
1、框架入口文件
corephpmsframe.php
/**
* 魔术方法的使用
*/
/* 这是一个魔术方法,当一个对象或者类获取其不存在的属性的值时,
* 如:$obj = new BaseController ;
* $a = $obj -> a ;
* 该方法会被自动调用,这样做很友好,可以避免系统报错
*/
public function __get($property_name){
$msg = "属性 $property_name 不存在\n";
self::reportingDog($msg);
}
/* 这是一个魔术方法,当一个对象或者类给其不存在的属性赋值时,
* 如:$obj = new BaseController ;
* $obj -> a = 12 ;
* 该方法(__set(属性名,属性值))会被自动调用,这样做很友好,可以避免系统报错
*/
public function __set($property_name,$value){
$msg = "属性 $property_name 不存在\n";
self::reportingDog($msg);
}
/* 这是一个魔术方法,当一个对象或者类的不存在属性进行isset()时,
* 注意:isset 用于检查一个量是否被赋值 如果为NULL会返回false
* 如:$obj = new BaseController ;
* isset($obj -> a) ;
* 该方法会被自动调用,这样做很友好,可以避免系统报错
*/
public function __isset($property_name){
$msg = "属性 $property_name 不存在\n";
self::reportingDog($msg);
}
/* 这是一个魔术方法,当一个对象或者类的不存在属性进行unset()时,
* 注意:unset 用于释放一个变量所分配的内存空间
* 如:$obj = new BaseController ;
* unset($obj -> a) ;
* 该方法会被自动调用,这样做很友好,可以避免系统报错
*/
public function __unset($property_name){
$msg = "属性 $property_name 不存在\n";
self::reportingDog($msg);
}
/* 当对这个类的对象的不存在的实例方法进行“调用”时,会自动调用该方法,
* 这个方法有2个参数(必须带有的):
* $methodName 表示要调用的不存在的方法名;
* $argument 是一个数组,表示要调用该不存在的方法时,所使用的实参数据,
*/
public function __call($methodName,$argument){
$msg = "实例方法 $methodName 不存在\n";
self::reportingDog($msg);
}
四、三种基础设计模式
1、工厂模式
通过传入参数的不同,来实例化不同的类。
$cache =\Core\extend\CacheFactory::getCacheObj('redis',array(
'host' => '127.0.0.1',
'pass' => 'myRedis&&&'
));
var_dump($cache);
coreextendCacheFactory.php
2、单例模式
保证一个类只实例化一个类对象,进而减少系统开销和资源的浪费
//单例模式创建对象
$obj = Extend\SingleObject::getInstance();
$obj2 = Extend\SingleObject::getInstance();
var_dump($obj,$obj2);//从结果可以看出,两个实例化的对象其实是一个对象
coreextendSingleObject.php
3、注册树模式
将我们用到的对象注册到注册树上,然后在之后要用到这个对象的时候,直接从注册树上取下来就好。(就和我们用全局变量一样方便)
coreextendRegisterTree,php
关于注册树模式,这里推荐一篇文章 ,可以方便理解。 https://segmentfault.com/a/11...
五、其他常见的8种PHP设计模式
1、适配器模式
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
常见的有两种适配器,分别是类适配器和对象适配器,这里拿更看好的对象适配器举例:
";
}
}
/**
* 类适配器角色(新定义接口的具体实现)
* Class Adapter
* @package Extend
*/
class Adapter implements Target
{
private $adaptee;
function __construct()
{
//适配器初始化直接new 原功能类,以方便之后委派
$adaptee = new Adaptee();
$this->adaptee = $adaptee;
}
//委派调用Adaptee的sampleMethod1方法
public function simpleMethod1()
{
echo $this->adaptee->simpleMethod1();
}
public function simpleMethod2()
{
echo 'Adapter simpleMethod2'."
";
}
}
/**
* 客户端调用
*/
$adapter = new Adapter();
$adapter->simpleMethod1();
$adapter->simpleMethod2();
这篇文章介绍了类适配器的使用,感兴趣的可以了解一下 https://segmentfault.com/a/11...
2、策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式,策略模式可以实现依赖倒置以及控制反转。
实例举例:假如一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示展示不同的广告。
userType->showAd();
echo "Category:";
$this->userType->showCategory();
}
/**
* 策略模式
* 根据传递的用户性别展示不同类别数据
* @param \Extend\UserType $userType
*/
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(定义的接口)
MaleUserType.php、FemaleUserType.php(具体实现的类 )
3、数据对象映射模式
将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作。
下面在代码中实现数据对象映射模式,我们将实现一个ORM类,将复杂的sql语句映射成对象属性的操作。并结合使用数据对象映射模式、工厂模式、注册模式。
(1)数据库映射模式简单实例实现
name = '小卜丢饭团子';
$user->salary = '20000';
$user->city = '浙江省';
Extend/User.php
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)数据库映射模式复杂案例实现
name = '小卜丢饭团子';
$user->salary = '20000';
$user->city = '浙江省';
}
function test()
{
$user = Extend\Factory::getUserObj(25);
$user->city = '广东省';
}
}
$ex = new EX();
$ex->index();
Extend/Factory.php
Extend/Register.php
Extend/User.php
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、传统模式举例:
";
//传统方式是在发生一个事件之后直接进行一系列的相关处理,耦合度比较高,比如写入日志,给用户发邮件等等
echo "在用户下单之后进行的一系列操作
";
}
}
$event = new Event();
$event->firmOrder();
4.2、观察者模式典型实现方式:
(1)定义2个接口:观察者(通知)接口、被观察者(主题)接口
(2)定义2个类,观察者类实现观察者接口、被观察者类实现被观察者接口
(3)被观察者注册自己需要通知的观察者
(4)被观察者类某个业务逻辑发生时,通知观察者对象,进而每个观察者执行自己的业务逻辑。
代码示例:
observers[] = $observer;
}
/**
* 购票主体方法
* BuyTicket constructor.
* @param $ticket 购票排号
*/
public function buyTicket($ticket)
{
//1、根据需求写购票逻辑
//..............
//2、购票成功之后,循环通知观察者,并调用其buyTicketOver实现不同业务逻辑
foreach ($this->observers as $observe) {
$observe->buyTicketOver($this, $ticket); //$this 可用来获取主题类句柄,在通知中使用
}
}
}
/**
* 购票成功后,发送短信通知
* Class buyTicketMSN
*/
class buyTicketMSN implements TicketObserver
{
public function buyTicketOver($sender, $ticket)
{
echo (date ( 'Y-m-d H:i:s' ) . " 短信日志记录:购票成功:$ticket
");
}
}
/**
* 购票成功后,记录日志
* Class buyTicketLog
*/
class buyTicketLog implements TicketObserver
{
public function buyTicketOver($sender, $ticket)
{
echo (date ( 'Y-m-d H:i:s' ) . " 文本日志记录:购票成功:$ticket
");
}
}
/**
* 购票成功后,赠送优惠券
* Class buyTicketCoupon
*/
class buyTicketCoupon implements TicketObserver
{
public function buyTicketOver($sender, $ticket)
{
echo (date ( 'Y-m-d H:i:s' ) . " 赠送优惠券:购票成功:$ticket 赠送10元优惠券1张。
");
}
}
//实例化购票类
$buy = new BuyTicket();
//添加多个观察者
$buy->addObserver(new buyTicketMSN());
$buy->addObserver(new buyTicketLog());
$buy->addObserver(new buyTicketCoupon());
//开始购票
$buy->buyTicket ("7排8号");
5、原型模式
原型模式与工厂模式的作用类似,都是用来创建对象的。但是实现方式是不同的。原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样,就免去了类创建时重复的初始化操作。
原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
代码实例:
_name = $name;
}
public function setName($name)
{
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
public function copy()
{
//深拷贝实现
//$serialize_obj = serialize($this); // 序列化
//$clone_obj = unserialize($serialize_obj); // 反序列化
//return $clone_obj;
// 浅拷贝实现
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 '
';
var_dump($object2->getName());
echo '
';
$demo->array = array(3, 4);
var_dump($object1->getName());
echo '
';
var_dump($object2->getName());
echo '
';
关于原型模式文章:https://www.imooc.com/article...
6、装饰器模式
可以动态的添加或修改类的功能
一个类实现一个功能,如果要再修改或添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法。
使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性。
color = $color;
}
public function beforeEcho()
{
echo "";
}
public function afterEcho()
{
echo "