博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
我设计一个phpms框架前的准备
阅读量:6973 次
发布时间:2019-06-27

本文共 19359 字,大约阅读时间需要 64 分钟。

phpms框架源码

一、PHP常用的四种数据结构

简介:spl是php的一个标准库。

官方文档:

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

关于注册树模式,这里推荐一篇文章 ,可以方便理解。

五、其他常见的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();

这篇文章介绍了类适配器的使用,感兴趣的可以了解一下

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 '
';

关于原型模式文章:

6、装饰器模式

可以动态的添加或修改类的功能

一个类实现一个功能,如果要再修改或添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法。

使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性。

color = $color; } public function beforeEcho() { echo "
"; } public function afterEcho() { echo ""; }} /** * 字体大小装饰器实现 * Class SizeDecorator */class SizeDecorator implements Decorator{ protected $size; public function __construct($size) { $this->size = $size; } public function beforeEcho() { echo "
"; } public function afterEcho() { echo ""; }} /** * 被装饰者 * 输出一个字符串 * 装饰器动态添加功能 * Class EchoText */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迭代器模式的定义。

相对于传统编程模式,迭代器模式可以隐藏遍历元素的所需的操作。

Extend/AllUser.php

pdo = new \PDO('mysql:host=127.0.0.1;dbname=test','root','123456'); //获取所有用户的id $this->ids = $this->pdo->query("select id from user")->fetchAll(2); } /** * 实现接口方法,重置迭代器,回到集合开头 */ public function rewind() { $this->index = 0; } /** * 实现接口方法,获取当前元素 * @return mixed|void */ 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; } /** * 实现接口方法,获取当前元素键值 * @return mixed|void */ public function key() { return $this->index; } /** * 实现接口方法,获取下一个元素 */ public function next() { $this->index++; } /** * 实现接口方法,验证是否还有下一个元素 * @return bool|void */ public function valid() { return $this->index < count($this->ids); } }

关于php迭代器文章 

 

8、代理模式

在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节。

典型的应用就是mysql的主从结构,读写分离。在mysql中,对所有读的操作请求从库,所有写的操作请求主库。

声明一个代理类,前台使用时只需创建一个代理类,调用对应方法即可。代码实例:

query("select * from user where id = 1 limit 1");#增删改操作使用主库//$db_master = Extend\Factory::getDatabase('master');//$db_master->query("update user name = 'xiaobudiu' where id = 29 limit 1"); // 2、使用代理模式$db_proxy = new Extend\Proxy();$db_proxy->getUserName(1);$db_proxy->setUserName(29,'xiaobudiu');

Extend/Proxy.php

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

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

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

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

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;

关于php代理模式文章

五、其余设计模式以及总结

文章接:

 

六、面向对象编程的基本原则

1、单一职责原则:一个类只需要做好一件事情。不要使用一个类完成很多功能,而应该拆分成更多更小的类。

2、开放封闭原则:一个类写好之后,应该是可扩展而不可修改的。

3、依赖倒置原则:一个类不应该强依赖另外一个类,每个类对于另外一个类都是可替换的。

4、配置化原则:尽量使用配置,而不是硬编码。

5、面向接口编程原则:只需要关心某个类提供了哪些接口,而不需要关心他的实现。

 

七、自动加载配置类文件

1、php中使用ArrayAccess实现配置文件的加载(使得程序可以以数组的方式进行读取配置)

(1)定义Config.php,继承php自带的ArrayAccess接口,并实现相应的方法,用于读取和设置配置

Extend/Config.php

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

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)读取配置

到此,就可以在程序中随心所欲的加载配置文件了。

2、在工厂方法中读取配置,生成可配置化的对象

Extend/Factory.php

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

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

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]); }}

转载地址:http://ldrsl.baihongyu.com/

你可能感兴趣的文章
您的Docker 容器还健康吗?一条简单命令帮您找出答案 [转载]
查看>>
WPF自定义控件与样式(14)-轻量MVVM模式实践
查看>>
HDD-FAT32 ZIP-FAT32
查看>>
当iPhone用上联发科,你还会爱上它吗?
查看>>
HDOJ(HDU) 1491 Octorber 21st
查看>>
ThinkPhp学习05
查看>>
Tomcat内核之ASCII解码的表驱动模式
查看>>
isual Studio 2013编译ImageMagick---转
查看>>
消息字节——MessageBytes
查看>>
送上最新鲜的互联网行业新闻-【2015-05-08】
查看>>
iOS Swift _Nullable 与 Android 注解帮助编译时检查 - 两家好像步调开始一致一段时间了...
查看>>
OpenCL异构计算资料收集
查看>>
Linux下按照时间和大小生成新文件的程序流程及其C代码实现
查看>>
MySQL数据库移植总结
查看>>
DockOne微信分享(一三零):探究PaaS网络模型设计
查看>>
控制并发访问的三道屏障: WCF限流(Throttling)体系探秘[下篇]
查看>>
移动WEB前端开发资源整合
查看>>
[WCF REST] 解决资源并发修改的一个有效的手段:条件更新(Conditional Update)
查看>>
加密技术 加强数据私密性确保云计算安全
查看>>
老司机教你一步步删掉艳照
查看>>