搜尋
首頁後端開發php教程常見的PHP設計模式分享

常見的PHP設計模式分享

Mar 09, 2018 pm 05:23 PM
php分享設計模式

設計模式 一書將設計模式引入軟體社區,該書的作者是 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides Design(俗稱 “四人幫”)。所介紹的設計模式背後的核心概念非常簡單。經過多年的軟體開發實踐,Gamma 等人發現了某些具有固定設計的模式,就像建築師設計房子和建築物一樣,可以為浴室的位置或廚房的構造方式開發模板。使用這些模板或說設計模式 意味著可以更快地設計更好的建築物。同樣的概念也適用於軟體。

設計模式不僅代表著更快開發健壯軟體的有用方法,而且還提供了以友善的術語封裝大型理念的方法。例如,您可以說您正在編寫一個提供鬆散耦合的訊息傳遞系統,也可以說你正在編寫名稱為觀察者 的模式。

用較小的範例展示模式的價值是非常困難的。這往往有些大材小用的意味,因為模式實際上是在大型程式碼庫中發揮作用的。本文不展示大型應用程序,所以您需要思索的是在您自己的大型應用程式中應用範例原理的方法 —— 而不是本文演示的程式碼本身。這不是說您不應該在小應用程式中使用模式。許多好的應用程式都以小型應用程式為起點,逐漸發展到大型應用程序,所以沒有理由不以此類紮實的編碼實踐為基礎。

既然您已經了解了設計模式以及它們的有用之處,現在我們來看看 PHP V5 的五種常用模式。

工廠模式

最初在設計模式 一書中,許多設計模式都鼓勵使用鬆散耦合。要理解這個概念,讓我們最好先談談許多開發人員從事大型系統的艱苦歷程。在更改一個程式碼片段時,就會發生問題,系統其他部分 —— 您曾經認為完全不相關的部分中也有可能出現級聯破壞。

此問題在於緊密耦合 。系統某個部分中的函數和類別嚴重依賴系統的其他部分中函數和類別的行為和結構。您需要一組模式,使這些類別能夠相互通信,但不希望將它們緊密綁定在一起,以避免出現聯鎖。

在大型系統中,許多程式碼依賴少數幾個關鍵類別。需要更改這些類別時,可能會出現困難。例如,假設您有一個從文件讀取的 User 類別。您希望將其更改為從資料庫讀取的其他類,但是,所有的程式碼都引用從檔案讀取的原始類別。這時候,使用工廠模式會很方便。

工廠模式 是一種類,它具有為您建立物件的某些方法。您可以使用工廠類別建立對象,而不直接使用 new。這樣,如果您想要更改所建立的物件類型,只需更改該工廠即可。使用該工廠的所有代碼會自動變更。

清單 1 顯示工廠類別的一個示列。等式的伺服器端包括兩個部分:資料庫和一組 PHP 頁面,這些頁面可讓您新增回饋、請求回饋清單並取得與特定回饋相關的文章。

清單 1. Factory1.ph

#
<?php
interface
 IUser
{
  function
 getName();
}
 
class
 User implements IUser
{
  public
 function __construct( $id ) { }
 
  public
 function getName()
  {
    return
 "Jack";
  }
}
 
class
 UserFactory
{
  public
 static function Create( $id )
  {
    return
 new User( $id );
  }
}
 
$uo= UserFactory::Create(
 1 );
echo(
 $uo->getName()."\n" );
?>

IUser 介面定義使用者物件應執行什麼操作。 IUser 的實作稱為 User,UserFactory 工廠類別則建立 IUser物件。此關係可用圖 1 中的 UML 表示。

圖1. 工廠類別及其相關IUser 介面與使用者類別

工厂类及其相关 IUser 接口和用户类

#如果您使用 php 解釋器在命令列上執行此程式碼,將會得到如下結果:

#% php factory1.php

Jack

%

#


测试代码会向工厂请求 User 对象,并输出 getName 方法的结果。

有一种工厂模式的变体使用工厂方法。类中的这些公共静态方法构造该类型的对象。如果创建此类型的对象非常重要,此方法非常有用。例如,假设您需要先创建对象,然后设置许多属性。此版本的工厂模式会将该进程封装在单个位置中,这样,不用复制复杂的初始化代码,也不必将复制好的代码在在代码库中到处粘贴。

清单 2 显示使用工厂方法的一个示例。

清单 2. Factory2.php
<?php
interface
 IUser
{
  function
 getName();
}
 
class
 User implements IUser
{
  public
 static function Load( $id )
  {
        return
 new User( $id );
  }
 
  public
 static function Create( )
  {
        return
 new User( null );
  }
 
  public
 function __construct( $id ) { }
 
  public
 function getName()
  {
    return
 "Jack";
  }
}
 
