PHP – 设计模式


在软件工程理论中,术语“设计模式”通常是指一种可重用的解决方案,它可以用作开发应用程序以解决常见问题的模板。在开发软件解决方案时,您可以将软件设计模式视为正式的最佳实践。

大多数标准设计模式都可以在 PHP 中开发应用程序时非常有效地实现。在本章中,我们将学习如何在开发 PHP 应用程序时应用一些流行的设计模式。

单例模式 (Singleton Pattern)

当您希望将某个类的对象的实例化限制为仅一个实例时,单例设计模式非常有用。“单例模式”这个名字来源于数学中单例的概念。单例模式确保只有一个实例,在整个应用程序中具有对该实例的全局访问权限。

单例模式的典型应用是创建数据库连接对象,该对象必须在应用程序的生命周期中创建一次。

例子

在下面的代码中,DataBaseConnector 类只能实例化一次,否则将发出不允许重复对象的消息。


<?php
   class DataBaseConnector {                
      private static $obj;                
      private final function __construct() {
         echo __CLASS__ . " object created for first time ". PHP_EOL;
      }
      public static function getConnect() {
         if (!isset(self::$obj)) {
            self::$obj = new DataBaseConnector();
            return self::$obj;
         } else {
            echo "connection object could not be created again" . PHP_EOL;
         }
      }
   }

   $obj1 = DataBaseConnector::getConnect();
   $obj2 = DataBaseConnector::getConnect();

   var_dump($obj1 == $obj2);
?>

它将产生以下输出 -

DataBaseConnector object created for first time 
connection object could not be created again
bool(false)

工厂模式 (Factory Pattern)

这是最常用的设计模式之一。在此模式中,您不直接声明所需类的对象,而是提供另一个类,其 static 方法创建所需的对象。

以下示例演示了工厂设计模式的工作原理 -


<?php
   class Automobile {
      private $bikeMake;
      private $bikeModel;

      public function __construct($make, $model) {
         $this->bikeMake = $make;
         $this->bikeModel = $model;
      }

      public function getMakeAndModel() {
         return $this->bikeMake . ' ' . $this->bikeModel;
      }
   }

   class AutomobileFactory {
      public static function create($make, $model) {
         return new Automobile($make, $model);
      }
   }

   $pulsar = AutomobileFactory::create('ktm', 'Pulsar');
   print_r($pulsar->getMakeAndModel());
?>

它将产生以下输出 -

ktm Pulsar

策略模式 (Strategy Pattern)

策略模式推荐一种方法,其中封装特定的算法系列,允许负责实例化特定算法的 Client 端类。实现该模式的类不知道实际的实现。

下面是一个演示策略模式使用的代码。我们有一个接口,它的 case() 方法由两个不同的类以不同的方式实现。testdata 类的对象通过其自己的 process() 方法间接调用相应的 case() 方法。


<?php
   interface example {
      public function case($str);
   }

   class ucase implements example {
      public function case($str) {
         return strtoupper($str);
      } 
   }

   class lcase implements example {
      public function case($str) {
         return strtolower($str);
      }
   }

   class testdata {
      private $data;

      public function __construct($input) {
         $this->data = $input;
      }
      public function process(example $type) {
         return $this->data = $type->case($this->data);
      }
   }
   $str = "hello";
   $obj = new testdata($str);
   echo $obj->process(new ucase) . PHP_EOL;  
   $str = "HELLO";
   echo $obj->process(new lcase);
?>

它将产生以下输出 -

HELLO
Hello

MVC 设计模式 (MVC Design Pattern)

MVC 代表 Model、View 和 Controller,是一种非常流行的软件架构模式。大多数 PHP 网络(如 Laravel、Symfony 等)都实现了 MVC 架构。

应用程序中每一层的角色分离如下 -

  • Model - 指数据结构。在本例中,数据库。
  • View  − 指用户界面。HTML 和 CSS.
  • Controller - 执行处理的“中间人”。接受来自视图的输入,并与模型一起使用。不言自明的是,PHP 脚本和库本身。

View 充当 GUI,Model 充当后端,Control 充当适配器。在这里,三个部分相互关联。它将传递数据并在彼此之间访问数据。

例子

在下面的示例中,让我们用纯 PHP、JavaScript 和 HTML 实现 MVC 设计模式 -

