デザインパターンを破る-PHPのシングルトン

ある晴れた日、私は自分が働いているプロジェクトのビジネスロジックの単体テストを書きました。 私の仕事は、クラスのいくつかのプライベートプロパティを特定の値で初期化することでした。







いくつかのロジックが記述されているため、通常のセッターは使用できませんでした。 クラスがfinalとして宣言されているため、クラスの継承またはロックアップも失敗しました。 そして、反射さえ適合しませんでした。 そこで、この問題の解決策を探し始めました。







dg / bypass-finalsライブラリを使用して最終クラスをロックする方法を説明する興味深い記事を見つけました。 私はこのオプションが好きで、それを実装しようとしました。 残念ながら、プロジェクトはPHPUnitの古いバージョンを使用しているため、成功しませんでした。







振り返って、私はClosure



クラス、特にクラスの目的のオブジェクトのコンテキストで匿名関数を実装できる静的bind()



メソッドについて思い出しました。 これに関する詳細は、 公式文書に記載されています 。 したがって、テストで使用した特性を作成しました(誰かが役に立つかもしれません)







 trait PrivatePropertySetterTrait { protected function assignValue($object, string $attribute, $value) { $setter = function ($value) use ($attribute) { $this->$attribute = $value; }; $setterClosure = \Closure::bind($setter, $object, \get_class($object)); $setterClosure($value); } }
      
      





この特性は、クラスオブジェクト、値を設定するプロパティの名前、および実際には値自体を取ります。 次に、単純な匿名関数が宣言されます。 $this



関数は、 $this



ポインターを使用して、結果の値をクラスプロパティに割り当てます。 戦いにさらにClosure



でいるのは、静的bind()



メソッドを持つClosure



クラスです。 このメソッドは、クラスオブジェクト、上記の匿名関数、およびクラスのフルネームを受け入れます。 したがって、匿名関数はオブジェクトのコンテキストに埋め込まれ、 bind()



メソッドはClosure



クラスのオブジェクトを返します。これは、魔法の__invoke()



メソッドを定義するため、通常の関数として呼び出すことができます。 そして出来上がり!







結局、私はなんとか問題を解決することができ、それからシングルトンのデザインパターンを思い出しました。 同じ方法で、新しいクラスオブジェクトを作成する匿名関数を実装することは可能でしょうか? もちろん、チェックしに行きました!







小さなコードを書くことにより







コード付きサンドボックス


 <?php final class Singleton { private static $instance; public static function getInstance() { if (null === self::$instance) { self::$instance = new self(); } return self::$instance; } private function __construct() { } private function __clone() { } private function __wakeup() { } } $s1 = Singleton::getInstance(); \var_dump(\spl_object_id($s1)); $createNewInstance = function () { return new self(); }; $newInstanceClosure = Closure::bind($createNewInstance, $s1, Singleton::class); $s2 = $newInstanceClosure(); \var_dump(\spl_object_id($s2));
      
      





同じ原理で機能しますが、クラスプロパティに値を割り当てる代わりに、 new



演算子を使用してnew



オブジェクトが作成されます。 \spl_object_id()



関数は、オブジェクトの一意の識別子を返します。 この機能の詳細については、 ドキュメントを参照してくださいspl_object_id()



およびvar_dump()



を使用して、オブジェクトの一意の識別子を取得しvar_dump()



それらの違いを確認します! 私はまだこの理論を確認し、シングルトンクラスの新しいインスタンスを作成することができました!







この記事では、非常に興味深い発見をPHPコミュニティと共有したいと考えました。







ご清聴ありがとうございました!








All Articles