目錄
您可能感興趣的文章:
首頁 後端開發 php教程 php精粹 php設計模式

php精粹 php設計模式

Jul 25, 2016 am 09:13 AM

1,選擇一個最適合的設計模式

沒有任何事物是完美的,也沒有人說過設計模式一個嚴格的放之四海而皆準的解決方法。因此你可以改變這些模式,使它們更適合手邊的工作。對某些設計模式而言,他們就是所屬程式固有的天性;而對於其他的一些設計模式,你可以改變自己的模式。模式之間互相配合、協同工作已經很常見。它們構成了整個應用(至少一部分)的基礎。

2.單例模式

  1. // The Database class represents our global DB connection

  2. class Database{
  3. // A holdic v. our single instance
  4. private static $_instance = null;
  5. // Make the constructor private to ensure singleton
  6. private function __construct()
  7. {
  8. private function __construct()
  9. { }
  10. // A method to get our singleton instance

  11. public static function getInstance()
  12. {
  13. if (!(self::$_instance instanceof Database)) {
  14. self::$_instance = new Database();
  15. }
  16. return self::$_instance;
  17. }
  18. }
  19. $database = Database::getInstance();

  20. var_dump($database);
複製程式碼

問題:使用單單>複製程式碼

問題:使用單單>複製程式碼
    問題:使用單單>複製程式碼
  1. 問題:使用單單>複製程式碼
  2. 問題:使用單單>複製程式碼
  3. 問題:使用單單>複製程式碼
  4. 問題:使用單單>複製程式碼
  5. 問題:使用單單>複製碼範例模式不能建立兩個實例,可用Traits解決建立兩個不同類型的實例的問題,但仍無法解決建立兩個相同實例的問題(可用登錄模式解決)。
  6. 建立兩個不同類別的實例 程式碼:
  7. trait Singleton {
  8. private static $_instance = null;
  9. public static ftion get getption $ __CLASS__;
  10. if(!(self::$_instance instanceof $class)) {
  11. self::$_instance = new $class;
  12. }
  13. return self:: $_instance;
  14. }
  15. }
  16. class DB {
}
class DBWriteConnection extends DB { s__Svate f🎜>;
echo 'DBWriteConnection
'; } } class DBReadConnection extends DB { use Singleton; private function ) { echo 'DBReadConnection
'; } } $dbWriteConnection = DBWriteConnection::getInstance(); var_dump($dbWriteConnection); 複製程式碼

3.登錄模式 註冊表模式只是一個單獨的全域類,在你需要的時候允許程式碼檢索一個物件的相同實例,也可以在你需要的時創建另一個實例(一經要求將再次存取那些全域實例)。

Registry類別:

  1. class Registry {

  2. /**
  3. * @var array 所有物件的儲存
  4. */
  5. static private $_store = array();
  6. /**
  7. * 將物件新增至登錄機碼
  8. *
  9. * 如果不指定名稱,則使用類別名稱
  10. *
  11. * @param mix $object 要儲存的物件
  12. * @param string $name 用於檢索物件的名稱
  13. * @return void
  14. * @throws Exception
  15. */
  16. static public function add($object, $name = null)
  17. {
  18. // Use the classname if no name given, simulates singleton
  19. $name = (!is_null($name)) ?$name:get_class($object);
  20. if (isset(self::$_store[$name])) {
  21. throw new Exception(" Object already exists in registry");
  22. }
  23. self::$_store[$name]= $object;
  24. }
  25. /**
  26. * 從登錄機碼取得一個物件
  27. *
  28. * @param string $name 物件名稱,{@see self::set()}
  29. * @return mix
  30. * @throws Exception
  31. */
  32. static public function get($name)
  33. {
  34. if (!self::contains($name)) {
  35. throw new Exception("Object does not exist in registry");
  36. }
  37. return self::$_store[$name];

  38. }
  39. /**
  40. * 檢查物件是否在登錄中
  41. *
  42. * @param string $name 物件名稱,{@see self::set()}
  43. * @return bool
  44. */
  45. static public function contains($name )
  46. {
  47. if (!isset(self::$_store[$name])) {
  48. return false;
  49. }
  50. return true;
  51. }
  52. /**
  53. * 從註冊表中刪除一個物件
  54. *
  55. * @param string $name 物件名稱,{@see self::set()}
  56. * @returns void
  57. */
  58. static public function remove($name)
  59. {
  60. if (self::contains($name)) {
  61. unset(self:: $_store[$name]);
  62. }
  63. }
  64. }
複製代碼

在類別外部,使用Registry類別:

