0

Singleton (container sense) — resolved once, same instance every time

Beginner5 min read·eng-14-006
interviewlaravel-src

Definition

In the context of Laravel's service container, a singleton is a binding that is resolved only once; every subsequent call to app(SomeClass::class) returns the exact same PHP object instance for the lifetime of the container. This is distinct from the GoF Singleton design pattern (which hard-codes uniqueness into the class itself using a static $instance property). Laravel's singleton binding is a container-level concept: the class itself is a normal class, but the container remembers the first-resolved instance and returns it to all subsequent callers.

In Practice

php
<?php

// Registering a singleton in a service provider
$this->app->singleton(CurrencyConverter::class, function ($app) {
    // This closure runs exactly once per container lifecycle
    return new CurrencyConverter(
        config('services.currency.api_key'),
        $app->make(HttpClient::class),
    );
});

// Both calls return the exact same object (=== true)
$a = app(CurrencyConverter::class);
$b = app(CurrencyConverter::class);
assert($a === $b); // true

// bind() — the non-singleton alternative — creates a new instance each time
$this->app->bind(HttpClient::class, function () {
    return new GuzzleClient(['timeout' => 5]);
});

$c = app(HttpClient::class);
$d = app(HttpClient::class);
assert($c === $d); // false — two different instances

// instance() — registers a pre-built object as a singleton
$this->app->instance(LoggerInterface::class, $myMonologInstance);

In a codebase, singletons are appropriate for stateless services that are expensive to construct (database connections, HTTP clients with connection pools, caches with warm state) or for services that manage shared state deliberately (a request-scoped metrics collector, a registry). Services with per-request mutable state should not be singletons in traditional PHP-FPM — but in Octane (long-lived process), the rules change dramatically.

In Context

In interviews, the singleton container binding is often conflated with the Singleton design pattern. The key distinction: the GoF Singleton locks uniqueness into the class (private constructor, static getInstance()) and is globally accessible without a container — this makes it hard to test. The container singleton is external to the class: the class has a normal public constructor, and only the container enforces one-instance semantics. You can rebind it in tests to get a fresh instance.

In Octane (Swoole/RoadRunner), the container lives across requests. A singleton registered in AppServiceProvider persists between requests. This is why Laravel introduced scoped() bindings — singletons that are reset between requests in Octane. If you are working on an Octane application and you register user-specific data in a singleton, you will leak that data across requests.

Related terms: bind() (new instance per resolution), singleton() (one instance per container), scoped() (one instance per request in Octane), instance() (pre-built object registered as a singleton). The app() helper itself always returns the same Application instance, making the application object the most fundamental singleton in every Laravel process.