Dependency Injection trong PHP
Bài đăng này đã không được cập nhật trong 7 năm
Khái niệm liên quan
-
Dependency Injection
(DI) là khái niệm thường được nghe trong giới lập trình. Có khá nhiều cái tên nghe liên quan và na ná nhau làm dev bị hoang mang như:Dependency Injection
,Inversion of Control
,Dependency Inversion
,Dependency Injection Container
. -
Các khái niệm trên được hiểu như sau:
Dependency Inversion
là một nguyên lý để thiết kế và viết code trong 5 nguyên lý S.O.L.I.D do Robert C.Martin viết. Các khái niệm tiếp theo đều được phát triển để thực hiện hóa nguyên lý này.Inversion of Control
(IoC) là mộtdesign pattern
được tạo ra có thể tuân thủ nguyên lýDependency Inversion
trong thiết kế và code. Có nhiều cách hiện thực pattern này: ServiceLocator, Event, Delegate, …Dependency Injection
là một trong các cách đó.Dependency Injection
là một phương thức để thực hiện design parternInversion of Control
, tức là một phương thức để viết code tốt hơn.Dependency injection container
là một tool để giúp DI tốt hơn, đơn giản hơn , phổ biết trongPHP
như làPHP-DI
,Dice
,Symfony-dependency
,Pimple
...
Các cách Dependency Injection
Có 3 dạng Dependency Injection:
Constructor Injection
- Các dependency sẽ được container truyền vào (inject vào) 1 class thông qua constructor của class đó. Đây là cách thông dụng nhất.
class A {
public $b;
public function __construct(B $b)
{
$this->b = $b;
}
}
Setter Injection
- Các dependency sẽ được truyền vào 1 class thông qua các hàm Setter.
class A {
public $b;
public function __construct()
{
}
public function setB(B $b)
{
$this->b = $b;
}
}
Interface Injection
- Class cần inject sẽ implement 1 interface. Interface này chứa 1 hàm tên Inject. Container sẽ injection dependency vào 1 class thông qua việc gọi hàm Inject của interface đó. Đây là cách rườm rà và ít được sử dụng nhất.
Ưu điểm và khuyết điểm của DI
Ưu điểm
- Giảm sự kết dính giữa các module
- Code dễ bảo trì, dễ thay thế module
- Rất dễ test và viết Unit Test
- Dễ dàng thấy quan hệ giữa các module (vì các dependecy đều được inject vào constructor)
Khuyết điểm
- Khái niệm DI khá khó cho các developer mới
- Sử dụng interface nên đôi khi sẽ khó debug, do không biết chính xác module nào được gọi
- Các object được khởi tạo toàn bộ ngay từ đầu, có thể làm giảm performance
- Làm tăng độ phức tạp của code
Đối vơi dự án lớn thì việc sử dụng DI là cần thiết vì code sẽ linh hoạt, dễ mở rộng và bảo trì. Hiên nay, tất cả các Framework PHP đều dùng DI
Dependency injection container (DI container)
- Có một vấn đề đặt ra trong DI đó là. Các module inject chia thành nhiều tầng nhiều lớp. Ví dụ module
A
injectB
,B
injectC
,C
injectD
,D
injectE
,F
... Khi số lượng module inject lớn thì việc kiểm soát DI rất phức tạp khi khởi tạo đối tượngA
. Chúng ta phải biết rõ từng module inject vào phụ thuộc module nào.
$a = new A(new B(new C(new D(new E, new F))));
Dependency injection container
ra đời để giải quyết vấn đề này. Tức là chúng ta sẽ khởi tạo đối tượng qua DI container mà không cần quan tâm đến các phụ thuộc DI của nó. DI container sẽ tự động inject chính xác các DI cần thiết. Điều này rất tuyệt vời.- Ví dụ mình sẽ dùng
Dice
DI container để khởi tạo một instanceA
vô cùng đơn giản. Các DI nhưB
,C
,D
,E
,F
đã tự động inject rồi.
require_once 'Dice.php';
$dice = new \Dice\Dice;
$a = $dice->create('A');
Kết luận
DI
là một kĩ thuật tuyệt vời để thiết kết và code rõ ràng, mạch lạc, dễ mở rộng và bảo trì hơn. Việc sử dụngDI container
sẽ giúp việcDI
dễ dàng và đơn giản hơn. Vậy nên việc ứng dụngDI
vàDI container
sẽ giúp chúng ta có những đoạn code pro hơn, nâng cao trình độ hơn.
All rights reserved