$uo= User::Load(
 1 );
echo(
 $uo->getName()."\n" );
?>

这段代码要简单得多。它仅有一个接口 IUser 和一个实现此接口的 User 类。User 类有两个创建对象的静态方法。此关系可用图 2 中的 UML 表示。

图 2. IUser 接口和带有工厂方法的 user 类

IUser 接口和带有工厂方法的用户类

在命令行中运行脚本产生的结果与清单 1 的结果相同,如下所示:

1

2

3

%
 php factory2.php
Jack
%


如上所述,有时此类模式在规模较小的环境中似乎有些大材小用。不过,最好还是学习这种扎实的编码形式,以便应用于任意规模的项目中。

单元素模式

某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。

单元素模式可以满足此要求。如果应用程序每次包含且仅包含一个对象,那么这个对象就是一个单元素(Singleton)。清单 3 中的代码显示了 PHP V5 中的一个常見的PHP設計模式分享。

清单 3. Singleton.php

<?php
require_once("DB.php");
 
class
 DatabaseConnection
{
  public
 static function get()
  {
    static
 $db= null;
    if
 ( $db == null )
      $db= newDatabaseConnection();
    return
 $db;
  }
 
  private
 $_handle= null;
 
  private
 function __construct()
  {
    $dsn= &#39;mysql://root:password@localhost/photos&#39;;
    $this->_handle
 =& DB::Connect( $dsn, array() );
  }
   
  public
 function handle()
  {
    return
 $this->_handle;
  }
}
 
print(
 "Handle = ".DatabaseConnection::get()->handle()."\n" );
print(
 "Handle = ".DatabaseConnection::get()->handle()."\n" );
?>

此代码显示名为 DatabaseConnection 的单个类。您不能创建自已的 DatabaseConnection,因为构造函数是专用的。但使用静态 get 方法,您可以获得且仅获得一个 DatabaseConnection 对象。此代码的 UML 如图 3 所示。

图 3. 常見的PHP設計模式分享

常見的PHP設計模式分享

在两次调用间,handle 方法返回的数据库句柄是相同的,这就是最好的证明。您可以在命令行中运行代码来观察这一点。


%
 php singleton.php
Handle
 = Object id #3
Handle
 = Object id #3
%

返回的两个句柄是同一对象。如果您在整个应用程序中使用常見的PHP設計模式分享,那么就可以在任何地方重用同一句柄。

您可以使用全局变量存储数据库句柄,但是,该方法仅适用于较小的应用程序。在较大的应用程序中,应避免使用全局变量,并使用对象和方法访问资源。

观察者模式

观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。

一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表,添加用户时,它将发送出一条消息。添加用户时,通过发送消息的日志观察者可以观察此列表。

清单 4. Observer.php

<?php
interface
 IObserver
{
  function
 onChanged( $sender, $args );
}
 
interface
 IObservable
{
  function
 addObserver( $observer );
}
 
class
 UserList implements IObservable
{
  private
 $_observers= array();
 
  public
 function addCustomer( $name )
  {
    foreach(
 $this->_observers as $obs )
      $obs->onChanged(
 $this, $name );
  }
 
  public
 function addObserver( $observer )
  {
    $this->_observers
 []= $observer;
  }
}
 
class
 UserListLogger implements IObserver
{
  public
 function onChanged( $sender, $args )
  {
    echo(
 "&#39;$args&#39; added to user list\n" );
  }
}
 
$ul
 = new UserList();
$ul->addObserver(
 new UserListLogger() );
$ul->addCustomer(
 "Jack" );
?>

此代码定义四个元素:两个接口和两个类。IObservable 接口定义可以被观察的对象,UserList 实现该接口,以便将本身注册为可观察。IObserver 列表定义要通过怎样的方法才能成为观察者,UserListLogger 实现 IObserver 接口。图 4 的 UML 中展示了这些元素。

图 4. 常見的PHP設計模式分享

常見的PHP設計模式分享

如果在命令行中运行它,您将看到以下输出:


%
 php observer.php
&#39;Jack&#39;
 added to user list
%

测试代码创建 UserList,并将 UserListLogger 观察者添加到其中。然后添加一个消费者,并将这一更改通知 UserListLogger。

认识到 UserList 不知道日志程序将执行什么操作很关键。可能存在一个或多个执行其他操作的侦听程序。例如,您可能有一个向新用户发送消息的观察者,欢迎新用户使用该系统。这种方法的价值在于 UserList 忽略所有依赖它的对象,它主要关注在列表更改时维护用户列表并发送消息这一工作。

此模式不限于内存中的对象。它是在较大的应用程序中使用的数据库驱动的消息查询系统的基础。

命令链模式

