> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Service container

> Explica el mecanismo de inyección de dependencias del service container de Laravel y los fundamentos de los bindings.

## Qué es el service container

El service container de Laravel es el mecanismo para gestionar las dependencias de las clases y realizar la inyección de dependencias. Inyectar dependencias significa «inyectar» en la clase las dependencias que necesita a través del constructor o, en algunos casos, mediante métodos setter.

Fíjate en el siguiente ejemplo.

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Services\AppleMusic;
use Illuminate\View\View;

class PodcastController extends Controller
{
    /**
     * Crea una nueva instancia del controlador
     */
    public function __construct(
        protected AppleMusic $apple,
    ) {}

    /**
     * Muestra la información del podcast indicado
     */
    public function show(string $id): View
    {
        return view('podcasts.show', [
            'podcast' => $this->apple->findPodcast($id)
        ]);
    }
}
```

En este ejemplo, `PodcastController` necesita obtener podcasts desde una fuente de datos como Apple Music. Por eso **inyectamos** un servicio capaz de obtener podcasts. Al inyectarlo, en las pruebas podemos sustituir con facilidad `AppleMusic` por un mock (una implementación falsa).

<Info>
  Entender el service container en profundidad es imprescindible para construir aplicaciones Laravel grandes. También ayuda a contribuir al propio núcleo de Laravel.
</Info>

```mermaid theme={null}
flowchart TD
    A["Service provider<br>register()"] --> B["Service container<br>Registro de bindings"]
    B --> C{"Solicitud de resolución<br>make() / inyección automática"}
    C -- "Clase concreta" --> D["Resolución automática<br>por reflection"]
    C -- "Interfaz" --> E["Resolver la clase de<br>implementación registrada"]
    D --> F["Crear instancia e<br>inyectar al constructor"]
    E --> F
```

## Resolución sin configuración

Si tu clase solo depende de otras clases concretas (no de interfaces), no necesitas indicarle al container cómo resolverlas. Por ejemplo, imagina que escribes el siguiente código en `routes/web.php`.

```php theme={null}
<?php

class Service
{
    // ...
}

Route::get('/', function (Service $service) {
    dd($service::class);
});
```

<Info>
  Este ejemplo define la clase dentro del archivo de rutas con fines de demostración. En una aplicación real, define las clases de servicio en el directorio `app/Services`.
</Info>

Al acceder a esta ruta, Laravel resuelve automáticamente la clase `Service` y la inyecta en el handler. No hace falta preparar ningún archivo de configuración para beneficiarse de la inyección de dependencias.

En la mayoría de las clases que escribes en una aplicación Laravel —controladores, listeners de eventos, middlewares, etc.—, las dependencias se inyectan automáticamente a través del container.

## Bindings

### Bindings básicos

La mayoría de los bindings se registran en los [service providers](/es/service-providers). Dentro de un service provider puedes acceder al container mediante la propiedad `$this->app`.

#### bind

Con el método `bind` registras un binding pasando el nombre de una clase o interfaz y un closure.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->bind(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

El closure puede recibir el propio container como argumento. Puedes usarlo para resolver sub-dependencias.

Si necesitas manipular el container fuera de un service provider, usa la fachada `App`.

```php theme={null}
use App\Services\Transistor;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Support\Facades\App;

