Hướng dẫn php parameter injection - tiêm tham số php

Hướng dẫn php parameter injection - tiêm tham số php

Đã đăng vào thg 5 4, 2017 6:53 SA 4 phút đọc 4 phút đọc

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ột
      class A {
         public $b;
      
         public function __construct()
         {
            
         }
      
         public function setB(B $b)
         {
             $this->b = $b;
         }
      }
      
      
      1 đượ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 partern Inversion of Control, tức là một phương thức để viết code tốt hơn.
    • class A {
         public $b;
      
         public function __construct()
         {
            
         }
      
         public function setB(B $b)
         {
             $this->b = $b;
         }
      }
      
      
      6 là một tool để giúp DI tốt hơn, đơn giản hơn , phổ biết trong
      class A {
         public $b;
      
         public function __construct()
         {
            
         }
      
         public function setB(B $b)
         {
             $this->b = $b;
         }
      }
      
      
      7 như là
      class A {
         public $b;
      
         public function __construct()
         {
            
         }
      
         public function setB(B $b)
         {
             $this->b = $b;
         }
      }
      
      
      8,
      class A {
         public $b;
      
         public function __construct()
         {
            
         }
      
         public function setB(B $b)
         {
             $this->b = $b;
         }
      }
      
      
      9,
      
      $a = new A(new B(new C(new D(new E, new F))));
      
      
      0,
      
      $a = new A(new B(new C(new D(new E, new F))));
      
      
      1 ...

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 = new A(new B(new C(new D(new E, new F))));
    
    
    2 inject
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    3,
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    3 inject
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    5,
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    5 inject
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    7,
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    7 inject
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    9,
    require_once 'Dice.php';
    $dice = new \Dice\Dice;
    
    $a = $dice->create('A');
    
    
    0... 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ượng
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    2. 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))));

  • class A {
       public $b;
    
       public function __construct()
       {
          
       }
    
       public function setB(B $b)
       {
           $this->b = $b;
       }
    }
    
    
    6 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
    class A {
       public $b;
    
       public function __construct()
       {
          
       }
    
       public function setB(B $b)
       {
           $this->b = $b;
       }
    }
    
    
    9 DI container để khởi tạo một instance
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    2 vô cùng đơn giản. Các DI như
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    3,
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    5,
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    7,
    
    $a = new A(new B(new C(new D(new E, new F))));
    
    
    9,
    require_once 'Dice.php';
    $dice = new \Dice\Dice;
    
    $a = $dice->create('A');
    
    
    0 đã tự động inject rồi.
require_once 'Dice.php';
$dice = new \Dice\Dice;

$a = $dice->create('A');

Kết luận

  • Dependency Injection0 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ụng Dependency Injection1 sẽ giúp việc Dependency Injection0 dễ dàng và đơn giản hơn. Vậy nên việc ứng dụng Dependency Injection0 và Dependency Injection1 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