  1. require 'Registry.php';

  2. class DBReadConnection {}

  3. class DBWrite {}
  4. $read = new DBReadConnection;

  5. Registry::add($read);
  6. $write = new DBWriteConnection;

  7. Registry ::add($write);
  8. // To get the instances, anywhere in our code:

  9. $read = Registry::get('DBReadConnection');
  10. $ write = Registry::get('DBWriteConnection');
  11. var_dump($read);

  12. var_dump($write);
複製程式碼

在類別內部使用Registry表類,使用者不與Registry互動。

範例程式碼:

  1. require 'Registry.php';

  2. abstract class DBConnection {

  3. static public function getInstance($name = null)
  4. {
  5. // Get the late-static-binding version of __CLASS__
  6. $class = get_called_class();
  7. // Allow passing in a name to get multiple instances
  8. // If you do not pass a name, it functions as a singleton
  9. $name = (!is_null($name)) ? $name:$class;
  10. if (!Registry::contains ($name)) {
  11. $instance = new $class();
  12. Registry::add($instance, $name);
  13. }
  14. return Registry::get($name);
  15. }
  16. }
  17. class DBWriteConnection extends DBConnection {

  18. public function __construct()
  19. {
  20. echo 'DBWConnectiona
    ';
  21. {
  22. echo 'DBWConnectiona
    ';
  23. ';
  24. }
  25. }
  26. class DBReadConnection extends DBConnection {

  27. public function __construct()
  28. {
  29. echo 'DBRead
    ';
  30. Connection
  31. echo 'DBRead
    ';
  32. Connection
  33. Connection
}

$dbWriteConnection = DBWriteConnection::getInstance('abc');var_dump($dbWriteConnection);$dbReadConnection = DBRead::getInstance(); var_dump($dbReadConnection);

複製程式碼

4.工廠模式 工廠(factory)模式製造對象,就像工業界與它同名的鋼筋混泥土產業一樣。通常,我們將工廠模式用於初始化相同抽象類別或介面的具體實作。

在通常方式下,雖然人們極少採用工廠模式,但是它仍是最適合初始化基於驅動安裝的許多變種的一種。例如不同的配置、會話或快取儲存引擎。工廠模式的最大價值在於它可以將多個物件設定封裝成單一、簡單的方法呼叫。

  1. /**
  2. * 日誌工廠
  3. *
  4. * 設定並傳回檔案、mysql 或 sqlite 記錄器
  5. */
  6. class Log_Factory {
  7. /**
  8. * 取得日誌物件
  9. *
  10. * @param string $type 日誌記錄後端的類型,檔案、mysql 或 sqlite
  11. * @param array $options 日誌類別選項
  12. */
  13. public function Log( $type = 'file', array $options)
  14. {
  15. // Normalize the type to lowercase
  16. $type = strtolower($type);
  17. // Figure out the class name and include it
  18. $class = "Log_" .ucfirst($type);
  19. require_once str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
  20. // Instantiate the class and set the appropriate options
  21. $log = new $class($options);
  22. switch ($type) {
  23. case 'file':
  24. $log->setPath($options[' location']);
  25. break;
  26. case 'mysql':
  27. $log->setUser($options['username']);
  28. $log->setPassword($options['password ']);
  29. $log->setDBName($options['location']);
  30. break;
  31. case 'sqlite':
  32. $log->setDBPath($otions['location' ]);
  33. break;
  34. }
  35. return $log;
  36. }
  37. }
複製代碼

5.迭代模式 迭代模式允許我們將foreach的性能添加到任何物件的內部儲存數據,而不僅僅添加到公共屬性。它覆蓋了預設的foreach行為,並允許我們為循環注入業務邏輯。

(1)使用Iterator迭代器接口

  1. class BasicIterator implements Iterator {

  2. private $key = 0;
  3. private $data = array( "world",
  4. );
  5. public function __construct() {

  6. $this->key = 0;
  7. }
  8. public function rewind() {

  9. $this->key = 0;
  10. }
  11. public function current() {

  12. return $this ->data[$this->key];
  13. }
  14. public function key() {

  15. return $this->key;
  16. }
  17. public function next() {

  18. $this->key++;
  19. return true;
  20. }
  21. public function valid() {

  22. return isset($this->data[$this->key]);
  23. }
  24. }
  25. $iterator = new BasicIterator();

  26. $iterator->rewind ();
  27. do {

  28. $key = $iterator->key();
  29. $value = $iterator->current();
  30. echo $key . ': ' .$value . PHP_EOL;
  31. } while ($iterator->next() && $iterator->valid());
  32. $iterator = new BasicIterator ();
  33. foreach ($iterator as $key => $value) {
  34. echo $key .': ' .$value . PHP_EOL;
  35. }
複製程式碼
(2)使用RecursiveIteratorIterator迭代器遍歷數組

  1. $array = array(

  2. "Hello", // Level 1
  3. array(
  4. "World " // Level 2
  5. ),
  6. array(
  7. "How", // Level 2
  8. array(
  9. "are", // Level 3
  10. "you" // Level 3
  11. )
  12. ),
  13. "doing?" // Level 1
  14. );
  15. $recursiveIterator = new RecursiveArrayIterator($array);

  16. $recursiveIteratorIterator = new RecursiveIteratorIterator($recursiveIterator);

  17. foreach ($recursiveIteratorIterator as $key => $value) {

  18. echo "Depth: " value. recursiveIteratorIterator->getDepth() . PHP_EOL;
  19. echo "Key: " . $key . PHP_EOL;
  20. echo "Value: " .$value . PHP_EOL;
  21. }
複製程式碼

(3)用FilterIterator迭代器實現過濾

  1. class EvenFilterIterator extends FilterIterator {

  2. /**
  3. * 僅接受偶數鍵值
  4. *
  5. * @return bool
  6. > / {
  7. // 取得實際的迭代器
  8. $iterator = $this->getInnerIterator();
  9. // 取得目前的key
  10. $ key = $iterator->key();
  11. // 檢查偶數鍵
  12. if ($key % 2 == 0) {
  13. return true;
  14. }
  15. return false;
  16. }
  17. }
  18. $array = array(

  19. 0 => "你好",
  20. 1 => "每個人都是”,
  21. 2 => 「我」,
  22. 3 => 「太棒了」,
  23. 4 => 「那個」,
  24. 5 => 「誰」,
  25. 6 => "Doctor" ,
  26. 7 => "Lives"
  27. );
  28. // 從我們的陣列建立一個迭代器

  29. $ iterator = new ArrayIterator($array); p>
  30. // 建立FilterIterator

  31. $filterIterator = new EvenFilterIterator($iterator);
  32. foreach ($filterIterator as $key => $value) {

  33. echo $key .': '. $價值。 PHP_EOL;
  34. }
  35. ?>
複製程式碼
(4)RegexIterator迭代器

  1. // 建立一個RecursiveDirectoryIterator

  2. $directoryIterator = 建立一個RecursiveDirectoryIterator
  3. $directoryIterator = 建立一個RecursiveDirectoryIterator
  4. $directoryIterator = 建立一個RecursiveDirectoryIterator
  5. // 建立一個RecursiveIteratorIterator 進行遞歸迭代

  6. $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);
  7. //ator 建立一個過濾器*. php 檔案

  8. $regexFilter = new RegexIterator($recursiveIterator, '/(.*?)Iterator(.*?).php$/');
  9. // 迭代
  10. foreach ($regexFilter as $key => $file) {
  11. /* @var SplFileInfo $file */
  12. echo $file->getFilename() . PHP_EOL;
  13. }
複製程式碼

功能:找到所有的php檔案

(4)LimitItertor迭代器,像SQL中的LIMIT
  1. //定義數組

  2. $array = array(
  3. 'Hello',
  4. '$array = array(
  5. 'Hello',
  6. ' ',,,
  7. '怎麼樣',
  8. '是',
  9. '你',
  10. '做什麼? 🎜>$iterator = new ArrayIterator($array);
  11. // 建立限制迭代器,取得前2 個元素

  12. $limitIterator = new LimitIterator($ iterator, 0, 2) ;
  13. //迭代

  14. foreach ($limitIterator as $key => $value) {
  15. echo $key .': '. $值。 PHP_EOL;
  16. }
複製程式碼

6.觀察者模式(observer)

觀察者模式的核心在於雲霄你的應用程式註冊一個回調,當某個特定的事件發生時便會促發它

  1. /**

  2. * 事件類
  3. *
  4. * 使用這個類,您可以註冊將
  5. * 為給定事件調用(先進先出)的回調。
  6. */
  7. class Event {
  8. /**
  9. * @var array 事件的多維數組 =>回呼
  10. */
  11. class Event {
  12. /**
  13. * 註冊回呼
  14. *
  15. * @param string $eventName 觸發事件的名稱
  16. * @param mix $callback Event_Callback 或 Closure 的實例
  17. */
  18. class Event {
  19. /**
  20. * 觸發事件
  21. *
  22. * @param string $eventName 要觸發的事件名稱
  23. * @param mix $data 要傳送到回呼的資料
  24. */
  25. class Event {
  26. /**
  27. * 執行回呼
  28. *
  29. * @param mix $callback Event_Callback 或閉包的實例
  30. * @param mix $data 傳送到回調的資料
  31. */
  32. class Event {
  33. /**
  34. * 事件回呼介面
  35. *
  36. * 如果你不想使用閉包
  37. * 你可以定義一個擴充
  38. * this 的類別。 run 方法將
  39. * 當事件觸發時被呼叫。
  40. */
  41. static protected $callbacks = array();
  42. /**
  43. * 記錄器回呼
  44. */
  45. static public function registerCallback($eventName, $call>back)
  46. back {
  47. if (!($callback instanceof Event_Callback) && !($callback instanceof Closure)) {
  48. throw new Exception("Invalid callback!");
  49. }
  50. self::$callbacks[$eventName][] = $callback;
  51. }
  52. /***/
  53. static public function trigger ($eventName, $data)
  54. {
  55. $eventName = strtolower($eventName);
  56. if (isset(self::$callbacks[$eventName])) {
  57. foreach ( self::$callbacks[$eventName] as $callback) {
  58. self::callback($callback, $data);
  59. }
  60. }
  61. }
  62. /** */
  63. static protected function callback($callback, $data)
  64. {
  65. if ($callback instanceof Closure) {
  66. $callback($data);
  67. }
  68. }
  69. }
  70. }
  71. }
  72. }
  73. }
  74. }
  75. }
  76. }
  77. }
  78. }
  79. }
  80. }
  81. }
  82. }
  83. }
  84. }
  85. }
  86. }
  87. } else
  88. $callback->run($data);
  89. }
  90. }
  91. }
  92. /***/

  93. interface Event_Callback { public function run($data);
  94. }
  95. /***/

