ホームページ  >  記事  >  バックエンド開発  >  php エッセンス php デザイン パターン

php エッセンス php デザイン パターン

WBOY
WBOYオリジナル
2016-07-25 09:13:12876ブラウズ

1. 最適なデザインパターンを選択します

完璧なものはなく、デザインパターンが厳密に万能の解決策であるとは誰も言っていません。したがって、これらのモードを変更して、現在の作業により適したものにすることができます。一部のデザイン パターンは、そのパターンが属するプログラムに固有のものですが、他のデザイン パターンでは、パターン自体を変更できます。モードが連携して動作するのは一般的です。これらはアプリケーション全体 (の少なくとも一部) の基礎を形成します。

2. シングルトンモード

  1. // Database クラスはグローバル DB 接続を表します

  2. class Database{
  3. // 単一のインスタンスを保持する静的変数
  4. private static $_instance = null;
  5. // constructor private to ensure singleton
  6. private function __construct()
  7. {
  8. echo 'constructor';
  9. }

  10. // シングルトン インスタンスを取得するメソッド

  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. var_dump($database);

コードをコピー

問題: シングルトン モードを使用して 2 つのインスタンスを作成できない2 つのインスタンスの作成の問題 異なるタイプのインスタンスの問題ですが、2 つの同一のインスタンスの作成の問題はまだ解決されていません (レジストリ モードで解決できます)。

異なるクラスの 2 つのインスタンスを作成する コード:

  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. レジストリモード レジストリ パターンは、必要なときにコードでオブジェクトの同じインスタンスを取得し、必要なときに別のインスタンスを作成できるようにする単一のグローバル クラスです (これらのグローバル インスタンスは要求に応じて再度アクセスされます)。

レジストリクラス:

  1. class Registry {

  2. /**
  3. * @var array すべてのオブジェクトのストア
  4. */
  5. static private $_store = array();
  6. /**
  7. * オブジェクトをレジストリに追加します
  8. *
  9. * 名前を指定しない場合は、クラス名が使用されます
  10. *
  11. * @parammixed $object 保存するオブジェクト
  12. * @param string $name オブジェクトの取得に使用される名前
  13. * @return void
  14. * @throws 例外
  15. */
  16. static public function add($ object, $name = null)
  17. {
  18. // 名前が指定されていない場合はクラス名を使用し、シングルトンをシミュレートします
  19. $name = (!is_null($name)) ?$name:get_class($object);
  20. if (isset(self) ::$_store[$name])) {
  21. throw new Exception("オブジェクトは既にレジストリに存在します");
  22. }
  23. self::$_store[$name]= $object;
  24. }
  25. /**
  26. * レジストリからオブジェクトを取得します
  27. *
  28. * @param string $name オブジェクト名、{@self::set() を参照}
  29. * @returnmixed
  30. * @throws Exception
  31. */
  32. static public function get($name)
  33. {
  34. if (!self::contains($name)) {
  35. throw new Exception("オブジェクトがレジストリに存在しません");
  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 オブジェクト名、{@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. / / インスタンスを取得するには、コード内の任意の場所で次のようにします:

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

  11. var_dump ($read);

  12. var_dump($write);
コードをコピー
クラス内でレジストリ テーブル クラスを使用すると、ユーザーはレジストリと対話しません。

サンプルコード:

  1. require 'Registry.php';

  2. abstract class DBConnection {

  3. static public function getInstance($name = null)
  4. {
  5. // を取得late-static-binding バージョンの __CLASS__
  6. $class = get_called_class();
  7. // 名前を渡して複数のインスタンスを取得できるようにします
  8. // 名前を渡さない場合は、シングルトンとして機能します
  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. < ;p>$dbWriteConnection = DBWriteConnection::getInstance('abc');
  30. var_dump($dbWriteConnection);
  31. $dbReadConnection = DBReadConnection::getInstance();
  32. var_dump($dbReadConnection);

コードをコピー

4.ファクトリーモード 工場パターンは、その名の由来である鉄鋼およびコンクリート産業と同じように、物体を製造します。通常、ファクトリ パターンを使用して、同じ抽象クラスまたはインターフェイスの具象実装を初期化します。

一般に、ファクトリー モードが使用されることはほとんどありませんが、ドライバー ベースのインストールの多くのバリアントを初期化するのに最適です。たとえば、さまざまな構成、セッション、キャッシュストレージエンジンなどです。ファクトリ パターンの最大の価値は、複数のオブジェクト設定を 1 つの単純なメソッド呼び出しにカプセル化できることです。

  1. /**
  2. * Log Factory
  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 getLog($type = 'file', array $options)
  14. {
  15. // を正規化しますtype を小文字に変換します
  16. $type = strto lower($type);
  17. // クラス名を調べてそれを含めます
  18. $class = "Log_" .ucfirst($type);
  19. require_once str_replace('_', DIRECTORY_SEPARATOR, $ class) . '.php';
  20. // クラスをインスタンス化し、適切なオプションを設定します
  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['パスワード']);
  29. $log->setDBName($options['location']);
  30. ブレーク;
  31. case 'sqlite':
  32. $log->setDBPath($otions['location']);
  33. ブレーク;
  34. }
  35. return $log;
  36. }
  37. }
コードをコピー

5. 反復パターンを使用すると、パブリック プロパティだけでなく、任意のオブジェクトの内部に保存されたデータに foreach のパフォーマンスを追加できます。これにより、デフォルトの foreach 動作がオーバーライドされ、ビジネス ロジックをループに挿入できるようになります。

(1) Iteratorインターフェースを使用する

  1. class BasicIterator は Iterator {

  2. private $key = 0;
  3. private $data = array(
  4. "hello",
  5. "world",
  6. ); を実装します。 ;p> パブリック関数 __construct() {
  7. $this->key = 0;
  8. }

  9. パブリック関数 rewind() {

  10. $this->key = 0;
  11. }< ;/p>
  12. public function current() {

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

  15. return $this->key;
  16. }

  17. public function next() {

  18. $this->key++;
  19. return true;
  20. }

  21. return isset($this->data[$this->key]);
  22. }
  23. }

  24. $ite​​rator = new BasicIterator();

  25. $iterator->rewind();

  26. do {

  27. $key = $iterator->key();
  28. $value = $iterator->current();
  29. echo $ key .': ' .$value .PHP_EOL;
  30. } while ($iterator->next() && $iterator->valid());
  31. $iterator = new BasicIterator ();
  32. foreach ($iterator as $key => $value) {
  33. echo $key .': ' .$value ;
  34. }

コードをコピー
(2) ) RecursiveIteratorIterator イテレータを使用して配列を走査します。

  1. $array = array(

  2. "こんにちは", // レベル 1
  3. array(
  4. "世界" // レベル 2
  5. ),
  6. array(
  7. "どうやって", // レベル2
  8. array(
  9. "are", // レベル 3
  10. "あなた" // レベル 3
  11. )
  12. ),
  13. "やっている?" // レベル 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 .$value . ;
  20. コードをコピー

(3)用FilterIterator迭代器实现过滤

  1. class EvenFilterIterator extends FilterIterator {

  2. /**
  3. * 偶数キーの値のみを受け入れます
  4. *
  5. * @return bool
  6. */
  7. public function accept()
  8. {
  9. // 実際のイテレータを取得します
  10. $iterator = $ this->getInnerIterator();
  11. // 現在のキーを取得します
  12. $key = $iterator->key();
  13. // 偶数キーをチェックします
  14. if ($key % 2 == 0) {
  15. return true;
  16. }
  17. return false;
  18. }
  19. }

  20. $array = array(

  21. 0 => "こんにちは",
  22. 1 => "みんなです",
  23. 2 =>「私は」、
  24. 3 =>「すごい」、
  25. 5 =>「博士」、
  26. 7 => "Lives"
  27. );

  28. // 配列からイテレータを作成します

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

  30. // FilterIterator を作成します

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

  32. // Iterate

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

复制代码
(4)RegexIterator迭代器

  1. &lt; p&gt;&lt;?php
  2. // recursivedirectoryiteratorを作成します$ directoryiterator = new recursivedirectoryiterator( "./" );&lt;/p&gt;再帰的に反復
  3. $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);

  4. // *Iterator*.php ファイルのフィルターを作成します

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

  6. // Iterate

  7. foreach ($regexFilter as $key => $file) {
  8. /* @var SplFileInfo $file */
  9. echo $file->getFilename() 。 PHP_EOL;
  10. }
  11. 复制代
機能:找到全部的php文件 (4)LimitItertor代器、画像SQL内のLIMIT

// 配列を定義します

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

  8. // イテレータを作成します

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

  10. // 取得するための制限イテレータを作成します最初の 2 つの要素

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

  12. // Iterate

  13. foreach ($limitIterator as $key => $value) {
  14. echo $鍵 。': '。 $value 。 PHP_EOL;
  15. }

  16. 复制代

6. オブザーバーモード(オブザーバー)

オブザーバー パターンの中核は、アプリケーションがコールバックを登録し、特定のイベントが発生したときにコールバックをトリガーすることです。

  1. /**

  2. * イベント クラス
  3. *
  4. * このクラスを使用すると、
  5. * 特定のイベントに対して呼び出される (FIFO)
  6. コールバックを登録できます。*/
  7. class Event {
  8. /**
  9. * @var array イベントの多次元配列 =>コールバック
  10. */
  11. static protected $callbacks = array();
  12. / **
  13. * コールバックを登録します
  14. *
  15. * @param string $eventName トリガーとなるイベントの名前
  16. * @parammixed $callback Event_Callback または Closure のインスタンス
  17. */
  18. static public function registerCallback($eventName, $callback)
  19. {
  20. if (!($callbackinstanceof Event_Callback) && !($callbackinstanceof Closure)) {
  21. throw new Exception("無効なコールバック! ");
  22. }
  23. $eventName = strto lower($eventName);
  24. self::$callbacks[$eventName][] = $callback;
  25. }
  26. /**
  27. * イベントをトリガーします
  28. *
  29. * @param string $eventName トリガーされるイベントの名前
  30. * @parammixed $data コールバックに送信されるデータ
  31. */
  32. 静的パブリック関数トリガー($eventName, $data)
  33. {
  34. $eventName = strto lower($eventName);
  35. if (isset(self::$callbacks[$eventName])) {
  36. foreach (self::$callbacks[$eventName] as $callback) {
  37. self::callback($callback, $data);
  38. }
  39. }
  40. }
  41. /**
  42. * コールバックを実行します
  43. *
  44. * @parammixed$callback Event_CallbackまたはClosureのインスタンス
  45. * @parammixed$data コールバックに送信されるデータ
  46. */
  47. 静的保護関数 callback($callback, $data)
  48. {
  49. if ( $callback instanceof Closure) {
  50. $callback($data);
  51. } else {
  52. $callback->run($data);
  53. }
  54. }
  55. }

  56. /**

  57. * イベント コールバック インターフェイス
  58. *
  59. * クロージャを使用したくない場合
  60. * 代わりに、これを拡張するクラスを定義できます
  61. *。 run メソッドは
  62. * イベントがトリガーされると呼び出されます。
  63. */
  64. interface Event_Callback {
  65. public function run($data);
  66. }

  67. /**

  68. * ロガーコールバック
  69. */
  70. class LogCallbackimplemented Event_Callback {
  71. public function run($data) )
  72. {
  73. echo "ログ データ" .
  74. var_dump($data);
  75. }
  76. }

  77. // ログ コールバックを登録します

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

  79. // キャッシュクリアコールバックをクロージャとして登録

  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. // データを保存します
  88. // 保存イベントをトリガーします
  89. Event::trigger ('save', array("Hello", "World"));
  90. }
  91. }

  92. // 新しいデータ レコードをインスタンス化します

  93. $data = new MyDataRecord();
  94. $data ->save(); // ここで「save」イベントがトリガーされます

コードをコピーします

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('ログを書き込めません。エンジンが設定されていません。');
  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 は 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'] ' ユーザー: ' .$data['user'] . PHP_EOL;
  61. $config = Registry::get('site-config');
  62. if (!file_put_contents($config['location'], $line, FILE_APPEND)) {
  63. throw new Exception("エラーファイルへの書き込みが発生しました。");
  64. }
  65. }
  66. }

  67. $engine = new Log_Engine_File();

  68. $log = new Log();

  69. $log->setEngine($engine);

  70. // レジストリに追加します

  71. Registry::add($log);

