wiki

View on GitHub

Dependency Injection trong PHP

1. Khái niệm liên quan

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 như Inversion of Control, Dependency Inversion, Dependency Injection Container theo đều được phát triển để thực hiện hóa nguyên lý này.

Dependency Injection là một kỹ thuật trong lập trình hướng đối tượng, được sử dụng để giảm thiểu sự phụ thuộc giữa các thành phần trong một hệ thống phần mềm. Nó cho phép chúng ta tạo ra các đối tượng phụ thuộc vào các đối tượng khác thông qua việc “cung cấp” các đối tượng này (dependencies) vào đối tượng đang được tạo ra, thay vì tạo ra các đối tượng đó trong đối tượng hiện tại.

2. 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.

<?php

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.

<?php

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.

3. Ư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

4. Ví dụ

Không sử dụng DI

class Member

<?php

class Member {
    private $name;
    private $position;

    public function __construct($name, $position){
        $this->name = $name;
        $this->position   = $position;
    }

   public function getName()
   {
       return $this->name;
   }
}

class Company

<?php

class Company {
    private $name;
    private $members;

    public function __construct($name){
        $this->name = $name;
    }

    public function addMember($name, $position)
    {
        $member = new Member($name, $position);
        $this->members[] = $member;
    }

    public function getMembers()
    {
        return $this->members;
    }
}

Add Member

<?php

$company = new Company("hapo");
$company->addMember("Pham Dat", "Dev");

Sử dụng DI

class Company

<?php

class Company {
    private $name;
    private $members;

    public function __construct($name){
        $this->name = $name;
    }

    public function addMember(Member $member)
    {
        $this->members[] = $member;
    }

    public function getMembers()
    {
        return $this->members;
    }
}

Add Member

<?php

$company = new Company("hapo");
$member = new Member("Pham Dat", "Dev");
$company->addMember($member);