class LogCallback implements Event_Callback {
public function run($data) { echo "Log Data" . PHP_EOL;
var_dump($data); }}

// Register the log callbackEvent::registerCallback('save', new LogCallback());

// Register the clear cache callback as a closureEvent::registerCallback('save', function ( $data) { echo "Clear Cache" . PHP_EOL; var_dump($data); });

class MyDataRecord { public function save( ) { // Save data // Trigger the save event Event::trigger('save', array("Hello", "World")); }}

// Instantiate a new data record$data = new MyDataRecord();$data->save(); // 'save' Event is triggered here

複製程式碼

7.依賴注入模式 依賴注入模式允許類別的使用這為這個類別注入依賴的行為。

  1. /**

  2. * 日誌類別
  3. */
  4. class Log {
  5. /**
  6. * @var Log_Engine_Interface
  7. */
  8. protected $engine = false;
  9. /**
  10. * 將事件新增至日誌
  11. *
  12. * @param string $message
  13. */
  14. public function add($message)
  15. {
  16. if (!$this->engine) {
  17. throw new Exception('Unable to write log. No Engine set.');
  18. }
  19. $data['datetime'] = time();
  20. $data['message' ] = $message;
  21. $session = Registry::get('session');
  22. $data['user'] = $session->getUserId();
  23. $ this->engine->add($data);
  24. }
  25. /**
  26. * 設定日誌資料儲存引擎
  27. *
  28. * @param Log_Engine_Interface $Engine
  29. */
  30. public function setEngine(Log_Engine_Interface $engine)
  31. {
  32. $this ->engine = $engine;
  33. }
  34. /**
  35. * 擷取資料儲存引擎
  36. *
  37. * @return Log_Engine_Interface
  38. */
  39. public function getEngine()
  40. {
  41. return $this->engine>;
  42. ; }
  43. }
  44. interface Log_Engine_Interface {

  45. /**
  46. * 將事件新增至日誌
  47. *
  48. * @param string $message
  49. */
  50. public function add(array $data);
  51. }
  52. class Log_Engine_File implements Log_Engine_Interface {

  53. /**
  54. * 將事件新增至日誌
  55. *
  56. * @param string $message
  57. */
  58. public function add(array $data)
  59. {
  60. $line = '[' .data('r ', $data['datetime']). '] ' .$data['message']. ' User: ' .$data['user'] . PHP_EOL;
  61. $config = Registry:: get('site-config');
  62. if (!file_put_contents($config['location'], $line, FILE_APPEND)) {
  63. throw new Exception("An error occurred writing to file. ");
  64. }
  65. }
  66. }
  67. $engine = new Log_Engine_File();

