The till in the physical shop reuses the checkout but takes cash. Contextual binding gives one consumer its own implementation of an interface, and tagging names a group of bindings:
$this->app->when(TillCheckout::class)
->needs(PaymentGateway::class)
->give(CashDrawer::class);
$this->app->tag([SalesReport::class, LowStockReport::class], 'reports');The trace in The Service Container showed TillCheckout, a subclass of Checkout, receiving CashDrawer; needs('$min')->give(3) would pass a scalar by name.
Contextual attributes declare the same on the parameter. LowStockReport takes #[Config('shop.low_stock', 5)] private int $threshold, and DailyDigest takes #[Tag('reports')] private iterable $reports and prints one line per report:
echo app(App\Reports\DailyDigest::class)->render(), "\n";- Sales: 0 orders, $0.00 - Below 5: BK-102, BK-103, BK-105
The tagged set arrives as a lazy RewindableGenerator, so each report is built only when the loop reaches it. The other built-in attributes in Illuminate\Container\Attributes are Auth, Cache, DB, Log, Storage, Context, Give, RouteParameter, RequestAttribute and CurrentUser; your own implements ContextualAttribute with a static resolve().