Laravel - pass parameters through app->bind to model's constructor

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Laravel: Passing Parameters Through app->bind to Model Constructors

As developers working within the Laravel ecosystem, we frequently deal with dependency injection (DI) and service providers. The mechanism of binding classes to interfaces via $app->bind() is fundamental to how Laravel manages object instantiation. However, when we move beyond simply injecting repositories or services, we often run into a challenge: how do we pass runtime data—like an array of parameters retrieved from a controller or request—into the constructor of the bound entity or model?

This post dives into the specific pattern of passing dynamic data through app->bind() to initialize your Eloquent Models or Entities, addressing the exact scenario you presented.

The Challenge: Binding Static vs. Dynamic Data

When you use app->bind('Class\Interface', function ($app) { ... }), you are essentially defining a factory that tells Laravel how to create an instance of Class\Interface whenever it is requested from the container. In your initial setup, if you only inject a repository:

$this->app->bind('Playlist\PlaylistEntity', function($app) {
    // Only injecting the repository, ignoring necessary parameters
    return new PlaylistEntity($app->make('Playlist\PlaylistRepositoryInterface'));
});

This works perfectly for simple dependency injection. The problem arises when your Entity or Model requires specific data (like an array of playlist IDs) to be initialized upon creation. Standard binding mechanisms don't inherently provide a clean way to inject external, request-specific variables directly into the factory closure without extra context.

The Solution: Injecting Parameters into the Binding Closure

The solution lies in ensuring that the data you need is accessible within the scope of the Service Provider where the binding occurs. Since the Service Provider is often executed in response to a request lifecycle (via route binding or event listeners), we can access those parameters.

If your goal is to pass data from an external source (like a controller method) into the binding, you need to ensure those parameters are available when the provider defines the binding. While direct injection into bind isn't standard, we can leverage the context provided by the container itself or scope the binding appropriately.

A cleaner approach is often to move the parameter retrieval logic one step further up the chain, ensuring that the data required for instantiation is available when the entity is first resolved.

Here is how you structure the binding to incorporate external parameters:

// In your Service Provider (e.g., PlaylistServiceProvider)

use App\Models\PlaylistEntity;
use App\Repositories\PlaylistRepositoryInterface;

public function register()
{
    $this->app->bind('Playlist\PlaylistEntity', function ($app) {
        // 1. Retrieve the dynamic parameters needed for construction.
        // Assume these parameters were passed into the service provider's constructor, 
        // or retrieved from a context available to this binding scope.
        $parameters = $this->getRequiredParameters(); // Hypothetical retrieval method

        // 2. Use the retrieved parameters in the constructor call.
        return new PlaylistEntity($app->make(PlaylistRepositoryInterface), $parameters);
    });
}

Best Practice: Using Constructor Injection for Complex Data

While binding factories is powerful, a much more robust and Laravel-idiomatic approach for passing complex data to models is Constructor Injection. Instead of relying solely on the Service Provider's bind method to inject everything, ensure your Entity/Model constructor explicitly defines all dependencies it needs:

// App\Models\PlaylistEntity.php

class PlaylistEntity
{
    protected $repository;
    protected $playlistIds;

    public function __construct(PlaylistRepositoryInterface $repository, array $playlistIds)
    {
        $this->repository = $repository;
        $this->playlistIds = $playlistIds; // Data is cleanly injected here
    }

    public function getPlaylists()
    {
        // Logic to fetch based on the injected $playlistIds
        return $this->repository->findMany($this->playlistIds);
    }
}

When you resolve this entity via the container, Laravel automatically resolves all required dependencies defined in the constructor, making your code significantly more testable and explicit. This aligns perfectly with the principles of clean architecture promoted by frameworks like Laravel and fosters better separation of concerns.

Conclusion

While manipulating app->bind closures can be technically achieved to pass parameters, it often leads to tightly coupled service providers where request data pollutes the binding layer. For passing dynamic data into Eloquent Models or Entities, the recommended practice is to utilize explicit Constructor Injection. This approach ensures that your entities remain decoupled from the specific mechanism of dependency resolution and clearly communicate exactly what data they require, making your application architecture cleaner, more maintainable, and easier to test. Always strive for explicit contracts when building complex systems on top of Laravel.