app

Returns the service container, or resolves the given class or binding out of it.

Signature
app(string|class-string|null $abstract = null, array $parameters = []): mixed

Parameters

ParameterTypeDescription
$$abstractoptionalstring|class-string|null= nullA class name, interface, or string binding key to resolve; null returns the container itself.
$$parametersoptionalarray= []Additional constructor parameters passed through to make().

Return value

mixedThe container instance when no abstract is given, otherwise the resolved instance of the abstract.

Errors

Throws Illuminate\Contracts\Container\BindingResolutionException when the abstract cannot be built, and fails outright when no container instance has been set.

app() with no arguments returns the container instance — Container::getInstance(), which in a full application is the Illuminate\Foundation\Application. With an abstract — a class name, an interface, or a string binding key — it calls make() and builds the thing, resolving constructor dependencies recursively. The optional second argument is an array of extra parameters handed to the constructor.

When to reach for it

Prefer constructor injection: the container fills it in for you and the dependency stays visible in the signature. Reach for app() only where injection is unavailable — inside a closure handed to another library, in a Blade view, in a static helper, in a service provider's boot(), or when the class to build is chosen at runtime from config.

What trips people up

Calling app() hides the dependency from anyone reading the constructor and from your test setup. That is the Service Locator criticism and the reason static-analysis tools flag it.

It also resolves eagerly. Calling it during class construction, or worse inside a service provider's register(), can build a service before the providers it depends on have registered their own bindings. Move such calls into boot().

And unless the binding was registered as a singleton, every call constructs a fresh instance.

Example

Example · php
<?php

namespace App\Http\Controllers;

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

class CheckoutController extends Controller
{
    public function store(Request $request)
    {
        // The container builds whatever concrete class is bound to the interface.
        $gateway = app(PaymentGateway::class);

        // Extra constructor parameters go in the second argument.
        $report = app(SalesReport::class, ['month' => '2026-03']);

        echo get_class($gateway), "\n";   // App\Services\StripeGateway
        echo $report->title(), "\n";      // Sales for 2026-03

        return back();
    }
}

When to use it

  • Resolve a service inside a closure where constructor injection is not possible.
  • Pick an implementation at runtime from a class-string held in configuration.
  • Grab the application instance to check the environment or a filesystem path.

Frequently asked questions

What is the difference between app() and resolve() in Laravel?

None of substance — resolve($abstract, $parameters) is a thin alias that calls the same container make(). The only difference is that app() with no arguments returns the container itself, which resolve() cannot do.

How do I pass constructor arguments through app()?

Use the second argument: app(SalesReport::class, ['month' => '2026-03']) forwards the array to make(), which merges it with the dependencies the container resolves automatically. Keys must match the constructor parameter names.

Should I use app() instead of constructor injection?

No, prefer constructor injection — the container fills the dependency in automatically and the signature documents what the class needs. Reach for app() only where injection is impossible, such as inside a closure, a Blade view, or a static method.

More examples

The container itself

With no abstract you get the Application object, which is why app()->environment() and app()->basePath() work. bound() is useful in package code that must degrade gracefully when an optional binding is missing.

Example · php
<?php

$container = app();

echo $container->environment(), "\n";          // local
echo $container->version(), "\n";              // 12.x.x
var_dump($container->bound('cache'));          // bool(true)
var_dump($container->runningInConsole());      // bool(false)
var_dump(app()->environment('production'));    // bool(false)

Bind in register(), resolve in boot()

register() runs for every provider before any boot() method does, so resolving a service in register() can build it before another provider has bound its dependencies. Because the binding is a singleton, later app(PaymentGateway::class) calls return the same instance.

Example · php
<?php

namespace App\Providers;

use App\Contracts\PaymentGateway;
use App\Services\StripeGateway;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Only bind here — never resolve.
        $this->app->singleton(PaymentGateway::class, StripeGateway::class);
    }

    public function boot(): void
    {
        // Safe: every provider has finished registering by now.
        echo get_class(app(PaymentGateway::class)), "\n";
        // App\Services\StripeGateway
    }
}

Prefer injection where you can

The constructor version is the one to copy: a test can pass a fake gateway without touching the container. The app() call inside the closure is the legitimate escape hatch, and even there $this->gateway would usually have been the better choice.

Example · php
<?php

namespace App\Services;

use App\Contracts\PaymentGateway;

class Checkout
{
    // Visible in the signature, resolved by the container, trivially mockable.
    public function __construct(private PaymentGateway $gateway) {}

    public function run(array $ids): void
    {
        collect($ids)->each(function (int $id) {
            // Only reach for app() when injection is genuinely impossible,
            // for example inside a closure passed to third-party code.
            echo get_class(app(PaymentGateway::class)), " charging {$id}\n";
        });
    }
}

Discussion

  • Be the first to comment on this lesson.