Laravel Service Container: Contextual Binding &amp; Tagging | Mohamed Said        [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com) [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles  ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

       [  ](https://github.com/EG-Mohamed)       

 [ Home ](https://msaied.com) [ Projects ](https://msaied.com/projects) [ Articles ](https://msaied.com/articles) [ Certificates ](https://msaied.com/certificates) [ Contact ](https://msaied.com#contact-section) 

  [ home ](https://msaied.com)    [ articles ](https://msaied.com/articles)    Laravel Service Container: Contextual Binding, Tagging, and Method Injection        On this page       1. [  Beyond app()-&gt;make(): The Container Features You're Probably Underusing ](#beyond-codeapp-gtmakecode-the-container-features-youre-probably-underusing)
2. [  Contextual Binding ](#contextual-binding)
3. [  Tagging: Collecting Related Bindings ](#tagging-collecting-related-bindings)
4. [  Method Injection ](#method-injection)
5. [  Contextual Attributes (PHP 8.x) ](#contextual-attributes-php-8x)
6. [  Takeaways ](#takeaways)

  ![Laravel Service Container: Contextual Binding, Tagging, and Method Injection](https://cdn.msaied.com/231/71797ad08a2a2c3669a4c96040c1720c.png)

  #laravel   #dependency-injection   #service-container   #architecture   #php  

 Laravel Service Container: Contextual Binding, Tagging, and Method Injection 
==============================================================================

     18 Jun 2026      3 min read    ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said  

       Table of contents

1. [  01   Beyond app()-&gt;make(): The Container Features You're Probably Underusing  ](#beyond-codeapp-gtmakecode-the-container-features-youre-probably-underusing)
2. [  02   Contextual Binding  ](#contextual-binding)
3. [  03   Tagging: Collecting Related Bindings  ](#tagging-collecting-related-bindings)
4. [  04   Method Injection  ](#method-injection)
5. [  05   Contextual Attributes (PHP 8.x)  ](#contextual-attributes-php-8x)
6. [  06   Takeaways  ](#takeaways)

 Beyond `app()->make()`: The Container Features You're Probably Underusing
-------------------------------------------------------------------------

Most Laravel developers know how to bind an interface to a concrete class. Fewer use the container's more surgical tools — contextual binding, tagged groups, and method injection — which can dramatically simplify complex dependency graphs without introducing a service locator.

---

### Contextual Binding

Contextual binding lets you resolve different implementations of the same interface depending on *which class* is requesting it. This is invaluable in multi-channel or multi-driver architectures.

```php
// AppServiceProvider::register()
$this->app
    ->when(OrderNotificationService::class)
    ->needs(NotifierInterface::class)
    ->give(SlackNotifier::class);

$this->app
    ->when(InvoiceNotificationService::class)
    ->needs(NotifierInterface::class)
    ->give(EmailNotifier::class);

```

Both services type-hint `NotifierInterface`. The container resolves the correct driver per consumer — no factory, no `if` chain, no service locator.

You can also pass a closure for runtime logic:

```php
$this->app
    ->when(ReportExporter::class)
    ->needs(StorageInterface::class)
    ->give(fn ($app) => $app->make(
        config('exports.driver') === 's3' ? S3Storage::class : LocalStorage::class
    ));

```

---

### Tagging: Collecting Related Bindings

Tags let you group related bindings and resolve them all at once — perfect for plugin-style architectures, validators, or pipeline stages.

```php
// Register
$this->app->bind(CsvImporter::class);
$this->app->bind(XmlImporter::class);
$this->app->bind(JsonImporter::class);

$this->app->tag(
    [CsvImporter::class, XmlImporter::class, JsonImporter::class],
    'importers'
);

```

```php
// Resolve all tagged bindings
class ImportOrchestrator
{
    public function __construct(
        private readonly iterable $importers,
    ) {}

    public static function register(Application $app): void
    {
        $app->bind(self::class, fn ($app) => new self(
            $app->tagged('importers')
        ));
    }

    public function handle(string $type, mixed $payload): void
    {
        foreach ($this->importers as $importer) {
            if ($importer->supports($type)) {
                $importer->import($payload);
                return;
            }
        }

        throw new UnsupportedImportTypeException($type);
    }
}

```

Adding a new importer is a one-line registration — no changes to the orchestrator.

---

### Method Injection

`app()->call()` resolves dependencies for any callable, not just constructors. This is useful for one-off invocations where you don't want a full class binding.

```php
$result = app()->call(
    [ReportGenerator::class, 'generate'],
    ['format' => 'pdf']
);

```

The container resolves all type-hinted parameters automatically, merging them with the explicit `['format' => 'pdf']` array. Works equally well with closures:

```php
$result = app()->call(function (UserRepository $repo, string $format) {
    return $repo->exportAll($format);
}, ['format' => 'csv']);

```

This pattern is used internally by Laravel's route model binding and controller dispatch — you can leverage it in console commands, custom runners, or test helpers.

---

### Contextual Attributes (PHP 8.x)

Laravel 11+ supports `#[\Illuminate\Container\Attributes\Config]` and custom contextual attributes, letting you inject config values or tagged collections declaratively:

```php
use Illuminate\Container\Attributes\Config;

class PaymentGateway
{
    public function __construct(
        #[Config('services.stripe.secret')] private string $secret,
    ) {}
}

```

You can create your own attribute by implementing `ContextualAttribute` and registering a resolver — a clean alternative to constructor pollution with scalar values.

---

### Takeaways

- **Contextual binding** eliminates factory classes and `if/switch` driver selection by letting the container decide per consumer.
- **Tagging** enables open/closed plugin systems — new implementations register themselves without touching orchestrators.
- **`app()->call()`** is underused for ad-hoc dependency resolution in commands, test helpers, and event listeners.
- **Contextual attributes** (Laravel 11+) keep constructors clean when injecting scalar config values.
- Prefer these container features over service locator calls (`app(Foo::class)` inside methods) to keep dependencies explicit and testable.

 Found this useful?

          [  ](https://twitter.com/intent/tweet?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-service-container-contextual-binding-tagging-and-method-injection&text=Laravel+Service+Container%3A+Contextual+Binding%2C+Tagging%2C+and+Method+Injection) [  ](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fmsaied.com%2Farticles%2Flaravel-service-container-contextual-binding-tagging-and-method-injection) 

 Frequently Asked Questions 
----------------------------

  3 questions  

     Q01  When should I use contextual binding instead of a factory class?        Use contextual binding when the variation is purely about which consumer is requesting the dependency and the selection logic is static or config-driven. Factories are better when the variation depends on runtime data (e.g., a value from the database) that isn't available at container build time. 

      Q02  Does resolving tagged bindings instantiate all of them eagerly?        Yes — `$app-&gt;tagged('importers')` returns a generator-like `ContextualBindingBuilder` that resolves each binding on iteration, but all tagged classes will be instantiated as you iterate. If instantiation is expensive, consider lazy wrappers or resolving only the matching implementation. 

      Q03  Can I use method injection in Artisan commands?        Artisan commands use constructor injection for their dependencies. Method injection via `app()-&gt;call()` is available but you'd invoke it manually inside `handle()`. A cleaner pattern is to inject a single orchestrator or action class into the constructor and delegate there. 

  Continue reading

 More Articles 
---------------

 [ View all    ](https://msaied.com/articles) 

 [ ![PostgreSQL CTEs, Recursive Queries, and Lateral Joins in Laravel](https://cdn.msaied.com/241/32858f9c67eae0649999c32a6d31818f.png) laravel postgresql query-builder 

### PostgreSQL CTEs, Recursive Queries, and Lateral Joins in Laravel

Go beyond basic Eloquent with raw PostgreSQL power: composable CTEs, recursive tree traversal, and LATERAL joi...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 19 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/postgresql-ctes-recursive-queries-and-lateral-joins-in-laravel) [ ![PostgreSQL Window Functions in Laravel: Ranking, Running Totals, and Gap Detection](https://cdn.msaied.com/239/f588e7cbf8e6d3317a581ce0fa27140d.png) laravel postgresql eloquent 

### PostgreSQL Window Functions in Laravel: Ranking, Running Totals, and Gap Detection

Window functions let you compute rankings, running totals, and gaps directly in SQL without pulling rows into...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 19 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/postgresql-window-functions-in-laravel-ranking-running-totals-and-gap-detection) [ ![Custom Eloquent Casts: Encapsulating Domain Logic Inside Model Attributes](https://cdn.msaied.com/238/8e843e57a34f81f853eedefae629c09b.png) laravel eloquent domain-driven-design 

### Custom Eloquent Casts: Encapsulating Domain Logic Inside Model Attributes

Custom Eloquent casts let you push value-object logic directly into model attributes, keeping controllers and...

  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MJ.jpg)  Mohamed Said 

 19 Jun 2026     3 min read  

  Read    

 ](https://msaied.com/articles/custom-eloquent-casts-encapsulating-domain-logic-inside-model-attributes) 

   [  ![Mohamed Said](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png)   Mohamed Said Laravel Backend Engineer  ](https://msaied.com)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

Explore

- [Home](https://msaied.com)
- [Projects](https://msaied.com/projects)
- [Articles](https://msaied.com/articles)
- [Certificates](https://msaied.com/certificates)
- [Contact](https://msaied.com#contact-section)

Connect

- [   hello@msaied.com ](mailto:hello@msaied.com)
- [   +20 109 461 9204 ](tel:+201094619204)

© 2026 Mohamed Said. All rights reserved.

 [  ](https://github.com/EG-Mohamed) [  ](https://www.linkedin.com/in/msaiedm/) [  ](https://wa.me/201094619204) [  ](mailto:hello@msaied.com) [  ](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
