シングルトンおよび後期静的バインディング

プロジェクト内のシングルトンの数は、多くの場合、その複雑さとサイズに正比例します。 当然のことながら、プライベートコンストラクター、オブジェクトの静的プロパティ、および有形の任意の数のクラスに対してそれを取得する方法を記述するのは少し面倒であり、おそらく間違っています。 これは、シングルトンの実装をどのように「破壊」するかという疑問を招きます。

私の意見ではいくつかの選択肢があるかもしれません。 1つは、アプリケーションアーキテクチャを修正することです。 特定のコレクションにシングルトンであると主張するすべてのオブジェクトを登録し、それを介して排他的にアクセスする方が簡単な場合があります。 これにより、誤ってオブジェクトの2つのコピーを作成することを回避できます。 ただし、特定の時点でのアプリケーションにはオブジェクトのコピーが1つしかないと言うのは安全です。このシナリオでは、コレクションをバイパスしてオブジェクトを直接作成することは誰にも干渉できないため、不可能です。

2番目の方法は、すべてのシングルトンクラスが継承するシングルトンスーパークラスを実装することです。 ただし、PHPでの実装には1つの落とし穴があります。静的メソッドでの遅延/動的バインディングです。 より正確には、静的getInstanceメソッドでの現在のクラスの名前の定義。
get_classメソッドなどの標準ツールはここでは使用できません。実際にはオブジェクトがまだないためです。 リフレクションが思い浮かびますが、それとは何の関係もないことにすぐに気付きます。なぜなら、その出発点はオブジェクトの名前であり、実際にそれを見つけようとしているからです。
そしてここでは、バージョン5.3.0以降で利用可能な「遅延静的バインディング」と呼ばれるメカニズムが役立ちます。 その本質は、静的継承のコンテキストで呼び出されたクラスを参照する機能です。 つまり、バージョン5.3.0以降では、 get_called_class関数を使用して、静的メソッドの一部として呼び出されたクラスの名前を取得できます。

上記を知っていれば、シングルトンテンプレートを実装するためのスーパークラスを簡単に作成できます。

/** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  1. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  2. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  3. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  4. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  5. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  6. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  7. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  8. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  9. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  10. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  11. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  12. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  13. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  14. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  15. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  16. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  17. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  18. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  19. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  20. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  21. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  22. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  23. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  24. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  25. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  26. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  27. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  28. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  29. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
  30. /** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .
/** * Singleton pattern implementation */ abstract class Singleton { /** * Collection of instances * @var array */ private static $_aInstance = array(); /** * Private constructor */ private function __construct(){} /** * Get instance of class */ public static function getInstance() { // Get name of current class $sClassName = get_called_class(); // Create new instance if necessary if ( !isset( self::$_aInstance[ $sClassName ] ) ) self::$_aInstance[ $sClassName ] = new $sClassName(); $oInstance = self::$_aInstance[ $sClassName ]; return $oInstance; } /** * Private final clone method */ final private function __clone(){} } * This source code was highlighted with Source Code Highlighter .


ちょっとしたテストでコードを完成させましょう

  1. class Exampleはシングルトンを拡張します{}
  2. $ oExample1 =例:: getInstance();
  3. $ oExample2 =例:: getInstance();
  4. echo(is_a($ oExample1、 'Example' )&& $ oExample1 === $ oExample2)
  5. '同じ''異なる'"\ n" ;
*このソースコードは、 ソースコードハイライターで強調表示されました。


その結果は、「同じ」と推測します。

debug_backtraceメソッドを使用して呼び出しスタックを分析することにより、5.3.0より前のPHPバージョンの静的関数のコンテキストで呼び出されたクラスの名前を取得するメカニズムがあることに注意してください 。 しかし、私の意見では、このアプローチは完全にやや直腸に近いものです。

PS
この場合、継承は最良のメカニズムではないことに同意します。 私の意見では、PHPがアノテーションとAOPをサポートしていれば、 Singletonアノテーションでクラスをマークし、マークされたクラスにシングルトンを実装するために必要なコードを注入するアスペクトを実装する方がはるかに便利です。 ただし、私が知る限り、PHPでのアノテーション(言語構成要素として)もAOPも近い将来計画されていません。

Source: https://habr.com/ru/post/J85852/


All Articles