コードをコピー

依存関係の注入にはファクトリーモードは必要なく、さまざまなストレージエンジンごとに関連する知識を理解する必要もありません。つまり、ロギング クラスを使用する開発者は、独自のストレージ エンジンを追加して、インターフェイスを簡単に作成できます。

8. モデルビューコントローラー MVC パターンとしても知られる Model-View-Controller は、アプリケーションの 3 つの異なるレベル間の関係を記述する方法です。 モデル データ層 すべての出力データはモデルから取得されます。それはデータベース、Web サービス、またはファイルである可能性があります。 ビュー プレゼンテーション層は、モデルからデータを取り出してユーザーに出力する役割を果たします。 コントローラー アプリケーション フロー層は、ユーザーの要求に従って対応するモデルを呼び出して要求されたデータを取得し、ビューを呼び出して操作の結果をユーザーに表示します。

典型的な MVC アーキテクチャ図: php mvc架构图

9. パターンの理解
パターンは、多くの一般的な問題に対する最良の解決策です。

興味があるかもしれない記事:

  • php デザイン パターン: シングルトン モード、ファクトリー モード、オブザーバー モード
  • PHPのデザインパターン例を徹底解説
  • phpデザインパターンのサンプルコマンドパターン
  • phpデザインパターン例 オブザーバーパターン(2)
  • PHP デザイン パターンのサンプル オブザーバー パターン
  • phpデザインパターンサンプルファクトリーパターン
  • phpデザインパターンのサンプルシングルトンパターン
  • PHPデザインパターンのObserverパターンの例
  • PHP デザイン パターン ファクトリ パターンのサンプル コード
  • PHPデザインパターンシングルトンパターンサンプルコード
  • PHP共通デザインパターンのファクトリパターンとシングルトンパターンの紹介
  • PHPデザインパターンシングルトンパターンを学ぶ
  • PHP でよく使用される 3 つのデザイン パターンについての学習メモ
  • PHPデザインパターンのシングルトンパターンを学ぶ


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。