应用程序的表示层是 view.php,它呈现 HTML 表单。用户将数据提交到控制器脚本。控制器返回的结果在网页上呈现,并带有一点 JavaScript

view.php  


<!DOCTYPE html>
<html>
<head>
   <title>View (User Interface)</title>
   <link rel="stylesheet" href="style.css">
</head>
<body>
   <form id="mysearch" action="controller.php" method="POST">
      <input type="text" id = "nm" name="search" required>
      <input type="submit" value="Search">
   </form>
   <div id="results"></div>
   <script>
      let results = document.getElementById("results");
      results.innerHTML = "";
   </script>
   <?php
      session_start();
      if (isset($_SESSION['result'])) {
         $arr=$_SESSION['result'];

         foreach ($arr as $obj) {?>
            <script>
               results.innerHTML += "<div><?php echo $obj['id'] . "-" . 
                  $obj['name'] . "</div>"; ?>";
            </script>
            <?php
         }
      }
   ?>
</body>
</html>

控制器脚本需要 model.php,并使用数据库对象调用 select 方法从数据库中获取数据。结果存储在当前会话中,以便可以在视图页面上访问它。

controller.php


<?php
   session_start();
   require "model.php";
   $results = $_DB->select(
      "SELECT * FROM `users` WHERE `name` LIKE ?",
      ["%{$_POST["search"]}%"]
   );
   $_SESSION['search'] = $_POST['search'];
   $_SESSION['result'] = $results;
   Header("Location: view.php", true);
?>

应用程序的模型层以 “model.php” 编码。它使用 PDO 扩展与名为 mydb 的 mysql 数据库建立连接。

model.php


<?php
   class DB {
      public $error = "";
      private $pdo = null;
      private $stmt = null;
      var $dsn="localhost";  
      var $dbName="myDB";  
      var $username="root";       
      var $password=""; 
      function __construct () {
         $this->pdo = new PDO("mysql:host=$this->dsn;dbname=$this->
            dbName",$this->username,$this->password); 
      }
      function __destruct () {
         if ($this->stmt!==null) { $this->stmt = null; }
         if ($this->pdo!==null) { $this->pdo = null; }
      }
      function select ($sql, $data=null) {
         $this->stmt = $this->pdo->prepare($sql);
         $this->stmt->execute($data); 
         return $this->stmt->fetchAll();
      }
   }
   $_DB = new DB();
?>

后端 mydb 数据库必须具有具有 ID NAME 字段的 users 表。


-- Table structure for table `users`
--
CREATE TABLE `users` (
   `id` bigint(20) NOT NULL,
   `name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

--
-- Dumping data for table `users`
--
INSERT INTO `users` (`id`, `name`) VALUES
(21, 'Ahmad Shaikh'),
(24, 'Akshay Wadkar'),
(26, 'Bridget Wooten'),
(10, 'Coby Kelleigh'),
(20, 'Dashan Shah'),
(12, 'Elizabeth Taylor'),
(41, 'Issac Newton'),
(34, 'Julia Roberts'),
(31, 'Junior Mahmood'),
(32, 'Kailas Bende'),
(47, 'Karan Sharma'),
(16, 'Kenneth Sanders'),
(28, 'Kirstie Thomas'),
(33, 'Lawrence Murphy'),
(14, 'Leah Shan'),
(51, 'Marcus Best'),
(29, 'Maya Pande'),
(50, 'Nathaniel Khan'),
(6, 'Richard Breann'),
(54, 'Rowan Avalos'),
(3, 'Rusty Terry'),
(37, 'Sacha Gross'),
(27, 'Sally Castillo'),
(11, 'Sarah Sanders'),
(18, 'Seth Sonnel'),
(38, 'Shannon Peterson'),
(25, 'Shayan Clements'),
(49, 'Shoaib Vickers'),
(43, 'Simran Kaur'),
(35, 'Sulaiman Gilmour'),
(44, 'Taran Morin'),
(48, 'Taran Morin'),
(22, 'Thelma Kim'),
(8, 'Tillie Sharalyn'),
(36, 'Virgil Collier');

通过访问浏览器中的“http://localhost/view.php”来启动应用程序。输入与具有所需字母的名称相对应的搜索词。

PHP Design Patterns