Home > Article > Backend Development > Several common development patterns in PHP
This article brings you relevant knowledge about PHP, which mainly introduces several common development models. Let’s take a look at them together. I hope it will be helpful to everyone.
Six Principles of Design Patterns
Open and Closed Principle: A software entity such as a class, module, and function should be open to extension and closed to modification .
Richter Substitution Principle: All places that reference a base class must be able to transparently use objects of its subclasses.
Dependency Inversion Principle: High-level modules should not depend on low-level modules, both should Depend on its abstraction; abstractions should not depend on details; details should depend on abstractions.
Single Responsibility Principle: Do not have more than one reason for class changes. In layman's terms, a class is only responsible for one responsibility.
Interface isolation principle: The client should not rely on interfaces it does not need; the dependence of one class on another class should be based on the smallest interface.
Demeter's Law: An object should keep the least knowledge about other objects.
Features: Using singleton mode, you can avoid a large number of resources consumed by new operations
Single case class It cannot be created directly by instantiation, but can only be instantiated by the class itself. Therefore, to obtain such a restrictive effect, the constructor must be marked private, thus preventing the class from being instantiated.
Need a private static member variable to save the class instance and expose a public static method that can access the instance.
In PHP, in order to prevent others from cloning singleton class instances, an empty private __clone() method is usually provided for it.
$_instance must be declared as a static private variable
The constructor and destructor must be declared as private to prevent external programs from creating new classes. Losing the meaning of the singleton mode
The getInstance() method must be set to public, and this method must be called to return a reference to the instance
::Operator can only access static variables and static functions
new objects will consume memory
Usage scenarios: The most commonly used place is the database connect.
After using the singleton pattern to generate an object, the object can be used by many other objects.
Private __clone() method prevents cloning objects
<?php class Singleton{ //私有属性,用于保存实例 private static $instance; //构造方法私有化,防止外部创建实例 private function __construct(){}//公有方法,用于获取实例 public static function getInstance(){ //判断实例有无创建,没有的话创建实例并返回,有的话直接返回 if(!(self::$instance instanceof self)){ self::$instance = new self(); } return self::$instance; } //克隆方法私有化,防止复制实例 private function __clone(){}}
Factory mode, factory method Or the class generates the object instead of new directly in the code.
Use method new to instantiate a class. Each instantiation only requires calling the method in the factory class to instantiate.
Advantages: Since a class may be instantiated in many places. When the class name or parameters change, the factory mode can be easily and quickly modified once in the method under the factory class, avoiding the need to modify the instantiated objects one by one
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; }} Test1.php <?php class Test1 { protected static tt) { echo "对象已经创建<br>"; return self::tt = new Test1(); echo "创建对象<br>"; return self::$tt; } }function echoHello() { echo "Hello<br>"; }} Test.php <?php spl_autoload_register('autoload1'); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello(); $test = Test1::getInstance(); $test->echoHello();function autoload1($class) { $dir = __DIR__; $requireFile = $dir."\".$class.".php"; require $requireFile; }}
For example, assuming that rectangles and circles have the same method, then when we use the API provided by the base class to create an instance, we will automatically create an instance of the corresponding class by passing parameters. They all have the perimeter and Area functions
<?php interface InterfaceShape { function getArea(); function getCircumference(); }/** • 矩形 */ class Rectangle implements InterfaceShape { private $width; private $height; public function __construct($width, $height) { $this->width = $width; $this->height = $height; } public function getArea() { return $this->width* $this->height; } public function getCircumference() { return 2 * $this->width + 2 * $this->height; } }/** • 圆形 */ class Circle implements InterfaceShape { private $radius; function __construct($radius) { $this->radius = $radius; } public function getArea() { return M_PI * pow($this->radius, 2); } public function getCircumference() { return 2 * M_PI * $this->radius; } }/** • 形状工厂类 */ class FactoryShape { public static function create() { switch (func_num_args()) { case1: return newCircle(func_get_arg(0)); case2: return newRectangle(func_get_arg(0), func_get_arg(1)); default: # code... break; } } }rect); echo "<br>";// object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) } circle);
Registration mode solves global sharing and exchange objects. The created object is hung on a globally usable array. When needed, it can be obtained directly from the array. Register the object in the global tree. Go directly to visit anywhere.
<?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]);//移除某个注册到树上的对象。 }}
The strategy pattern encapsulates a specific set of behaviors and algorithms into classes to adapt to certain specific contexts.
eg: If there is an e-commerce website system, male and female users need to jump to different product categories, and all advertising slots display different ads. In traditional codes, various if else judgments are added to the system in a hard-coded manner. If one day a user is added, the code needs to be rewritten. Using the policy mode, if you add a new user type, you only need to add a policy. Everything else just requires a different strategy.
First declare the interface file of the strategy and stipulate the included behavior of the strategy. Then, define each specific strategy implementation class.
UserStrategy.php
<?php /*• 声明策略文件的接口,约定策略包含的行为 */interface UserStrategy { function showAd(); function showCategory(); }FemaleUser.php <?phprequire_once 'Loader.php'; class FemaleUser implements UserStrategy { function showAd() { echo "2016冬季女装"; }function showCategory(){ echo "女装"; }} MaleUser.php <?phprequire_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(); }strategy); $page->index();
Summary:
Through the above method, you can find that different content is displayed when different users log in, but the problem of hard coding during display is solved. If you want to add a strategy, you only need to add a strategy implementation class, then perform judgment in the entry file and pass in this class. Achieve decoupling. Implement dependency inversion and control inversion (to be understood); through interfaces, there is no direct dependence between classes. When using this class, an implementation class of the interface is dynamically passed in. If you want to replace a class, you only need to provide an implementation class that implements the interface, and the replacement can be completed by modifying one line of code.
观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新(一个对象通过提供方法允许另一个对象即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者)
场景1:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。
场景2: 用户登录,需要写日志,送积分,参与活动等;使用消息队列,把用户和日志,积分,活动之间解耦合
观察者模式实现了低耦合,非侵入式的通知与更新机制。
<?php /* 观察者接口 */ interface InterfaceObserver { function onListen($sender, $args); function getObserverName(); }// 可被观察者接口 interface InterfaceObservable { function addObserver(observer_name); }// 观察者抽象类 abstract class Observer implements InterfaceObserver { protected $observer_name;function getObserverName() { return $this->observer_name; }function onListen($sender, $args) {} }// 可被观察类 abstract class Observable implements InterfaceObservable { protected $observers = array();public function addObserver(observerinstanceofInterfaceObserver) { $this->observers[] = $observer; } }public function removeObserver(this->observersas $index => observer->getObserverName() === this->observers, $index, 1); return; } } } }// 模拟一个可以被观察的类 class A extends Observable { public function addListener(this->observersas $observer) { this, $listener); } } }// 模拟一个观察者类 class B extends Observer { protected $observer_name = 'B';public function onListen($sender, sender); echo "<br>"; var_dump($args); echo "<br>"; } }// 模拟另外一个观察者类 class C extends Observer { protected $observer_name = 'C';public function onListen($sender, sender); echo "<br>"; var_dump($args); echo "<br>"; } }a->addObserver(new B()); $a->addObserver(new C());// 可以看到观察到的信息 $a->addListener('D');// 移除观察者 $a->removeObserver('B');// 打印的信息: // object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } } // string(1) "D" // object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } } // string(1) "D"
装饰器模式, 根据运行时不同的情景动态地为某个对象调用前后添加不同的行
一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重写实现类的方法,使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大额灵活性
场景:
1.symfony 控制器中beforepost afterpost 中post提交前和提交后,对数据处理
2.当某一功能或方法draw,要满足不同的功能需求时,可以使用装饰器模式
/** • 输出一个字符串 • 装饰器动态添加功能 • Class EchoText */ class EchoText { protected $decorator = []; public function Index() { //调用装饰器前置操作 $this->beforeEcho(); echo "你好,我是装饰器。"; //调用装饰器后置操作 $this->afterEcho(); } //增加装饰器 public function addDecorator(Decorator $decorator) { $this->decorator[] = $decorator; } //执行装饰器前置操作 先进先出原则 protected function beforeEcho() { foreach ($this->decorator as $decorator) $decorator->before(); } //执行装饰器后置操作 先进后出原则 protected function afterEcho() { this->decorator); foreach ($tmp as $decorator) $decorator->after(); } }/** • 装饰器接口 • Class Decorator */ interface Decorator { public function before(); public function after(); }/** • 颜色装饰器实现 • Class ColorDecorator */ class ColorDecorator implements Decorator { protected $color; public function __construct($color) { $this->color = $color; } public function before() { echo "<dis style='color: {$this->color}'>"; } public function after() { echo "</div>"; } }/** • 字体大小装饰器实现 • Class SizeDecorator */ class SizeDecorator implements Decorator { protected $size; public function __construct($size) { $this->size = $size; } public function before() { echo "<dis style='font-size: {$this->size}px'>"; } public function after() { echo "</div>"; } }//实例化输出类 echo->addDecorator(new ColorDecorator('red')); //增加装饰器 echo->Index(); //输出<dis style='color: red'><dis style='font-size: 22px'>你好,我是装饰器。</div></div>
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。例如:php连接数据库的方法:mysql,,mysqli,pdo,可以用适配器统一
//老的代码 class User {private $name; function __construct($name) { $this->name = $name; } public function getName() { return $this->name; }} //新代码,开放平台标准接口 interface UserInterface { function getUserName(); }class UserInfo implements UserInterface { protected $user; function __construct($user) { $this->user = $user; } public function getUserName() { return $this->user->getName(); }} $olduser = new User('张三'); echo $olduser->getName()."n";olduser); echo $newuser->getUserName()."n";
推荐学习:《PHP视频教程》
The above is the detailed content of Several common development patterns in PHP. For more information, please follow other related articles on the PHP Chinese website!