当前位置:Gxlcms > PHP教程 > php精粹php设计模式

php精粹php设计模式

时间:2021-07-01 10:21:17 帮助过:19人阅读

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架构图: php mvc架构图

9.对模式的理解
模式是很多常见问题的最佳解决方法。

您可能感兴趣的文章:

  • php设计模式之单例模式、工厂模式与观察者模式
  • 深入php设计模式实例详解
  • php设计模式实例之命令模式
  • php设计模式实例之观察者模式(2)
  • PHP设计模式实例之观察者模式
  • php设计模式实例之工厂模式
  • php设计模式实例之单例模式
  • PHP设计模式之观察者模式的例子
  • php设计模式之工厂模式的实例代码
  • php设计模式之单例模式的实例代码
  • php常用设计模式之工厂模式与单例模式介绍
  • 学习php设计模式之单例模式
  • php常用的三种设计模式的学习笔记
  • php设计模式之单例模式学习

人气教程排行