If you have been following our posts, you probably noticed that this content is definitely not for those looking for the “best plugins” for WP or trying to find ways to troubleshoot problems not rarely caused by those same plugins.

At the same time, we are not targetting experienced and top notch PHP developers or programmers, although they can always earn, like us, from reading interesting new approaches and ideas on coding.

But no, if you are willing to really understand WP and other frameworks, as well as PHP, in a way that you can not find the solutions, but think about them, so you are definitely the one we’ve been writing for.

Back to the topic, if you are relatively familiar with PHP and even WP coding, you already heard about the term Singleton. Maybe you heard something on Multiton, or even design patterns in PHP. If not, let’s quickly recap.

Singletons – a simple design pattern

Before explaining the Singleton briefly, let’s put you aware about the design patterns – the Singleton is one of them. A Singleton is a creational design pattern which makes sure that just one object of its kind exists simultaneously. A lot of developers consider the Singleton pattern an antipattern, but sometimes it’s still pretty handy, even though it harms the code modularity.

Singletons in PHP usually make use of a static property that holds a single instance of an object. This is an example of a very simple Singleton class:

final class Singleton
{
    private static ?Singleton $instance = null;

    /**
     * gets the instance via lazy initialization (created on first usage)
     */
    public static function getInstance(): Singleton
    {
        if (static::$instance === null) {
            static::$instance = new static();
        }

        return static::$instance;
    }

    /**
     * is not allowed to call from outside to prevent from creating multiple instances,
     * to use the singleton, you have to obtain the instance from Singleton::getInstance() instead
     */
    private function __construct() { }

    /**
     * prevent the instance from being cloned (which would create a second instance of it)
     */
    private function __clone() { }

    /**
     * prevent from being unserialized (which would create a second instance of it)
     */
    private function __wakeup() { }
}

In WP context, especially while developing a plugin, sometimes it proves to be useful: in logging features, assuring events and behaviors on plugin’s installation or uninstallation or even in the plugin’s main class or init class.

However, many plugins show an overuse of it. Sometimes we want to limit instances, but not necessarily to a single one. And other times, we want to instatiate a class a handful of times, but make sure each one of the instances can be distinctive. For such you have a related pattern – the Multiton.

Multitons

Well… if we wanted to limit instances of an object, so why designing a pattern that can produce multiple instances? The Multiton also limits instances in a way – not in number, but flagging each one of the objects with a particular key. A Multiton resembles a Singleton, but with two main differences:

  • The static property $instances is an array.
  • The instance() or getInstance() method receives an argument.

About this last topic, in a Multiton, the method that gets the instance would look like this:

/**
     * gets the instance with the given name and uses lazy initialization.
     *
     * @param string $key
     *
     * @return Multiton
     */
    public static function getInstance($key)
    {
        if (!array_key_exists($key, self::$instances)) {
            self::$instances[$key] = new self();
        }

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

What for? Some classes might be used in different instances, for similar but not equal tasks. Like multiple loggers or different PDO instance for two or more concurrent databases, in hybrid apps (MySQL and SQLite, for instance).

In WordPress, that could be handy for accessing two different MySQL databases (in sites using HyperDB, for example). Loggers can also be useful in a lot of situations, using a Multiton.

What if I wanted a particular number of instance?

Nor unique, neither multiple – but a specific and controlled number of instances. Multitons could be used, but you would need to find another way to limit instances when they reached the maximum number.

That made us to suggest a silly but useful child for the Singleton pattern: the Limiton. In this case, on top of a key for each instance, we want to set a variable, which provides the maximum number of instances, and them count() instances held by the property $instances before instatiating any new object. Something like this:

/**
     * @var reference to limiton array of instances
     */
    private static $instances = [];

    /**
     * @var limit of concurrent instances of the class
     */
    public static $limit = 2;
    
    /**
     * Creates a new instance of a limiton class flagged with a key.
     *
     * @param $key the key which the instance should be stored/retrieved
     *
     * @return self
     */
    final public static function instance($key)
    {
        if(!array_key_exists($key, self::$instances)) {

            if(count(self::$instances) < self::$limit) {
                self::$instances[$key] = new self;
            }
              
        }
        
        return self::$instances[$key];
    }

    /**
     * Sets the maximum number of instances the class allows
     *
     * @param $number int number of instances allowed
     * @return void
     */
    public function setLimit(int $number) {

        self::$limit = $number;
    }

Simple, straightforward and solves the issue. A Limiton could be useful in a number of situations: it limits, like the Singleton, but keeps a flag on each allowed instance. Besides, a method setLimit() assures flexibility in terms of increasing or modifying the number of concurrent object anytime.

Finally, let's cut the redundant code

Nothing worse than finding an app or plugin in which at least a dozen of classes start with a Singleton inside them - a tragic ans unnecessary copy and paste. If you are familiar with, traits have been a smart way of avoiding duplicity in coding. So let's use traits inside our classes to apply Singletons, rather than pasting it on every situation required.

Of course we provide a library for that: you can just use traits. A Singleton, a Multiton and our Limiton. Check the source in our Github repository.

Dark Mode

tonton (this link opens in a new window) by carloswph (this link opens in a new window)

A serie of tools based on traits that simplify the use of singletons, multitons and other class instances controllers.

Leave a comment

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