命令链 模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。如果可以,该请求被处理,进程停止。您可以为系统添加或移除处理程序,而不影响其他处理程序。清单 5 显示了此模式的一个示例。

清单 5. Chain.php

<?php
interface
 ICommand
{
  function
 onCommand( $name, $args );
}
 
class
 CommandChain
{
  private
 $_commands= array();
 
  public
 function addCommand( $cmd )
  {
    $this->_commands
 []= $cmd;
  }
 
  public
 function runCommand( $name, $args )
  {
    foreach(
 $this->_commands as $cmd )
    {
      if
 ( $cmd->onCommand( $name, $args ) )
        return;
    }
  }
}
 
class
 UserCommand implements ICommand
{
  public
 function onCommand( $name, $args )
  {
    if
 ( $name != &#39;addUser&#39; ) return false;
    echo(
 "UserCommand handling &#39;addUser&#39;\n" );
    return
 true;
  }
}
 
class
 MailCommand implements ICommand
{
  public
 function onCommand( $name, $args )
  {
    if
 ( $name != &#39;mail&#39; ) return false;
    echo(
 "MailCommand handling &#39;mail&#39;\n" );
    return
 true;
  }
}
 
$cc
 = new CommandChain();
$cc->addCommand(
 new UserCommand() );
$cc->addCommand(
 new MailCommand() );
$cc->runCommand(
 &#39;addUser&#39;, null );
$cc->runCommand(
 &#39;mail&#39;, null );
?>

此程式碼定義維護 ICommand 物件清單的 CommandChain 類別。兩個類別都可以實現 ICommand 介面 —— 一個對郵件的請求作出回應,另一個對新增使用者作出回應。 圖 5 給出了 UML。

圖5. 命令鍊及其相關命令

常見的PHP設計模式分享

如果您執行包含某些測試程式碼的腳本,則會得到以下輸出:


#% php chain.php

UserCommand handling 'addUser'

MailCommand handling 'mail'

%

代码首先创建 CommandChain 对象,并为它添加两个命令对象的实例。然后运行两个命令以查看谁对这些命令作出了响应。如果命令的名称匹配 UserCommand 或 MailCommand,则代码失败,不发生任何操作。

为处理请求而创建可扩展的架构时,命令链模式很有价值,使用它可以解决许多问题。

策略模式

我们讲述的最后一个设计模式是策略 模式。在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分 —— 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。

作为一个较简单的示例,清单 6 显示了一个用户列表类,它提供了一个根据一组即插即用的策略查找一组用户的方法。

清单 6. Strategy.php
<?phpinterface
 IStrategy{  function
 filter( $record );} class
 FindAfterStrategy implements IStrategy{  private
 $_name;   public
 function __construct( $name )  {    $this->_name
 = $name;  }   public
 function filter( $record )  {    return
 strcmp( $this->_name, $record ) <= 0;  }} class
 RandomStrategy implements IStrategy{  public
 function filter( $record )  {    return
 rand( 0, 1 ) >= 0.5;  }} class
 UserList{  private
 $_list = array();   public
 function __construct( $names )  {    if
 ( $names != null )    {      foreach(
 $names as $name )      {        $this->_list
 []= $name;      }    }  }   public
 function add( $name )  {    $this->_list
 []= $name;  }   public
 function find( $filter )  {    $recs
 = array();    foreach(
 $this->_list as $user )    {      if
 ( $filter->filter( $user ) )        $recs
 []= $user;    }    return
 $recs;  }} $ul
 = new UserList( array( "Andy", "Jack", "Lori", "Megan" ) );$f1
 = $ul->find( new FindAfterStrategy( "J" ) );print_r(
 $f1 ); $f2
 = $ul->find( new RandomStrategy() );print_r(
 $f2 );?>

此代码的 UML 如图 6 所示。

图 6. 常見的PHP設計模式分享

常見的PHP設計模式分享

UserList 类是打包名称数组的一个包装器。它实现 find 方法,该方法利用几个策略之一来选择这些名称的子集。这些策略由 IStrategy 接口定义,该接口有两个实现:一个随机选择用户,另一个根据指定名称选择其后的所有名称。运行测试代码时,将得到以下输出:

%
 php strategy.phpArray(    [0]
 => Jack    [1]
 => Lori    [2]
 => Megan)Array(    [0]
 => Andy    [1]
 => Megan)%

测试代码为两个策略运行同一用户列表,并显示结果。在第一种情况中,策略查找排列在 J 后的任何名称,所以您将得到 Jack、Lori 和 Megan。第二个策略随机选取名称,每次会产生不同的结果。在这种情况下,结果为 Andy 和 Megan。

策略模式非常适合复杂数据管理系统或数据处理系统,二者在数据筛选、搜索或处理的方式方面需要较高的灵活性。

结束语

本文介绍的仅仅是 PHP 应用程序中使用的几种最常见的设计模式。在设计模式 一书中演示了更多的设计模式。不要因架构的神秘性而放弃。模式是一种绝妙的理念,适用于任何编程语言、任何技能水平。

以上是常見的PHP設計模式分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
PHP:服務器端腳本語言的簡介PHP:服務器端腳本語言的簡介Apr 16, 2025 am 12:18 AM

PHP是一種服務器端腳本語言,用於動態網頁開發和服務器端應用程序。 1.PHP是一種解釋型語言,無需編譯,適合快速開發。 2.PHP代碼嵌入HTML中,易於網頁開發。 3.PHP處理服務器端邏輯,生成HTML輸出,支持用戶交互和數據處理。 4.PHP可與數據庫交互,處理表單提交,執行服務器端任務。

PHP和網絡:探索其長期影響PHP和網絡:探索其長期影響Apr 16, 2025 am 12:17 AM

PHP在過去幾十年中塑造了網絡,並將繼續在Web開發中扮演重要角色。 1)PHP起源於1994年,因其易用性和與MySQL的無縫集成成為開發者首選。 2)其核心功能包括生成動態內容和與數據庫的集成,使得網站能夠實時更新和個性化展示。 3)PHP的廣泛應用和生態系統推動了其長期影響,但也面臨版本更新和安全性挑戰。 4)近年來的性能改進,如PHP7的發布,使其能與現代語言競爭。 5)未來,PHP需應對容器化、微服務等新挑戰,但其靈活性和活躍社區使其具備適應能力。

