Bài viết được dịch từ inchoo.net 

Một trong những thay đổi lớn nhất trong Magento 2 là việc sử dụng Dependency Injection design pattern.

Để bắt đầu, tôi sẽ giải thích ý tưởng cơ bản đằng sau pattern này. Trong Dependency Injection, bạn nên truy vấn dữ liệu khi object được tạo. Điều này cho phép tạo class riêng và phát triển độc lập. Ví dụ:

class A
{
  ...
  public function read()
  {
    $dbh = new DatabaseConnection(); // nên tránh
    $dbh->query('SELECT ...');
    ...
  }
  ...
}

Trong ví dụ trên class A sử dụng phương thức read(). Trong phương thức này chúng ta kết nối đến cơ sở dữ liệu ở dòng đầu tiên. Đây là cách mà hầu hết mọi người đang dùng và nó cũng tương tự những gì mà được sử dụng ở Magento 1.x (Với việc sử dụng Factory Pattern). Ở ví dụ tiếp theo sẽ thực hiện cùng một logic nhưng sử dụng Dependency Injection:

class A
{
  protected $_dbh;
  ...
  public function __construct(DatabaseConnection $connection)
  {
    $this->_dbh = $connection;
  }
  ...
  public function read()
  {
    $this->_dbh->query('SELECT ...');
    ...
  }
  ...
}

 Ở trong ví dụ này, trong class A việc kết nối cơ sở dữ liệu diễn ra ở bên trong phương thức __construct thay vì kết nối ở bên trong phương thức read(). Mặc dù vậy đây không phải là cách duy nhất sử dụng dependency trên object, điều này từng được sử dụng trong magento 2. Vì vậy, chính xác chúng ta đã làm được những gì bằng cách này?

Đầu tiên, class A được phát triển tách biệt so với class DatabaseConnection như cách chúng ta có thể dùng để kết nối database. Nó tách biệt so với class DatabaseConection và nó dễ dàng hơn cho việc kiểm tra code.

Một trong những nhược điểm bạn có thể nhận ra là đoạn code thứ hai lớn hơn đoạn trước đó. Trong ví dụ Magento\Catalog\Mode\Product có constructor được viết tới tận 52 dòng. Ngoài ra, nếu bạn thử debug đoạn code này thì bạn sẽ thấy nó là một công việc thực sự khó khăn. 

Để khởi tạo một object lớn như vậy, dependency injection đưa vào Dependency Injection Container, trong magento 2 gọi nó là Objectmanager. Container này có nhiệm vụ giải quyết và tạo mối liên hệ dựa vào đối tượng tạo ra. Cùng xem xét cách hoạt động qua ví dụ sau:

class A
{
  public function __construct(B $b)
  {
    $this->_b = $b;
  }
}

Khi tạo đối tượng từ class A, điều gì sẽ  xảy ra:

1. ObjectManager->create('A') được gọi.

2. Hàm constructor được kiểm tra.

3. Class B được tạo ra và được sử dụng cho việc tạo ra class A.

Ở trong những bước này. ObjectManager đã tạo ra object từ class. Nhưng nhìn nó không đơn giản như thế, chúng ta có nhiều sự thực thi của class B.  Có câu hỏi được đặt ra là sự thi hành nào đã được sử dụng? Và câu trả lời cho câu hỏi đó được tìm thấy ở một trong những file di.xml, nó có thể nằm ở một số vị trí:

  • {moduleDir}/etc/{areaCode}/di.xml
  • moduleDir}/etc/di.xml
  • moduleDir}/etc/di.xml

Ở trong những file này, bạn có thể tìm kiếm / thiết lập cài đặt:

  • Class defintions: Type và number của dependencies . Thật may mắn, Magento 2 sử dụng constructor signature để  biên dịch một cách tự động.
  • Instance configuration: Định nghĩa về tạo ra đối tượng. Điều này có liên quan đến việc thiết lập cho types virtuaTypes , nhưng nó nằm ngoài phạm vi bài viết này.
  • Abstraction-implementation mappings:  Mapping cho phép bạn lựa chọn interface implementation mong muốn.  Đây là điều gì đó tương tự đã có ở Magento 1.x. 

Ở trong Magento 2, object được chia ra thành 2 nhóm: injectablenon-injectable. Đầu tiên là tôi giải thích thế nào là object non-injectable. Còn injectable thì là ngược lại.

Một ví dụ, cùng xem xét trang sản phẩm, nơi bạn muốn hiển thị các sản phẩm hiện có và vài sản phẩm liên quan. Nếu bạn chuyển qua product model tới controller, đầu tiên bạn phải load những sản phẩm đó để lấy sản phẩm hiện tại. Nhưng một khi object được sử dụng, bạn sẽ lấy thông tin các sản phẩm khác ở đâu? Vậy bạn đang nghĩ product model là một trong những non-injectable objects. Thực ra, tất cả Object đều có vài kiểu nhận dạng, có thể là non-injectables: products, orders, cart items, users,... 

Để sử dụng non-injectable object trong code của bạn, bạn phải gọi đến factory. Ví dụ bạn muốn load nhiều sản phẩm, code của bạn phải sẽ dựa vào product factory, qua đó object sẽ gọi đến phương thức create() với định dạng những product bạn muốn load. 

Trên đây là những ví dụ cơ bản về Dependency Injection design pattern trong Magento 2, bạn có thể tham khảo thêm chi tiết hơn tại đây http://devdocs.magento.com/guides/v2.1/extension-dev-guide/depend-inj.html​.