📜 ⬆️ ⬇️

Fix design pattern - Singleton in PHP

I recently wrote about how to break a design pattern - Singleton in PHP . After writing the article, I was looking for a new version of the pattern implementation: is there a way to create a Singleton in PHP, preventing the creation of new classes with the help of Closure::bind() ?


How to fix Singleton in PHP


I came up with many different options, but I also found ways to get around them. I already thought that it would not be possible to create a new implementation, but an idea came and I began to check it.


Here, in fact, the code and link to the sandbox . Let's sort it out:


 <?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); // Fatal error: Class is already instantiated $newInstanceClosure(); 

We transfer the static variable $instance to the getInstance() method so that we cannot access it using the self and static operators in the anonymous function.


In the class constructor, we also add a static variable that stores a boolean value. When creating a new object, we check the value of this variable: if false is stored there, we set this variable to true and the object is successfully created. When trying to create a new object, the code will go into the if , because when creating the first object we wrote the value true to the static variable $hasInstance , then in the body of if 'and we will cause a custom error with the text Class is already instantiated .


In the __clone() and __wakeup() magic methods, we also cause user errors with appropriate messages in order to be unable to create objects using the clone operator and the serialization mechanism in an anonymous function.


If you wish, you can throw exceptions instead of custom errors.


Thus it is possible to create only one class Singleton object. So far, I have not found a way to break this implementation of the pattern, so if someone can do it - write about it in the comment :)


Thanks for attention!


')

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


All Articles