App::bind(Transistor::class, function (Application $app) {
    // ...
});
```

<Info>
  Las clases que no dependen de una interfaz no necesitan registrarse en el container. El container puede resolverlas automáticamente usando reflection.
</Info>

#### singleton

El método `singleton` vincula la clase o interfaz de modo que se resuelva una sola vez. Una vez resuelto el singleton, todas las llamadas posteriores al container devuelven la misma instancia.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->singleton(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

Con `singletonIf` puedes registrar el binding singleton solo si aún no existe uno para el tipo indicado.

```php theme={null}
$this->app->singletonIf(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

#### Atributo Singleton

Puedes indicarle al container que la clase o interfaz debe resolverse una sola vez añadiendo el atributo `#[Singleton]`.

```php theme={null}
<?php

namespace App\Services;

use Illuminate\Container\Attributes\Singleton;

#[Singleton]
class Transistor
{
    // ...
}
```

#### Bindings de singleton con scope

El método `scoped` vincula la clase o interfaz para que se resuelva una sola vez dentro del ciclo de vida de la petición/job de Laravel. Es similar a `singleton`, pero las instancias registradas con `scoped` se descartan cada vez que la aplicación Laravel inicia un nuevo «ciclo de vida», como cuando un worker de [Laravel Octane](/es/octane) atiende una nueva petición o cuando un [worker de cola](/es/queues) procesa un nuevo job.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;
use Illuminate\Contracts\Foundation\Application;

$this->app->scoped(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

Con `scopedIf` puedes registrar el binding con scope solo si aún no existe uno para el tipo indicado.

```php theme={null}
$this->app->scopedIf(Transistor::class, function (Application $app) {
    return new Transistor($app->make(PodcastParser::class));
});
```

#### Atributo Scoped

También puedes indicarle al container que resuelva una sola vez por ciclo de petición/job añadiendo el atributo `#[Scoped]`.

```php theme={null}
<?php

namespace App\Services;

use Illuminate\Container\Attributes\Scoped;

#[Scoped]
class Transistor
{
    // ...
}
```

#### instance

También puedes vincular al container una instancia de objeto ya existente con el método `instance`. En las llamadas posteriores al container se devolverá siempre esa instancia.

```php theme={null}
use App\Services\Transistor;
use App\Services\PodcastParser;

$service = new Transistor(new PodcastParser);

$this->app->instance(Transistor::class, $service);
```

### Vincular una interfaz a una implementación

Una de las funcionalidades más potentes del service container es la posibilidad de vincular una interfaz a una implementación concreta. Por ejemplo, imagina que tienes la interfaz `EventPusher` y la implementación `RedisEventPusher`.

```php theme={null}
use App\Contracts\EventPusher;
use App\Services\RedisEventPusher;

$this->app->bind(EventPusher::class, RedisEventPusher::class);
```

Con esto, el container inyectará `RedisEventPusher` en cualquier clase que necesite una implementación de `EventPusher`. Basta con hacer un type hint de la interfaz `EventPusher` en el constructor.

```php theme={null}
use App\Contracts\EventPusher;

/**
 * Crea una nueva instancia de la clase
 */
public function __construct(
    protected EventPusher $pusher,
) {}
```

<Tip>
  Al depender de interfaces, cambiar la implementación no requiere modificar el código. Esto facilita las pruebas y los cambios futuros.
</Tip>

#### Atributo Bind

Laravel también ofrece el útil atributo `Bind`. Añadiéndolo a una interfaz, indicas a Laravel qué implementación inyectar automáticamente cuando se solicita esa interfaz. Con `Bind` no necesitas registrar nada adicional en un service provider.

Además, colocando varios atributos `Bind` sobre la interfaz, puedes configurar la inyección de implementaciones distintas por entorno.

```php theme={null}
<?php

namespace App\Contracts;

use App\Services\FakeEventPusher;
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;

#[Bind(RedisEventPusher::class)]
#[Bind(FakeEventPusher::class, environments: ['local', 'testing'])]
interface EventPusher
{
    // ...
}
```

Para bindings que dependan de condiciones arbitrarias puedes usar el atributo `BindWhen`. Al closure se le puede pasar el container y debe devolver `true` cuando quieras aplicar el binding. Los atributos `Bind` y `BindWhen` se evalúan en el orden en que se declaran.

```php theme={null}
use App\Services\BetaEventPusher;
use Illuminate\Container\Attributes\BindWhen;
use Laravel\Pennant\Feature;

#[BindWhen(BetaEventPusher::class, static fn () => Feature::active('beta-events'))]
interface EventPusher
{
    // ...
}
```

<Info>
  Para usar el atributo `BindWhen` se requiere PHP 8.5 o superior.
</Info>

Además, combinándolos con los atributos [Singleton](#atributo-singleton) o [Scoped](#atributo-scoped), puedes especificar que ese binding se resuelva una sola vez o una sola vez por petición/job.

```php theme={null}
use App\Services\RedisEventPusher;
use Illuminate\Container\Attributes\Bind;
use Illuminate\Container\Attributes\Singleton;

#[Bind(RedisEventPusher::class)]
#[Singleton]
interface EventPusher
{
    // ...
}
```

## Resolución automática (DI por type hint)

El service container inyecta automáticamente las dependencias mirando los type hints del constructor al resolver clases como controladores, listeners de eventos o middlewares.

```php theme={null}
<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * Crea una nueva instancia del controlador
     */
    public function __construct(
        protected UserRepository $users,
    ) {}
}
```

Si `UserRepository` no depende de una interfaz, no hay que registrarlo en el container. Basta con acceder a la ruta correspondiente y el container resolverá automáticamente la dependencia y la inyectará en el controlador.

## Resolver desde el container

### Método make

Con el método `make` puedes resolver una instancia de clase desde el container.

```php theme={null}
use App\Services\Transistor;

$transistor = app()->make(Transistor::class);
```

Si las dependencias de la clase no pueden resolverse en el container, con `makeWith` puedes pasar argumentos adicionales.

```php theme={null}
$transistor = $this->app->makeWith(Transistor::class, ['id' => 1]);
```

### Inyección automática

En la práctica rara vez llamarás directamente a `make`. Basta con añadir type hints al constructor de las clases que resuelve el container (controladores, listeners de eventos, middlewares, etc.) y las inyectará automáticamente.

## Relación entre fachadas y container

Las fachadas de Laravel ofrecen una interfaz estática a los objetos dentro del container. Por ejemplo, `Cache::get()` internamente obtiene el servicio `Cache` desde el container y lo invoca.

```php theme={null}
use Illuminate\Support\Facades\Cache;

// Llamada usando la fachada
Cache::get('key');

// Llamada equivalente usando directamente el container
app('cache')->get('key');
```

Las fachadas son envoltorios cómodos del container. En las pruebas puedes sustituir la fachada por un mock.

```php theme={null}
use Illuminate\Support\Facades\Cache;

Cache::shouldReceive('get')
    ->once()
    ->with('key')
    ->andReturn('value');
```

## Ejemplo práctico de inyección por constructor

Veamos un patrón típico en una aplicación real.

<Steps>
  <Step title="Define la interfaz">
    ```php theme={null}
    <?php

    namespace App\Contracts;

    interface PaymentGateway
    {
        public function charge(int $amount, string $token): bool;
    }
    ```
  </Step>

  <Step title="Crea la clase de implementación">
    ```php theme={null}
    <?php

    namespace App\Services;

    use App\Contracts\PaymentGateway;

    class StripePaymentGateway implements PaymentGateway
    {
        public function charge(int $amount, string $token): bool
        {
            // Procesamiento del pago usando la API de Stripe...
            return true;
        }
    }
    ```
  </Step>

  <Step title="Vincúlala en el service provider">
    ```php theme={null}
    use App\Contracts\PaymentGateway;
    use App\Services\StripePaymentGateway;

    $this->app->singleton(PaymentGateway::class, StripePaymentGateway::class);
    ```
  </Step>

  <Step title="Recibe la inyección en el controlador">
    ```php theme={null}
    <?php

    namespace App\Http\Controllers;

    use App\Contracts\PaymentGateway;
    use Illuminate\Http\Request;

    class OrderController extends Controller
    {
        public function __construct(
            protected PaymentGateway $payment,
        ) {}

        public function store(Request $request)
        {
            $this->payment->charge(
                $request->amount,
                $request->payment_token
            );

            // ...
        }
    }
    ```
  </Step>
</Steps>

Con este patrón, cambiar el servicio de pago de `Stripe` a otro proveedor requiere modificar un solo binding.

## Próximos pasos

<Card title="Service providers" icon="plug" href="/es/service-providers">
  Aprende a registrar bindings mediante service providers.
</Card>


## Related topics

- [Desarrollo de paquetes para Laravel](/es/advanced/package-development.md)
- [Investigación inicial de Laravel Passkeys (passkeys-server + @laravel/passkeys)](/es/blog/passkeys-introduction.md)
- [Manejo de errores](/es/error-handling.md)
- [Service providers](/es/service-providers.md)
- [Guía de actualización de Laravel 12 a 13](/es/blog/upgrade-12-to-13.md)
