php精粹 php設計模式

來源:互聯網
上載者:User

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

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

2.單例模式

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

  2. class Database{
  3. // A static variable to hold our single instance
  4. private static $_instance = null;
  5. // Make the constructor private to ensure singleton
  6. private function __construct()
  7. {
  8. echo 'constructor';
  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);

複製代碼

問題:使用單例模式不能建立兩個執行個體,可用Traits解決建立兩個不同類型的執行個體的問題,但仍然不能解決建立兩個相同執行個體的問題(可用註冊表模式解決)。

建立兩個不同類的執行個體 代碼:

  1. trait Singleton {
  2. private static $_instance = null;
  3. public static function getInstance() {
  4. $class = __CLASS__;
  5. if(!(self::$_instance instanceof $class)) {
  6. self::$_instance = new $class;
  7. }
  8. return self::$_instance;
  9. }
  10. }
  11. class DB {
  12. }
  13. class DBWriteConnection extends DB {
  14. use Singleton;
  15. private function __construct() {
  16. echo 'DBWriteConnection
    ';
  17. }
  18. }
  19. class DBReadConnection extends DB {
  20. use Singleton;
  21. private function __construct() {
  22. echo 'DBReadConnection
    ';
  23. }
  24. }
  25. $dbWriteConnection = DBWriteConnection::getInstance();
  26. var_dump($dbWriteConnection);
複製代碼

3.註冊表模式註冊表模式僅僅是一個單獨的全域類,在你需要的時候允許代碼檢索一個對象的相同執行個體,也可以在你需要的時建立另一個執行個體(一經要求將再次訪問那些全域執行個體)。

Registry類:

  1. class Registry {

  2. /**
  3. * @var array The store for all of our objects
  4. */
  5. static private $_store = array();
  6. /**
  7. * Add an object to the registry
  8. *
  9. * If you do not specify a name the classname is used
  10. *
  11. * @param mixed $object The object to store
  12. * @param string $name Name used to retrieve the object
  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. * Get an object from the registry
  27. *
  28. * @param string $name Object name, {@see self::set()}
  29. * @return mixed
  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. * Check if an object is in the registry
  41. *
  42. * @param string $name Object 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. * Remove an object from the registry
  54. *
  55. * @param string $name Object 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 DBWriteConnection {}

  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 'DBWriteConnection
    ';
  21. }
  22. }

  23. class DBReadConnection extends DBConnection {

  24. public function __construct()
  25. {
  26. echo 'DBReadConnection
    ';
  27. }
  28. }

  29. $dbWriteConnection = DBWriteConnection::getInstance('abc');

  30. var_dump($dbWriteConnection);
  31. $dbReadConnection = DBReadConnection::getInstance();
  32. var_dump($dbReadConnection);

複製代碼

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

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

  1. /**
  2. * Log Factory
  3. *
  4. * Setup and return a file, mysql, or sqlite logger
  5. */
  6. class Log_Factory {
  7. /**
  8. * Get a log object
  9. *
  10. * @param string $type The type of logging backend, file, mysql or sqlite
  11. * @param array $options Log class options
  12. */
  13. public function getLog($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(
  4. "hello",
  5. "world",
  6. );

  7. public function __construct() {

  8. $this->key = 0;
  9. }

  10. public function rewind() {

  11. $this->key = 0;
  12. }

  13. public function current() {

  14. return $this->data[$this->key];
  15. }

  16. public function key() {

  17. return $this->key;
  18. }

  19. public function next() {

  20. $this->key++;
  21. return true;
  22. }

  23. public function valid() {

  24. return isset($this->data[$this->key]);
  25. }
  26. }

  27. $iterator = new BasicIterator();

  28. $iterator->rewind();

  29. do {

  30. $key = $iterator->key();
  31. $value = $iterator->current();
  32. echo $key .': ' .$value . PHP_EOL;
  33. } while ($iterator->next() && $iterator->valid());

  34. $iterator = new BasicIterator();
  35. foreach ($iterator as $key => $value) {
  36. echo $key .': ' .$value . PHP_EOL;
  37. }

複製代碼

(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: " . $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. * Accept only even-keyed values
  4. *
  5. * @return bool
  6. */
  7. public function accept()
  8. {
  9. // Get the actual iterator
  10. $iterator = $this->getInnerIterator();
  11. // Get the current key
  12. $key = $iterator->key();
  13. // Check for even keys
  14. if ($key % 2 == 0) {
  15. return true;
  16. }
  17. return false;
  18. }
  19. }

  20. $array = array(

  21. 0 => "Hello",
  22. 1 => "Everybody Is",
  23. 2 => "I'm",
  24. 3 => "Amazing",
  25. 4 => "The",
  26. 5 => "Who",
  27. 6 => "Doctor",
  28. 7 => "Lives"
  29. );

  30. // Create an iterator from our array

  31. $iterator = new ArrayIterator($array);

  32. // Create our FilterIterator

  33. $filterIterator = new EvenFilterIterator($iterator);

  34. // Iterate

  35. foreach ($filterIterator as $key => $value) {
  36. echo $key .': '. $value . PHP_EOL;
  37. }
  38. ?>

複製代碼

(4)RegexIterator迭代器

  1. // Create a RecursiveDirectoryIterator

  2. $directoryIterator = new RecursiveDirectoryIterator("./");

  3. // Create a RecursiveIteratorIterator to recursively iterate

  4. $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);

  5. // Createa filter for *Iterator*.php files

  6. $regexFilter = new RegexIterator($recursiveIterator, '/(.*?)Iterator(.*?)\.php$/');

  7. // Iterate

  8. foreach ($regexFilter as $key => $file) {
  9. /* @var SplFileInfo $file */
  10. echo $file->getFilename() . PHP_EOL;
  11. }
複製代碼

功能:找到所有的php檔案

(4)LimitItertor迭代器,像SQL中的LIMIT

  1. // Define the array

  2. $array = array(
  3. 'Hello',
  4. 'World',
  5. 'How',
  6. 'are',
  7. 'you',
  8. 'doing?'
  9. );

  10. // Create the iterator

  11. $iterator = new ArrayIterator($array);

  12. // Create the limiting iterator, to get the first 2 elements

  13. $limitIterator = new LimitIterator($iterator, 0, 2);

  14. // Iterate

  15. foreach ($limitIterator as $key => $value) {
  16. echo $key .': '. $value . PHP_EOL;
  17. }

複製代碼

6.觀察者模式(observer)

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

  1. /**

  2. * The Event Class
  3. *
  4. * With this class you can register callbacks that will
  5. * be called (FIFO) for a given event.
  6. */
  7. class Event {
  8. /**
  9. * @var array A multi-dimentional array of events => callbacks
  10. */
  11. static protected $callbacks = array();
  12. /**
  13. * Register a callback
  14. *
  15. * @param string $eventName Name of the triggering event
  16. * @param mixed $callback An instance of Event_Callback or a Closure
  17. */
  18. static public function registerCallback($eventName, $callback)
  19. {
  20. if (!($callback instanceof Event_Callback) && !($callback instanceof Closure)) {
  21. throw new Exception("Invalid callback!");
  22. }
  23. $eventName = strtolower($eventName);
  24. self::$callbacks[$eventName][] = $callback;
  25. }
  26. /**
  27. * Trigger an event
  28. *
  29. * @param string $eventName Name of the event to be triggered
  30. * @param mixed $data The data to be sent to the callback
  31. */
  32. static public function trigger($eventName, $data)
  33. {
  34. $eventName = strtolower($eventName);
  35. if (isset(self::$callbacks[$eventName])) {
  36. foreach (self::$callbacks[$eventName] as $callback) {
  37. self::callback($callback, $data);
  38. }
  39. }
  40. }
  41. /**
  42. * Perform the callback
  43. *
  44. * @param mixed $callback An instance of Event_Callback or a Closure
  45. * @param mixed $data The data sent to the callback
  46. */
  47. static protected function callback($callback, $data)
  48. {
  49. if ($callback instanceof Closure) {
  50. $callback($data);
  51. } else {
  52. $callback->run($data);
  53. }
  54. }
  55. }

  56. /**

  57. * The Event Callback interface
  58. *
  59. * If you do not wish to use a closure
  60. * you can define a class that extends
  61. * this instead. The run method will be
  62. * called when the event is triggered.
  63. */
  64. interface Event_Callback {
  65. public function run($data);
  66. }

  67. /**

  68. * Logger callback
  69. */
  70. class LogCallback implements Event_Callback {
  71. public function run($data)
  72. {
  73. echo "Log Data" . PHP_EOL;
  74. var_dump($data);
  75. }
  76. }

  77. // Register the log callback

  78. Event::registerCallback('save', new LogCallback());

  79. // Register the clear cache callback as a closure

  80. Event::registerCallback('save', function ($data) {
  81. echo "Clear Cache" . PHP_EOL;
  82. var_dump($data);
  83. });

  84. class MyDataRecord {

  85. public function save()
  86. {
  87. // Save data
  88. // Trigger the save event
  89. Event::trigger('save', array("Hello", "World"));
  90. }
  91. }

  92. // Instantiate a new data record

  93. $data = new MyDataRecord();
  94. $data->save(); // 'save' Event is triggered here

複製代碼

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

  1. /**

  2. * Log Class
  3. */
  4. class Log {
  5. /**
  6. * @var Log_Engine_Interface
  7. */
  8. protected $engine = false;
  9. /**
  10. * Add an event to the log
  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. * Set the log data storage engine
  27. *
  28. * @param Log_Engine_Interface $Engine
  29. */
  30. public function setEngine(Log_Engine_Interface $engine)
  31. {
  32. $this->engine = $engine;
  33. }
  34. /**
  35. * Retrieve the data storage engine
  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. * Add an event to the log
  47. *
  48. * @param string $message
  49. */
  50. public function add(array $data);
  51. }

  52. class Log_Engine_File implements Log_Engine_Interface {

  53. /**
  54. * Add an event to the log
  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架構圖:

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

您可能感興趣的文章:

  • php設計模式之單例模式、原廠模式與觀察者模式
  • 深入php設計模式執行個體詳解
  • php設計模式執行個體之命令模式
  • php設計模式執行個體之觀察者模式(2)
  • PHP設計模式執行個體之觀察者模式
  • php設計模式執行個體之原廠模式
  • php設計模式執行個體之單例模式
  • PHP設計模式之觀察者模式的例子
  • php設計模式之原廠模式的執行個體代碼
  • php設計模式之單例模式的執行個體代碼
  • php常用設計模式之原廠模式與單例模式介紹
  • 學習php設計模式之單例模式
  • php常用的三種設計模式的學習筆記
  • php設計模式之單例模式學習
  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.