PHP Singleton Design Pattern Creational Pattern

PHP Singleton Pattern

A short screencast: the Singleton pattern in PHP — one object for the whole app with lazy initialization.

Singleton Pattern — open the lesson page

Overview

We build a Logger that cannot have more than one instance. The constructor is private, and getInstance() creates the object only on the first call, then always returns the same one. We write a message through $a, read it through $b — and it is the very same object.

UML diagram

classDiagram class Logger { -static Logger instance +array messages -__construct() +static getInstance() Logger +log(message: string) void } Logger --> Logger : same

Code

Logger.php

class Logger
{
    private static ?Logger $instance = null;

    public array $messages = [];

    private function __construct() {}

    public static function getInstance(): Logger
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    public function log(string $message): void
    {
        $this->messages[] = $message;
    }
}

demo.php

require_once 'Logger.php';

$a = Logger::getInstance();
$b = Logger::getInstance();

$a->log('first');

echo $a === $b ? 'Same instance: true' : 'Same instance: false';
echo PHP_EOL;
echo 'Messages: ' . implode(', ', $b->messages);

Note: pros and criticism

The upside is a single access point and lazy creation: the instance uses no memory until it is actually needed. But we pay for it with global state — anyone can write to the log, which complicates tests and hides the dependency. In many cases, instead of a singleton, injecting one object from a container is a better choice, because the decision stays with the calling code.

Example output

Running php demo.php in the terminal produces:

Same instance: true
Messages: first

Advantages

  • Guarantees a single instance per application.
  • Lazy initialisation: the object is created on first use.
  • A shared access point to a common resource.
  • Saves memory and resources: one connection, one logger.

When to use

  • When a class must have exactly one instance.
  • When you need shared access to a resource (config, log, cache).
  • When creating the resource is expensive and should be lazy.
  • When global state must be controlled from one place.

Usage in Laravel

In Laravel the singleton is the service container: a ->singleton() binding guarantees that app() returns the same object every time. The Illuminate\Log\LogManager, Illuminate\Cache\CacheManager and the database connection are registered as singletons, while facades (Illuminate\Support\Facades\Log, Cache) provide static access to them.