← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

IoC Container

quality PHP 7.0+ Intermediate

Also Known As

DI container service container dependency injection container IoC inversion of control container Laravel container Symfony DI

TL;DR

An Inversion of Control container automatically resolves and injects class dependencies — you declare what a class needs, the container figures out how to create it, eliminating manual dependency wiring.

Explanation

An IoC (Inversion of Control) container, also called a DI (Dependency Injection) container or service container, maintains a registry of how to construct objects. When you request a class, the container inspects its constructor type hints, recursively resolves each dependency, and returns a fully-constructed instance. In Laravel, the service container is the central registry — type-hint an interface in a controller constructor and the container injects the concrete implementation bound to that interface. Symfony's DI component reads service definitions from YAML/XML/PHP configuration. Binding patterns: concrete bindings (App::bind(UserRepository::class, EloquentUserRepository::class)); singleton bindings (App::singleton(Cache::class, RedisCache::class) — same instance reused); factory bindings (App::bind(Report::class, fn($app) => new Report($app->make(DB::class), config('reports')))); contextual bindings (inject different implementations depending on which class is requesting the dependency).

Common Misconception

A DI container is required to use dependency injection. Dependency injection is just passing dependencies through constructors or method parameters — no container required. A container automates the wiring for large applications with many classes and deep dependency trees. For small scripts or simple classes, constructor injection without a container is perfectly valid DI. The container solves the 'who constructs the dependencies?' question at scale.

Why It Matters

IoC containers eliminate the most tedious part of dependency injection at scale: manually constructing object graphs. Without a container, constructing a controller with five dependencies, each with their own dependencies, requires deeply nested new() calls in bootstrap code. With a container, type-hint the interface and it appears. More importantly, the container enables interface binding — you can swap EloquentUserRepository for InMemoryUserRepository in tests by changing one binding, without modifying any class that uses UserRepository. This is the foundation of testable PHP application architecture.

Common Mistakes

  • Injecting the container itself into classes — this is the Service Locator antipattern; inject specific dependencies, not the container.
  • Binding concrete classes to concrete classes — bind interfaces to implementations so you can swap implementations without changing dependent code.
  • Not using singleton binding for expensive-to-construct services — database connections and HTTP clients should be shared instances, not recreated per-request.
  • Overusing the container for simple value objects — inject config values directly, not through the container.

Code Examples

✗ Vulnerable
// Service locator antipattern — container injected into class
class OrderService {
    public function __construct(private Container $container) {}

    public function process(int $id): void {
        // Hidden dependency — unclear what this class needs
        $repo = $this->container->make(OrderRepository::class);
        $mail = $this->container->make(Mailer::class);
    }
}
✓ Fixed
// Constructor injection — dependencies explicit, testable
class OrderService {
    public function __construct(
        private OrderRepository $orders,
        private Mailer          $mailer,
    ) {}

    public function process(int $id): void {
        $order = $this->orders->find($id); // injected dependency
        $this->mailer->send(new OrderConfirmed($order));
    }
}

// ServiceProvider — bind interface to implementation once
public function register(): void {
    $this->app->singleton(OrderRepository::class, EloquentOrderRepository::class);
    $this->app->singleton(Mailer::class, SmtpMailer::class);
}

Added 23 Mar 2026
Edited 5 Apr 2026
Views 21
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 5 Perplexity 4 Google 2 ChatGPT 1 Majestic 1 Meta AI 1 Ahrefs 1
crawler 15
DEV INTEL Tools & Severity
🔵 Info ⚙ Fix effort: Medium
⚡ Quick Fix
Type-hint interfaces in constructors, bind interface to implementation once in a ServiceProvider: $this->app->bind(UserRepo::class, EloquentUserRepo::class) — the container handles the rest
📦 Applies To
PHP 7.0+ web cli

✓ schema.org compliant