1 Technique of Using PHP Singleton Class with Traits That You Might find Useful!

A brief introduction

A singleton class is a common design pattern technique to prevent multiple instantiations of an object. It does by making the __construct method private or protected, causing the class to be restricted from initializing with the new keyword. The magic method __clone used for cloning the class is also defined as protected, so the object is restricted from being cloned. The __wakeup method is also implemented to throw an Exception to prevent serializing.

Common Singleton Use Case

A common use case for a Single class is a DB class where only one instance of a class is needed in the lifecycle of an application. An example implementation of a Singleton class can be found below. The example below is taken from the Refactoring Guru website.

class Singleton
{
    
    private static $instances = [];

    protected function __construct() { }
    protected function __clone() { }
    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize a singleton.");
    }

    public static function getInstance()
    {
        $cls = static::class;
        if (!isset(self::$instances[$cls])) {
            self::$instances[$cls] = new static();
        }

        return self::$instances[$cls];
    }

    public function someBusinessLogic()
    {
        // ...
    }
}

To use this class, we’ll have to call the static method getInstance:

$instance = MyClass::getInstance();

This will always return the same instance of MyClass throughout the lifetime of the program.

To create another singleton class (e.g. DB), you’ll need to copy the example class above and get a singleton class. You can modify the example class and add methods according to your requirements.

Implementing PHP Singleton Class with Traits

Another technique is to use Traits. According to PHP documentation:

Traits are a mechanism for code reuse in single inheritance languages such as PHP

– https://www.php.net/manual/en/language.oop5.traits.php

A sample implementation would be:

trait Singleton
{
    
    private static $instances = [];

    protected function __construct() { }
    protected function __clone() { }
    public function __wakeup()
    {
        throw new \Exception("Cannot unserialize a singleton.");
    }

    public static function getInstance()
    {
        $cls = static::class;
        if (!isset(self::$instances[$cls])) {
            self::$instances[$cls] = new static();
        }

        return self::$instances[$cls];
    }
}

We replaced the class keyword with a trait keyword and removed the method “someBusinessLogic” because we no longer need that.

Now, we can use a Trait like this:

<?php
class MyClass {
    use Singleton;
    public function myMethod() {
       // Your class logic here.
    }
}

And same as usual:

$myClass = MyClass::getInstance();

This way, you would need to define a single Trait, and your existing class would be able to inherit the Trait, and it becomes a Singleton. This technique is helpful when you have so many Singleton classes and want to reduce the lines of code. Although I would prefer dependency injection over Singleton, that depends on your preference and use case.

Using traits can make the code for implementing a Singleton more concise and easier to understand. It also allows for the reuse of the Singleton functionality across multiple classes without duplicating the code in each class.

A personal opinion on using Singletons

Whether or not using traits to create singleton classes is a good practice depends on the context. In general, the singleton pattern is useful when you must ensure that only one class instance exists in your program, and that instance must be globally accessible. However, singletons can also make your code harder to test and maintain because they introduce global states and dependencies that are not easily mockable.

In some cases, it might be better to use dependency injection or a factory pattern instead of a singleton to manage the lifecycle of your objects. So, before using the singleton pattern, you should carefully consider whether it’s the best solution for your specific use case. A good article on the Hackernoon website also discusses the drawbacks of using a singleton.

Overall, the decision to use traits for a PHP Singleton will depend on the project’s specific needs and the developer’s preferences. As with any design pattern, it’s essential to carefully consider the potential benefits and drawbacks of using a Singleton before implementing it in your code.

Let me know in the comments section below.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *