Mô hình lập trình DI - Dependency Injection trong PHP
Show Nội dung chính
dependency : Giả sử bạn có một lớp classA, lớp này có sử dụng một chức năng từ đối tượng lớp classB (classA hoạt động dựa vào classB). Lúc đó classB gọi là phụ thuộc (dependency) (của classA) Bằng cách sử dụng mô hình Dependency Injection ta dễ dàng bảo trì code và module hóa ứng dụng. Tất cả các project đều có các thành phần phụ thuộc vào nhau, dự án càng lớn thì càng nhiều thành phần phụ thuộc, thì cơ chế DI giúp cho quản lý các thành phần phụ thuộc này tốt nhất. Giờ bạn tạo ra 2 lớp mà chúng không sử dụng cơ chế DI, sau đó viết lại có sử dụng DI để xem sự khác biệt: Lớp thứ nhất là class StockItem { private $quantity; private $status; public function __construct($quantity, $status){ $this->quantity = $quantity; $this->status = $status; } public function getQuantity(){ return $this->quantity; } public function getStatus(){ return $this->status; } } Lớp class Product { private $stockItem; private $code; public function __construct($code, $stockQuantity, $stockStatus){ $this->stockItem = new StockItem($stockQuantity, $stockStatus); $this->code = $code; } public function getStockItem(){ return $this->stockItem; } public function getCode(){ return $this->code; } } $product = new Product("101010", 50, "Áo Dài"); var_dump($product->getStockItem()); Code trên tạo ra lớp Với cách sử dụng code như trên, đó là đoạn code bình thường không có vấn đề gì về logic, nhiều khi đánh giá là đoạn code tốt. Tuy nhiên khi vận hành, bảo trì, mở rộng có thể phát sinh một số vấn đề:
Viết lại với Dependency InjectionTiêm vào đối tượng các thành phần phụ thuộc cần thiết: class Product { private $stockItem; private $code; public function __construct($code, StockItem $stockItem){ $this->stockItem = $stockItem; $this->code = $code; } public function getStockItem(){ return $this->stockItem; } public function getCode(){ return $this->code; } } $stockItem = new StockItem(50, "Áo Dài"); $product = new Product("101010", $stockItem); var_dump($product->getStockItem()); Với cách viết thứ 2 này, đối tượng StockItem không còn khởi tạo bên trong hàm tạo Product nữa, mà nó
được truyền vào (tiêm) Product thông qua chính đối tượng StockItem, như vậy khi thay đổi cách khởi tạo StockItem thì lớp Product không phải thay đổi gì. Đó chính là khái niệm Các kiểu Dependency InjectionViệc đưa đối tượng phụ thuộc vào một đối tượng khác (tiêm - inject) được thực hiện qua mấy cách sau: Constructor Injection - Inject qua hàm tạoỞ ví dụ trên chính là sử dụng kiểu Constructor Injection, với cách này có một số đặc điểm
Setter Injection - Inject thông qua hàm setterThành phần phụ thuộc được tiêm (truyền) vào đối tượng thông qua hàm setter. Ví dụ: class Product { private $stockItem; private $code; public function __construct($code){ $this->code = $code; } public function getStockItem(){ return $this->stockItem; } public function getCode(){ return $this->code; } public function setStockItem(StockItem $stockItem){ $this->stockItem = $stockItem; } } $stockItem = new StockItem(50, "Áo Dài"); $product = new Product("101010"); $product->setStockItem($stockItem); var_dump($product->getStockItem()); Như vậy đối tượng phụ thuộc vào
Interface Injection - Inject qua giao diện lớpVới cách này định nghĩa một giao diện sao cho các thành phần phụ thuộc được tích hợp vào mã triển khai giao diện: interface ProductInterface { public function getStockItem(); public function setStockItem(StockItem $stockItem); Khi triển khai giao diện Dependency Injection Container - Trình chứa DITrên đây là toàn bộ cách inject một đối tượng này vào đối tượng khác sao cho chúng không phụ thuộc vào nhau cứng nhắc, với một đối tượng có một vài đối tượng phụ thuộc vấn đề sẽ không có gì, tuy nhiên khi lượng đối tượng phụ thuộc là lớn thì lại trở lên rất phức tạp để quản lý nó. Lúc này giải pháp đưa ra cần tạo một trình chứa chuyên quản lý tất cả các đối tượng độc lập, từ autoload, khởi tạo, thiết lập và inject vào đối tượng khác. Đó là Dependency Injection Container (DI Container), chương trình quản lý - khởi tạo các đối tượng tập trung. Trong PHP, công đồng lập trình thống nhất đưa ra một giao diện của DI Container, interface này được mô tả tại: psr-11 và code giao diện lưu trên github: php-fig/container. Nếu muốn phát triển DI Container đúng chuẩn, bạn nên triển khai từ giao diện trên. Các PHP Framework hiện nay có sử dụng DI hầu hết đều triển khai từ giao diện này. Đây là danh sách các thư viện, framework PHP có triển khai DI Container trên: psr/container-implementation, bạn thấy có : lavarel, symfony, laminas (zend framework), joomla ... |