J'ai récemment écrit sur la façon de briser le modèle de conception - Singleton en PHP . Après avoir écrit l'article, je cherchais une nouvelle version de l'implémentation du modèle: existe-t-il un moyen de créer Singleton en PHP sans donner la possibilité de créer de nouvelles instances de la classe en utilisant Closure::bind()
?

J'ai proposé de nombreuses options différentes, mais j'ai également trouvé des moyens de les contourner. Il me semblait déjà qu'il ne serait pas possible de créer une nouvelle implémentation, mais une idée est venue et j'ai commencé à la tester.
Ici, en fait, le code et le lien vers le bac à sable . Prenons-le à part:
<?php final class Singleton { public static function getInstance() { static $instance; if (null === $instance) { $instance = new self(); } return $instance; } private function __construct() { static $hasInstance = false; if ($hasInstance) { \trigger_error('Class is already instantiated', \E_USER_ERROR); } $hasInstance = true; } private function __clone() { \trigger_error('Class could not be cloned', \E_USER_ERROR); } private function __wakeup() { \trigger_error('Class could not be deserialized', \E_USER_ERROR); } } $s1 = Singleton::getInstance(); \var_dump(\spl_object_id($s1)); $createNewInstance = function () { return new self(); }; $newInstanceClosure = Closure::bind($createNewInstance, $s1, Singleton::class);
nous transférons la variable statique $instance
à la méthode getInstance()
afin que nous ne puissions pas y accéder en utilisant les opérateurs self
et static
dans la fonction anonyme.
Dans le constructeur de classe, nous ajoutons également une variable statique qui stocke une valeur booléenne. Lors de la création d'un nouvel objet, nous vérifions la valeur de cette variable: si false
est stocké, nous définissons cette variable sur true
et l'objet est créé avec succès. Lorsque vous essayez de créer un nouvel objet, le code tombera dans if
, car lors de la création du premier objet, nous avons écrit true
à la variable statique $hasInstance
, puis dans le corps if
', et nous provoquerons une erreur utilisateur avec le texte La Class is already instantiated
.
Dans les méthodes magiques __clone()
et __wakeup()
nous __wakeup()
également des erreurs utilisateur avec les messages correspondants afin de ne pas pouvoir créer d'objets en utilisant l'opérateur clone
et le mécanisme de sérialisation dans une fonction anonyme.
Si vous le souhaitez, vous pouvez lever des exceptions au lieu d'erreurs utilisateur.
Ainsi, il est possible de créer un seul objet Singleton de la classe. Jusqu'à présent, je n'ai pas trouvé de moyen de rompre cette implémentation du modèle, donc si quelqu'un peut le faire, écrivez-le dans le commentaire :)
Merci de votre attention!