為什麼要使用PHP?解釋的優點和好處為什麼要使用PHP?解釋的優點和好處Apr 16, 2025 am 12:16 AM

PHP的核心優勢包括易於學習、強大的web開發支持、豐富的庫和框架、高性能和可擴展性、跨平台兼容性以及成本效益高。 1)易於學習和使用,適合初學者;2)與web服務器集成好,支持多種數據庫;3)擁有如Laravel等強大框架;4)通過優化可實現高性能;5)支持多種操作系統;6)開源,降低開發成本。

揭穿神話:PHP真的是一種死語嗎?揭穿神話:PHP真的是一種死語嗎?Apr 16, 2025 am 12:15 AM

PHP沒有死。 1)PHP社區積極解決性能和安全問題,PHP7.x提升了性能。 2)PHP適合現代Web開發,廣泛用於大型網站。 3)PHP易學且服務器表現出色,但類型系統不如靜態語言嚴格。 4)PHP在內容管理和電商領域仍重要,生態系統不斷進化。 5)通過OPcache和APC等優化性能,使用OOP和設計模式提升代碼質量。

PHP與Python辯論:哪個更好?PHP與Python辯論:哪個更好?Apr 16, 2025 am 12:03 AM

PHP和Python各有優劣,選擇取決於項目需求。 1)PHP適合Web開發,易學,社區資源豐富,但語法不夠現代,性能和安全性需注意。 2)Python適用於數據科學和機器學習,語法簡潔,易學,但執行速度和內存管理有瓶頸。

PHP的目的:構建動態網站PHP的目的:構建動態網站Apr 15, 2025 am 12:18 AM

PHP用於構建動態網站,其核心功能包括:1.生成動態內容,通過與數據庫對接實時生成網頁;2.處理用戶交互和表單提交,驗證輸入並響應操作;3.管理會話和用戶認證,提供個性化體驗;4.優化性能和遵循最佳實踐,提升網站效率和安全性。

PHP:處理數據庫和服務器端邏輯PHP:處理數據庫和服務器端邏輯Apr 15, 2025 am 12:15 AM

PHP在數據庫操作和服務器端邏輯處理中使用MySQLi和PDO擴展進行數據庫交互,並通過會話管理等功能處理服務器端邏輯。 1)使用MySQLi或PDO連接數據庫,執行SQL查詢。 2)通過會話管理等功能處理HTTP請求和用戶狀態。 3)使用事務確保數據庫操作的原子性。 4)防止SQL注入,使用異常處理和關閉連接來調試。 5)通過索引和緩存優化性能,編寫可讀性高的代碼並進行錯誤處理。

您如何防止PHP中的SQL注入? (準備的陳述,PDO)您如何防止PHP中的SQL注入? (準備的陳述,PDO)Apr 15, 2025 am 12:15 AM

在PHP中使用預處理語句和PDO可以有效防範SQL注入攻擊。 1)使用PDO連接數據庫並設置錯誤模式。 2)通過prepare方法創建預處理語句,使用佔位符和execute方法傳遞數據。 3)處理查詢結果並確保代碼的安全性和性能。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
4 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它們
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具