Service container — the object that wires DI together at runtime
Definition
The service container (also called an IoC container or DI container) is a runtime object that maintains a registry of how to build other objects and resolves them on demand, including their full dependency trees. In Laravel, the service container is an instance of Illuminate\Container\Container, stored as the app singleton. When you type-hint a class in a constructor, the container reads that type-hint via PHP Reflection, looks up how to build it (either from an explicit binding or via auto-resolution), builds any of its dependencies first, then assembles the outermost object — recursively.
In Practice
<?php
// Explicit binding — you tell the container exactly how to build something
app()->bind(PaymentGateway::class, function ($app) {
return new StripeGateway(
config('services.stripe.key'),
$app->make(HttpClient::class),
);
});
// Singleton binding — built once, same instance every subsequent call
app()->singleton(CurrencyConverter::class, function ($app) {
return new CurrencyConverter($app->make(CacheStore::class));
});
// Auto-resolution — no explicit binding needed for concrete classes
// The container reads the constructor type-hints via Reflection
$service = app(OrderService::class);
// Container sees: OrderService needs UserRepository and Mailer
// Recursively resolves both, then builds OrderService
// Instance binding — register a pre-built object
app()->instance(LoggerInterface::class, $monologInstance);When you look at a Laravel service provider's register() method, you are looking at instructions being given to the container. The container itself lives at Illuminate/Container/Container.php and its build() and resolve() methods are where the Reflection-based auto-wiring happens.
In Context
In interviews, the service container question has two layers: what it does (registering and resolving dependencies) and how it does it (Reflection API reading constructor parameter types, recursively building the dependency graph). Candidates who only describe the "what" are at a junior level; the "how" is what separates mid-level from senior.
A frequent misconception is that app() is a global variable. It is a global function that calls Container::make() on the application singleton. Calling app(OrderService::class) is equivalent to calling Application::getInstance()->make(OrderService::class). The distinction matters in Octane and long-running process contexts where the container lifecycle differs from a traditional PHP request.
The container is also the foundation of Laravel's testing power. When you call $this->mock(PaymentGateway::class) in a test, you are rebinding that interface in the container to a mock object. Every class that depends on PaymentGateway through type-hints will receive the mock automatically — no manual wiring needed.