← Back to Modules

Interactive Demo

Click to see both injection types in action and understand when to use each

🎯 Interactive Demo

Constructor vs Method Injection

Laravel supports both types of dependency injection. Choose based on how often you need the dependency:

🏗️

Constructor Injection - Always-needed dependencies

Config loader loaded once, used everywhere

public function __construct(
    private ConfigurationLoader $config,
    private PaymentService $payment
) {}

public function process() {
    // $this->config and $this->payment
    // available in ALL methods
}

When to use:

Service needed in multiple methods

Live Demo Result:

instance_id: config_693d4fedc797e
load_count: 1
config: {"app_name":"Laravel Learn","version":"1.0.0","features":["di","container","facades"],"loaded_at":"2025-12-13 11:37:17"}

Method Injection - Sometimes-needed dependencies

Request object only needed in this action

public function update(Request $request, User $user) {
    // $request and $user only needed in THIS method
    // Laravel automatically injects them
}

When to use:

Dependency only needed in ONE method

Live Demo Result:

method: GET
path: demos/service-container/dependency-injection

📍 Where Does Auto-Injection Work?

✅ Controller constructors
✅ Controller methods
✅ Job handle() methods
✅ Event listener handle()
✅ Middleware handle()
✅ Command handle()
✅ Form Request classes
❌ Model constructors
❌ Regular PHP classes (unless resolved via container)

🎯 Practical Decision Guide

Scenario: Payment Processing Service

What it needs:
  • • PaymentGateway (all methods)
  • • Logger (all methods)
  • • NotificationService (all methods)
✅ Use Constructor Injection

All three services are needed in multiple methods. Inject once in constructor.

Scenario: Blog Post Controller

What it needs:
  • • Request (only in store/update)
  • • Post model (only in show/edit)
⚡ Use Method Injection

Each method needs different dependencies. Inject per-method.

Scenario: API Controller

What it needs:
  • • AuthService (all methods)
  • • RateLimiter (all methods)
  • • Request (specific methods)
  • • Specific models (per route)
🔄 Use BOTH

Constructor for AuthService & RateLimiter. Method injection for Request & models.

📝 Complete Example: Using Both

class PostController extends Controller
{
    // Constructor Injection - always needed
    public function __construct(
        private PostRepository $posts,
        private CacheManager $cache
    ) {}

    // Method Injection - only needed here
    public function store(Request $request)
    {
        // Use constructor-injected services
        $post = $this->posts->create($request->validated());
        $this->cache->forget('posts');

        return response()->json($post, 201);
    }

    // Method Injection - route model binding
    public function show(Post $post)
    {
        // $post automatically injected via route model binding
        return $this->cache->remember("post.{$post->id}", 
            fn() => $post->load('author', 'comments')
        );
    }

    // Combining both injection types
    public function update(Request $request, Post $post)
    {
        $this->authorize('update', $post); // Policy check
        
        $this->posts->update($post, $request->validated());
        $this->cache->forget("post.{$post->id}");

        return response()->json($post);
    }
}

💡 Pro Tips

  • Keep constructors lean: Only inject what's needed in multiple methods
  • Use method injection for Request: It's cleaner than constructor injection for form data
  • Combine with route model binding: Let Laravel inject models directly from routes
  • Don't over-inject: If you only use it once, use method injection