  68. $log = new Log() ;

  69. $log->setEngine($engine);
  70. // Add it to the registry

  71. Registry::add($log);
複製程式碼

依賴注入不想工廠模式,日之類無需了解每一個不同的儲存引擎的相關知識。這意味著任何使用日誌類別的開發者可以添加他們自己的儲存引擎,主要他們複合介面就行。

8.模型-視圖-控制器 模型-視圖-控制器又稱為MVC模式,是描述應用程式3個不同層次之間關係的一種方式。 模型-資料層 所有的輸出資料都來自模型。它可能是一個資料庫、web服務或文件。 視圖-表現層 負責將資料從模型中取出並輸出給使用者。 控制器-應用程式流程層 根據使用者的請求呼叫對應的模型檢索出請求的數據,然後呼叫視圖將操作的結果顯示給使用者。

一個典型的MVC架構圖: php mvc架构图

9.對模式的理解
模式是許多常見問題的最佳解決方法。

您可能感興趣的文章:

  • php設計模式單例模式、工廠模式與觀察者模式
  • 深入php設計模式實例詳解
  • php設計模式實例之指令模式
  • php設計模式實例之觀察者模式(2)
  • PHP設計模式實例之觀察者模式
  • php設計模式實例之工廠模式
  • php設計模式實例之單例模式
  • PHP設計模式之觀察者模式的例子
  • php設計模式之工廠模式的實例代碼
  • php設計模式之單例模式的實例程式碼
  • php常用設計模式之工廠模式與單例模式介紹
  • 學習php設計模式之單例模式
  • php常用的三種設計模式的學習筆記
  • php設計模式之單例模式學習


本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1321
25
PHP教程
1269
29
C# 教程
1249
24
PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? 說明PHP中的安全密碼散列(例如,password_hash,password_verify)。為什麼不使用MD5或SHA1? Apr 17, 2025 am 12:06 AM

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP類型提示如何起作用,包括標量類型,返回類型,聯合類型和無效類型? PHP類型提示如何起作用,包括標量類型,返回類型,聯合類型和無效類型? Apr 17, 2025 am 12:25 AM

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP和Python:代碼示例和比較 PHP和Python:代碼示例和比較 Apr 15, 2025 am 12:07 AM

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

See all articles