Php что такое singleton

Design Patterns in PHP 8: Singleton & Multiton

Hello, fellow developers!🧑🏼‍💻 I want to talk about design patterns in php in the few next articles. And I really like how the language is progressing that’s why I’ll make examples with the last innovations of php 8.

Singleton

Sometimes we need only one instance of some a class in different code places. For example, when we make a web application, usually it needs to connect to the database and it will be a really good idea to create just one copy of the connection and use it in every file, class, function. The pattern that will help us with this — Singleton, is one of the most popular and easiest design patterns. Let’s see how we can implement classes a database connection and logging with one instance in all objects:

class Singleton  protected static self|null $instance = null; final private function __construct()<> final protected function __clone()<> final protected function __wakeup()<> public static function getInstance(): static  if (static::$instance === null)  static::$instance = new static; > return static::$instance; > > class Database extends Singleton  public function connect()  // . > > class Logger extends Singleton  private $connection; public function settings($connection = null)  $this->connection = $connection ?? '/var/logs/filename.log'; > public function error(string $message)  // . > public function warn(string $message)  // . > > 

Now we’ll use a logger with writing logs in a database table. For that, we need a connection to the db and set it by the settings method:

$db = Database::getInstance(); $db->connect(); $logger = Logger::getInstance(); $logger->settings($db); $logger->error('Something wrong'); 

Multiton

But what if we need more than just one instance of a logger because some messages must be written in a file, some need to be send by email? Or we can have other reasons. For that, we’ll use the Multiton pattern. Multiton looks really resembling the previous pattern but with an array of instances of a class.

class Multiton  protected static array|null $instance = null; final private function __construct()<> final protected function __clone()<> final protected function __wakeup()<> public static function getInstance(int|string $key): self  if (!array_key_exists($key, self::$instance))  self::$instance[$key] = new self; > return self::$instance[$key]; > > class Logger extends Multiton  private array $settings; public function setSettings(array $settings)  // . > public function error(string $message)  // . > public function warn(string $message)  // . > > 

Let’s make two loggers with different settings for saving logs into files and database. I won’t describe the setter of settings and writer to file/database in details cause it isn’t important for the pattern.

$fileLogger = Logger::getInstance('file'); $fileLogger->setSettings([ //. ]); $fileLogger->error('Error text'); $dbLogger = Logger::getInstance('database'); $dbLogger->setSettings([ //. ]); $dbLogger->error('Error will write in Database'); 

P.S. If you found this article helpful and want to dive deeper into design patterns in PHP and TypeScript, I have some exciting news for you! I’m currently writing a book that extensively covers these topics. It’s packed with practical examples, clear explanations, and real-world scenarios where these patterns can be applied. The book is designed to help both beginners and experienced developers gain a solid understanding of design patterns and how to implement them in PHP and TypeScript. Whether you’re looking to brush up on your knowledge or learn something new, this book has got you covered. You can subscribe to my blog on dev.to and then you will receive a notification as soon as the book is ready. I can’t wait for you to read it and take your coding skills to the next level!

Источник

The singleton pattern::the good, the bad, and the ugly

We use the singleton pattern in order to restrict the number of instances that can be created from a resource consuming class to only one.

Resource consuming classes are classes that might slow down our website or cost money. For example:

  • Some external service providers (APIs) charge money per each use.
  • Some classes that detect mobile devices might slow down our website.
  • Establishing a connection with a database is time consuming and slows down our app.

So, in all of these cases, it is a good idea to restrict the number of objects that we create from the expensive class to only one.

The singleton design pattern in PHP explained

Use a singleton pattern to restrict the number of objects to only one!

The anatomy of a singleton pattern

Let’s start by understanding the structural characteristics of a class that obeys the singleton pattern:

  1. A private constructor is used to prevent the direct creation of objects from the class.
  2. The expensive process is performed within the private constructor.
  3. The only way to create an instance from the class is by using a static method that creates the object only if it wasn’t already created.
// General singleton class. class Singleton < // Hold the class instance. private static $instance = null; // The constructor is private // to prevent initiation with outer code. private function __construct() < // The expensive process (e.g.,db connection) goes here. > // The object is created from within the class itself // only if the class has no instance. public static function getInstance() < if (self::$instance == null) < self::$instance = new Singleton(); > return self::$instance; > > 

Why is it a singleton?

Since we restrict the number of objects that can be created from a class to only one, we end up with all the variables pointing to the same, single object.

// All the variables point to the same object. $object1 = Singleton::getInstance(); $object2 = Singleton::getInstance(); $object3 = Singleton::getInstance();

Comparison between the singleton design pattern and a conventional implementation.

Practical example::database class

Let’s demonstrate the singleton pattern with a class that establishes a database connection, and restricts the number of instances to only one.

// Singleton to connect db. class ConnectDb < // Hold the class instance. private static $instance = null; private $conn; private $host = 'localhost'; private $user = 'db user-name'; private $pass = 'db password'; private $name = 'db name'; // The db connection is established in the private constructor. private function __construct() < $this->conn = new PDO("mysql:host=host>; dbname=name>", $this->user,$this->pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'")); > public static function getInstance() < if(!self::$instance) < self::$instance = new ConnectDb(); > return self::$instance; > public function getConnection() < return $this->conn; > >

Since we use a class that checks if a connection already exists before it establishes a new one, it really doesn’t matter how many times we create a new object out of the class, we still get the same connection. To prove the point, let’s create three instances out of the class and var dump them.

$instance = ConnectDb::getInstance(); $conn = $instance->getConnection(); var_dump($conn); $instance = ConnectDb::getInstance(); $conn = $instance->getConnection(); var_dump($conn); $instance = ConnectDb::getInstance(); $conn = $instance->getConnection(); var_dump($conn);

The result is the same connection for the three instances.

Class that doesn’t use a singleton to contact the database

To understand the problem that the singleton pattern solves, let’s consider the following class that has no mechanism to check if a connection already exists before it establishes a new connection.

// Connect db without a singleton. class ConnectDbWOSingleton < private $conn; private $host = 'localhost'; private $user = 'db user-name'; private $pass = 'db password'; private $name = 'db name'; // Public constructor. public function __construct() < $this->conn = new PDO("mysql:host=host>; dbname=name>", $this->user,$this->pass, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'")); > public function getConnection() < return $this->conn; > >

Now, each time we create a new object, we also establish a new database connection.

$instance = new ConnectDbWOSingleton(); $conn = $instance->getConnection(); var_dump($conn); $instance = new ConnectDbWOSingleton(); $conn = $instance->getConnection(); var_dump($conn); $instance = new ConnectDbWOSingleton(); $conn = $instance->getConnection(); var_dump($conn);

This has implications for slowing down the system because each new connection with the database costs time.

I encourage you to run the code to see the result for yourself.

The singleton pattern::the good, the bad, and the ugly

The singleton pattern is probably the most infamous pattern to exist, and is considered an anti-pattern because it creates global variables that can be accessed and changed from anywhere in the code.

Yet, The use of the singleton pattern is justified in those cases where we want to restrict the number of instances that we create from a class in order to save the system resources. Such cases include data base connections as well as external APIs that devour our system resources.

Joseph Benharosh web developer

Joseph Benharosh is a full stack web developer and the author of the eBook The essentials of object oriented PHP.

Источник

Читайте также:  Метод pop python словарь
Оцените статью