1. Choose the most appropriate design pattern
Nothing is perfect, and no one ever said design patterns were a strict one-size-fits-all solution. So you can change these modes to make them more suitable for the job at hand. For some design patterns, they are inherent in the program they belong to; while for other design patterns, you can change the pattern itself. It is common for modes to cooperate and work together. They form the basis of (at least part of) the entire application.
2. Singleton mode
-
-
// The Database class represents our global DB connection
- class Database{
- // A static variable to hold our single instance
- private static $_instance = null;
-
- // Make the constructor private to ensure singleton
- private function __construct()
- {
- echo 'constructor';
- }
// A method to get our singleton instance
- public static function getInstance()
- {
- if (!(self::$_instance instanceof Database)) {
- self::$_instance = new Database();
- }
-
- return self::$_instance;
- }
- }
- var_dump($database);
-
Copy code
Problem: Two instances cannot be created using singleton mode. Traits can be used to solve the problem of creating two The problem of different types of instances, but still does not solve the problem of creating two identical instances (which can be solved by registry mode).
Create two instances of different classes Code:
-
- trait Singleton {
- private static $_instance = null;
-
- public static function getInstance() {
- $class = __CLASS__;
-
- if(!(self::$_instance instanceof $class)) {
- self::$_instance = new $class;
- }
-
- return self::$_instance;
- }
-
- }
- class DB {
- }
-
- class DBWriteConnection extends DB {
- use Singleton;
-
- private function __construct() {
- echo 'DBWriteConnection
';
- }
- }
-
- class DBReadConnection extends DB {
- use Singleton;
-
- private function __construct() {
- echo 'DBReadConnection
';
- }
- }
-
- $dbWriteConnection = DBWriteConnection::getInstance();
- var_dump($dbWriteConnection);
Copy code
3. Registry mode
The registry pattern is simply a single global class that allows code to retrieve the same instance of an object when you need it, and to create another instance when you need it (those global instances will be accessed again on request).
Registry class:
-
-
class Registry {
- /**
- * @var array The store for all of our objects
- */
- static private $_store = array();
-
- /**
- * Add an object to the registry
- *
- * If you do not specify a name the classname is used
- *
- * @param mixed $object The object to store
- * @param string $name Name used to retrieve the object
- * @return void
- * @throws Exception
- */
- static public function add($ object, $name = null)
- {
- // Use the classname if no name given, simulates singleton
- $name = (!is_null($name)) ?$name:get_class($object);
- if (isset(self ::$_store[$name])) {
- throw new Exception("Object already exists in registry");
- }
-
- self::$_store[$name]= $object;
- }
-
- /**
- * Get an object from the registry
- *
- * @param string $name Object name, {@see self::set()}
- * @return mixed
- * @throws Exception
- */
- static public function get($name)
- {
- if (!self::contains($name)) {
- throw new Exception("Object does not exist in registry");
- }
return self::$_store[$name];
- }
-
- /**
- * Check if an object is in the registry
- *
- * @param string $name Object name, {@see self::set()}
- * @return bool
- */
- static public function contains($name)
- {
- if (!isset(self::$ _store[$name])) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Remove an object from the registry
- *
- * @param string $name Object name, {@see self::set()}
- * @returns void
- */
- static public function remove($name)
- {
- if (self::contains( $name)) {
- unset(self::$_store[$name]);
- }
- }
- }
-
-
Copy code
Outside the class, use the Registry class:
-
-
require 'Registry.php';
class DBReadConnection {}
- class DBWriteConnection {}
$read = new DBReadConnection;
- Registry::add($read);
$write = new DBWriteConnection;
- Registry::add($write);
/ / To get the instances, anywhere in our code:
- $read = Registry::get('DBReadConnection');
- $write = Registry::get('DBWriteConnection');
var_dump ($read);
- var_dump($write);
-
-
Copy code
Use the Registry table class inside the class, and the user does not interact with the Registry.
Sample code:
-
-
require 'Registry.php';
abstract class DBConnection {
- static public function getInstance($name = null)
- {
- // Get the late-static-binding version of __CLASS__
- $class = get_called_class();
- // Allow passing in a name to get multiple instances
- // If you do not pass a name, it functions as a singleton
- $name = (! is_null($name)) ? $name:$class;
- if (!Registry::contains($name)) {
- $instance = new $class();
- Registry::add($instance, $name);
- }
- return Registry::get($name);
- }
- }
class DBWriteConnection extends DBConnection {
- public function __construct()
- {
- echo 'DBWriteConnection
' ;
- }
- }
class DBReadConnection extends DBConnection {
- public function __construct()
- {
- echo 'DBReadConnection
';
- }
- }
- < ;p>$dbWriteConnection = DBWriteConnection::getInstance('abc');
- var_dump($dbWriteConnection);
- $dbReadConnection = DBReadConnection::getInstance();
- var_dump($dbReadConnection);
-
Copy code
4.Factory mode
The factory pattern manufactures objects, just like its namesake steel and concrete industry. Usually, we use the factory pattern to initialize concrete implementations of the same abstract class or interface.
In general, although factory mode is rarely used, it is still the most suitable for initializing many variants of driver-based installation. For example different configurations, sessions or caching storage engines. The greatest value of the factory pattern is that it can encapsulate multiple object settings into a single, simple method call.
-
- /**
- * Log Factory
- *
- * Setup and return a file, mysql, or sqlite logger
- */
- class Log_Factory {
- /**
- * Get a log object
- *
- * @param string $type The type of logging backend, file, mysql or sqlite
- * @param array $options Log class options
- */
- public function getLog($type = 'file', array $options)
- {
- // Normalize the type to lowercase
- $type = strtolower($type);
-
- // Figure out the class name and include it
- $class = "Log_" .ucfirst($type);
- require_once str_replace('_', DIRECTORY_SEPARATOR, $ class) . '.php';
-
- // Instantiate the class and set the appropriate options
- $log = new $class($options);
- switch ($type) {
- case 'file':
- $log-> ;setPath($options['location']);
- break;
- case 'mysql':
- $log->setUser($options['username']);
- $log->setPassword($options[' password']);
- $log->setDBName($options['location']);
- break;
- case 'sqlite':
- $log->setDBPath($otions['location']);
- break ;
- }
-
- return $log;
- }
- }
Copy code
5. Iteration mode
The iteration pattern allows us to add the performance of foreach to the internally stored data of any object, not just to public properties. It overrides the default foreach behavior and allows us to inject business logic into the loop.
(1) Use Iterator interface
-
-
class BasicIterator implements Iterator {
- private $key = 0;
- private $data = array(
- "hello",
- "world",
- );
- < ;p> public function __construct() {
- $this->key = 0;
- }
public function rewind() {
- $this->key = 0;
- }< ;/p>
public function current() {
- return $this->data[$this->key];
- }
public function key() {
- return $this->key;
- }
public function next() {
- $this->key++;
- return true;
- }
return isset($this->data[$this->key]);
- }
- }
$iterator = new BasicIterator();
- $iterator->rewind();
do {
- $key = $iterator->key();
- $value = $iterator->current();
- echo $ key .': ' .$value . PHP_EOL;
- } while ($iterator->next() && $iterator->valid());
- $iterator = new BasicIterator ();
- foreach ($iterator as $key => $value) {
- echo $key .': ' .$value . PHP_EOL;
- }
-
Copy code
(2 ) Traverse the array using the RecursiveIteratorIterator iterator
-
-
$array = array(
- "Hello", // Level 1
- array(
- "World" // Level 2
- ),
- array(
- "How", // Level 2
- array(
- "are", // Level 3
- "you" // Level 3
- )
- ),
- "doing?" // Level 1
- );
$recursiveIterator = new RecursiveArrayIterator($array);
$recursiveIteratorIterator = new RecursiveIteratorIterator($recursiveIterator);
foreach ($recursiveIteratorIterator as $key => $value ) {
- echo "Depth: " . $recursiveIteratorIterator->getDepth() . PHP_EOL;
- echo "Key: " . $key . PHP_EOL;
- echo "Value: " .$value . PHP_EOL;
- }
-
Copy code
(3)用FilterIterator迭代器实现过滤
-
-
class EvenFilterIterator extends FilterIterator { - /**
- * Accept only even-keyed values
- *
- * @return bool
- */
- public function accept()
- {
- // Get the actual iterator
- $iterator = $this->getInnerIterator();
-
- // Get the current key
- $key = $iterator->key();
-
- // Check for even keys
- if ($key % 2 == 0) {
- return true;
- }
-
- return false;
- }
- }
$array = array(
- 0 => "Hello",
- 1 => "Everybody Is",
- 2 => "I'm",
- 3 => "Amazing",
- 4 => "The",
- 5 => "Who",
- 6 => "Doctor",
- 7 => "Lives"
- );
// Create an iterator from our array
- $iterator = new ArrayIterator($array);
// Create our FilterIterator
- $filterIterator = new EvenFilterIterator($iterator);
// Iterate
- foreach ($filterIterator as $key => $value) {
- echo $key .': '. $value . PHP_EOL;
- }
- ?>
-
复制代码
(4)RegexIterator迭代器
-
-
- // Create a RecursiveDirectoryIterator
- $directoryIterator = new RecursiveDirectoryIterator("./");
// Create a RecursiveIteratorIterator to recursively iterate
- $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);
// Createa filter for *Iterator*.php files
- $regexFilter = new RegexIterator($recursiveIterator, '/(.*?)Iterator(.*?).php$/');
// Iterate
- foreach ($regexFilter as $key => $file) {
- /* @var SplFileInfo $file */
- echo $file->getFilename() . PHP_EOL;
- }
-
-
复制代码
功能:找到所有的php文件
(4)LimitItertor迭代器,像SQL中的LIMIT
-
-
// Define the array
- $array = array(
- 'Hello',
- 'World',
- 'How',
- 'are',
- 'you',
- 'doing?'
- );
// Create the iterator
- $iterator = new ArrayIterator($array);
// Create the limiting iterator, to get the first 2 elements
- $limitIterator = new LimitIterator($iterator, 0, 2);
// Iterate
- foreach ($limitIterator as $key => $value) {
- echo $key .': '. $value . PHP_EOL;
- }
-
复制代码
6. Observer mode (observer)
The core of the observer pattern is that your application registers a callback, which will trigger it when a specific event occurs.
-
-
/** - * The Event Class
- *
- * With this class you can register callbacks that will
- * be called (FIFO) for a given event.
- */
- class Event {
- /**
- * @var array A multi-dimentional array of events => callbacks
- */
- static protected $callbacks = array();
-
- / **
- * Register a callback
- *
- * @param string $eventName Name of the triggering event
- * @param mixed $callback An instance of Event_Callback or a Closure
- */
- static public function registerCallback($eventName, $callback)
- {
- if (!($callback instanceof Event_Callback) && !($callback instanceof Closure)) {
- throw new Exception("Invalid callback! ");
- }
-
- $eventName = strtolower($eventName);
-
- self::$callbacks[$eventName][] = $callback;
- }
-
- /**
- * Trigger an event
- *
- * @param string $eventName Name of the event to be triggered
- * @param mixed $data The data to be sent to the callback
- */
- static public function trigger ($eventName, $data)
- {
- $eventName = strtolower($eventName);
-
- if (isset(self::$callbacks[$eventName])) {
- foreach (self::$callbacks[$eventName] as $callback) {
- self::callback($callback, $data);
- }
- }
- }
-
- /**
- * Perform the callback
- *
- * @param mixed $callback An instance of Event_Callback or a Closure
- * @param mixed $data The data sent to the callback
- */
- static protected function callback($callback, $data)
- {
- if ( $callback instanceof Closure) {
- $callback($data);
- } else {
- $callback->run($data);
- }
- }
- }
/**
- * The Event Callback interface
- *
- * If you do not wish to use a closure
- * you can define a class that extends
- * this instead. The run method will be
- * called when the event is triggered.
- */
- interface Event_Callback {
- public function run($data);
- }
/**
- * Logger callback
- */
- class LogCallback implements Event_Callback {
- public function run($data )
- {
- echo "Log Data" . PHP_EOL;
- var_dump($data);
- }
- }
// Register the log callback
- Event::registerCallback('save', new LogCallback());
// Register the clear cache callback as a closure
- Event::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
-
Copy code
7. Dependency injection mode
Dependency injection pattern allows classes to use this behavior to inject dependencies into this class.
-
-
/**
- * Log Class
- */
- class Log {
- /**
- * @var Log_Engine_Interface
- */
- protected $engine = false;
-
- /**
- * Add an event to the log
- *
- * @param string $message
- */
- public function add($message)
- {
- if (!$this->engine) {
- throw new Exception('Unable to write log. No Engine set.');
- }
-
- $data['datetime'] = time();
- $data['message'] = $message;
-
- $session = Registry::get('session');
- $data['user'] = $session->getUserId();
-
- $this->engine->add($data);
- }
-
- /**
- * Set the log data storage engine
- *
- * @param Log_Engine_Interface $Engine
- */
- public function setEngine(Log_Engine_Interface $engine)
- {
- $this->engine = $engine ;
- }
-
- /**
- * Retrieve the data storage engine
- *
- * @return Log_Engine_Interface
- */
- public function getEngine()
- {
- return $this->engine;
- }
- }
interface Log_Engine_Interface {
- /* *
- * Add an event to the log
- *
- * @param string $message
- */
- public function add(array $data);
- }
class Log_Engine_File implements Log_Engine_Interface {
- /**
- * Add an event to the log
- *
- * @param string $message
- */
- public function add(array $data )
- {
- $line = '[' .data('r', $data['datetime']). '] ' .$data['message']. ' User: ' .$data['user'] . PHP_EOL;
-
- $config = Registry::get('site-config');
-
- if (!file_put_contents($config['location'], $line, FILE_APPEND)) {
- throw new Exception("An error occurred writing to file.");
- }
- }
- }
$engine = new Log_Engine_File();
$log = new Log();
- $log->setEngine($engine);
// Add it to the registry
- Registry::add($log);
-
Copy code
Dependency injection does not require factory mode, and there is no need to understand the relevant knowledge of each different storage engine. This means that any developer using the logging class can add their own storage engine and simply compose the interface.
8. Model-View-Controller
Model-View-Controller, also known as the MVC pattern, is a way of describing the relationship between three different levels of an application.
Model-Data Layer All output data comes from the model. It may be a database, web service or file.
View-presentation layer is responsible for taking data out of the model and outputting it to the user.
The controller-application flow layer calls the corresponding model according to the user's request to retrieve the requested data, and then calls the view to display the results of the operation to the user.
A typical MVC architecture diagram:
9. Understanding of patterns Patterns are the best solutions to many common problems.
Articles you may be interested in:
- php design patterns: singleton mode, factory mode and observer mode
- In-depth explanation of PHP design pattern examples
- php design pattern example command pattern
- php design pattern example observer pattern (2)
- PHP Design Pattern Example Observer Pattern
- php design pattern example factory pattern
- php design pattern example singleton pattern
- Example of Observer pattern in PHP design pattern
- PHP design pattern factory pattern example code
- PHP design pattern singleton pattern example code
- Introduction to common PHP design patterns: factory pattern and singleton pattern
- Learn PHP design pattern singleton pattern
- Study notes on three commonly used design patterns in PHP
- Learning the Singleton Pattern of PHP Design Pattern
|