Ich habe kürzlich darüber geschrieben, wie man das Designmuster bricht - Singleton in PHP . Nachdem ich den Artikel geschrieben hatte, suchte ich nach einer neuen Version der Implementierung des Musters: Gibt es eine Möglichkeit, Singleton in PHP zu erstellen, ohne die Möglichkeit zu geben, neue Instanzen der Klasse mit Closure::bind()
zu erstellen?

Ich habe mir viele verschiedene Optionen ausgedacht, aber auch Wege gefunden, um sie zu umgehen. Es schien mir, dass es nicht möglich sein würde, eine neue Implementierung zu erstellen, aber eine Idee kam auf und ich fing an, sie zu testen.
Hier in der Tat der Code und der Link zur Sandbox . Nehmen wir es auseinander:
<?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);
Wir übertragen die statische Variable $instance
an die Methode getInstance()
, sodass wir nicht mit den Operatoren self
und static
in der anonymen Funktion darauf zugreifen können.
Im Klassenkonstruktor fügen wir außerdem eine statische Variable hinzu, die einen booleschen Wert speichert. Beim Erstellen eines neuen Objekts überprüfen wir den Wert dieser Variablen: Wenn dort false
gespeichert ist, setzen wir diese Variable auf true
und das Objekt wird erfolgreich erstellt. Beim Versuch, ein neues Objekt zu erstellen, fällt der Code in if
, da beim Erstellen des ersten Objekts true
in die statische Variable $hasInstance
, dann im if
'body, und wir verursachen einen Benutzerfehler, da die Textklasse Class is already instantiated
.
In den magischen Methoden __clone()
und __wakeup()
verursachen wir auch Benutzerfehler mit den entsprechenden Nachrichten, um keine Objekte mit dem clone
und dem Serialisierungsmechanismus in einer anonymen Funktion erstellen zu können.
Bei Bedarf können Sie Ausnahmen anstelle von Benutzerfehlern auslösen.
Somit ist es möglich, nur ein Singleton-Objekt der Klasse zu erstellen. Bisher habe ich keinen Weg gefunden, diese Implementierung des Musters zu brechen. Wenn also jemand dazu in der Lage ist, schreibe darüber im Kommentar :)
Vielen Dank für Ihre Aufmerksamkeit!