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