Dependency Injection và Container trong PHP
Trong bài học này, bạn sẽ tìm hiểu về Dependency Injection (DI) – một kỹ thuật lập trình giúp mã nguồn tách rời các thành phần phụ thuộc vào nhau, từ đó dễ kiểm thử và mở rộng. Đồng thời, bạn sẽ được giới thiệu Service Container, một công cụ quản lý và cung cấp các dependency một cách tự động và linh hoạt. Đây là một kỹ năng cốt lõi để xây dựng ứng dụng PHP hiện đại, đặc biệt là khi làm việc với framework hoặc viết kiến trúc module hóa.

1. Dependency là gì?
Trong lập trình, một dependency (sự phụ thuộc) là một đối tượng mà một lớp cần sử dụng để hoạt động.
Ví dụ:
class Logger {
public function log($message) {
echo "Log: $message";
}
}
class UserService {
private $logger;
public function __construct() {
$this->logger = new Logger(); // hardcoded dependency
}
public function register($username) {
// Logic đăng ký
$this->logger->log("User $username registered");
}
}
Vấn đề ở đây: UserService
phụ thuộc chặt vào lớp Logger
. Nếu muốn thay Logger, sẽ phải sửa đổi mã gốc.
2. Dependency Injection là gì?
Dependency Injection (DI) là kỹ thuật đưa dependency vào từ bên ngoài thay vì khởi tạo bên trong lớp.
3 cách phổ biến để inject dependency:
- Constructor Injection
- Setter Injection
- Method Injection
Ví dụ - Constructor Injection:
class UserService {
private $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function register($username) {
$this->logger->log("User $username registered");
}
}
// Khởi tạo bên ngoài
$logger = new Logger();
$userService = new UserService($logger);
$userService->register("admin");
Ưu điểm:
- Dễ kiểm thử (test được
UserService
với mockLogger
) - Dễ thay thế
Logger
(ví dụ: FileLogger, DatabaseLogger…)
3. Service Container là gì?
Một Service Container là nơi chứa, cấu hình và cung cấp các dependency. Bạn định nghĩa các service (class) một lần, rồi gọi ở bất kỳ đâu.
Giống như một "hộp đựng các dependency", container giúp bạn không phải khởi tạo thủ công và quản lý vòng đời các đối tượng.
4. Tự xây dựng Service Container đơn giản
Bước 1: Tạo Container class:
class Container {
protected $services = [];
public function set($name, callable $resolver) {
$this->services[$name] = $resolver;
}
public function get($name) {
if (isset($this->services[$name])) {
return $this->services[$name]($this);
}
throw new Exception("Service $name not found");
}
}
Bước 2: Đăng ký và sử dụng:
$container = new Container();
$container->set('logger', function() {
return new Logger();
});
$container->set('userService', function($c) {
return new UserService($c->get('logger'));
});
$service = $container->get('userService');
$service->register("john");
Lợi ích:
- Tự động quản lý dependency
- Không cần "new" khắp nơi
- Hỗ trợ lazy-loading (chỉ tạo khi cần)
- Rất gần với cách framework Laravel, Symfony… hoạt động
5. Ứng dụng thực tế với cấu trúc tách lớp
Ví dụ tình huống thực tế: Bạn muốn sử dụng FileLogger
thay vì Logger
gốc.
class FileLogger extends Logger {
public function log($message) {
file_put_contents('log.txt', "Log: $message\n", FILE_APPEND);
}
}
$container->set('logger', function() {
return new FileLogger(); // thay thế dễ dàng
});
Bạn không cần sửa UserService
hay controller — mọi thay đổi được thực hiện tại Container
.
Kết luận
Bài học này đã giúp bạn hiểu và áp dụng:
- Dependency Injection để làm cho ứng dụng dễ kiểm thử, mở rộng, và linh hoạt hơn.
- Service Container như một công cụ trung tâm để quản lý dependency một cách hiệu quả.
Đây là nền tảng quan trọng cho các kiến trúc chuyên nghiệp, đặc biệt khi bạn phát triển ứng dụng lớn hoặc sử dụng framework hiện đại như Laravel, Symfony, Slim, v.v.
Bài tập thực hành
- Viết một class
Mailer
và inject vàoUserService
để gửi email khi đăng ký. - Tạo một Service Container đơn giản để quản lý
Logger
,Mailer
, vàUserService
. - Thay thế
Logger
bằng một class khác (ví dụDatabaseLogger
) thông qua container mà không sửa mãUserService
.

Với hơn 10 năm kinh nghiệm lập trình web và từng làm việc với nhiều framework, ngôn ngữ như PHP, JavaScript, React, jQuery, CSS, HTML, CakePHP, Laravel..., tôi hy vọng những kiến thức được chia sẻ tại đây sẽ hữu ích và thiết thực cho các bạn.
Xem thêm

Chào, tôi là Vũ. Đây là blog hướng dẫn lập trình của tôi.
Liên hệ công việc qua email dưới đây.
lhvuctu@gmail.com