12/08/2018, 13:00

Laravel Beauty: Tìm hiểu về Service container

Laravel Beauty: Recipes & Best Practices Laravel Beauty: Tìm hiểu về Service Container Laravel Beauty: Tìm hiểu về Service Provider Laravel Beauty: Tìm hiểu về Facade Laravel Beauty: Tìm hiểu về Contract Trong bài viết lần trước, mình đã giới thiệu qua về Laravel , cũng như ...

laravel-1.png

  1. Laravel Beauty: Recipes & Best Practices
  2. Laravel Beauty: Tìm hiểu về Service Container
  3. Laravel Beauty: Tìm hiểu về Service Provider
  4. Laravel Beauty: Tìm hiểu về Facade
  5. Laravel Beauty: Tìm hiểu về Contract

Trong bài viết lần trước, mình đã giới thiệu qua về Laravel, cũng như một vài Best Practices mà mình hay sử dụng. Từ bài viết này, mình sẽ tập trung giới thiệu và giải thích về những thành phần core của Laravel Framework, hy vọng có thể giúp các bạn hiểu hơn về cách mà Laravel hoạt động.

Đầu tiên sẽ là về một thành phần được coi là "trái tim" của Laravel, Service Container, thứ mà có thể các bạn đang dùng rất nhiều nhưng lại không biết là đang dùng ở đâu ^^!

Nếu các bạn đã từng làm việc với Laravel 4.2 mà chưa tìm hiểu nhiều về Laravel 5, thì bạn sẽ thấy khái niệm Service Container rất là mới mẻ. Thế nhưng thực chất nó đã tồn tại từ trước đó rồi, ở phiên bản 4.2 đổ về trước thì nó được người ta gọi dưới cái tên "Inversion of Control Container (IoC Container)". Nếu các bạn để ý thì từ phiên bản 5, trên document của Laravel, phần giới thiệu về IoC Container biến mất, và thay vào đó là Service Container.

Do đó, trước tiên hãy nói một chút về Inversion of Control nhé.

Cũng có ý kiến cho rằng Inversion of Control và Dependency Injection là một, và chúng chỉ là 2 cái tên được dùng cho một mục đích. Tuy nhiên, phần nhiều thì cho rằng Dependency Injection là một phần nhỏ của Inversion of Control, và nó là một trong những giải pháp để thực hiện Inversion of Control. Nhìn chung ta có thể hiểu đơn giản như sau:

  • Dependency Injection: Mình đã từng đề cập ở bài viết trước. Nếu một Class A hoạt động phụ thuộc vào một vài Class khác, thì thay vì khởi tạo các instance của các Class kia bên trong Class A, ta sẽ inject những instance đó vào thông qua constructor hay setter. Những instance của các Class mà Class A cần để hoạt động đó được gọi là dependency. Ví dụ:
class Monitor {}
class Keyboard {}
class Computer
{
    protected $monitor;
    protected $keyboard;
    public function __construct($monitor, $keyboard)
    {
        $this->monitor = $monitor;
        $this->keyboard = $keyboard;
    }
}

$computer = new Computer(new Monitor(), new Keyboard());

Như ở ví dụ trên ta có thể thấy class Computer cần các dependency là instance của Monitor và Keyboard. Thay vì khởi tạo các dependency này bên trong constructor của class Computer, ta sẽ inject chúng vào khi gọi new Computer.

  • Inversion of Control: Dưới đây là định nghĩa về IoC trên Wikipedia:

In software engineering, inversion of control (IoC) describes a design in which custom-written portions of a computer program receive the flow of control from a generic, reusable library. A software architecture with this design inverts control as compared to traditional procedural programming: in traditional programming, the custom code that expresses the purpose of the program calls into reusable libraries to take care of generic tasks, but with inversion of control, it is the reusable code that calls into the custom, or task-specific, code.

Trông có vẻ lằng nhằng và khó hiểu phải không? IoC là một kỹ thuật trong lập trình làm "đảo ngược" flow của những xử lý truyền thống. Bình thường thì đoạn xử lý logic của ta sẽ gọi đến những class, library mà nó cần dùng, thế nhưng, với IoC thì ta sẽ gửi cho những đoạn xử lý logic đó những thứ mà nó cần. Hay nói cách khác: Đừng cố gọi khắp nơi để tạo ra những thứ mà bạn cần (dependency), chúng tôi sẽ đưa chúng cho bạn khi chúng tôi cần đến bạn!

Với IoC thì các sự phụ thuộc sẽ được ghép vào các đối tượng tương ứng tại thời điểm run time thay vì compile time.

Nếu bạn vẫn chưa hiểu rõ về IoC thì ta hãy xem qua một ví dụ sau đây:

// With IoC
// Đầu tiên, ta đăng ký với IoC Container
IoC::register('computer', function() {
    $keyboard = new Keyboard();
    $monitor = new Monitor();
    $computer = new Computer($monitor, $keyboard);
    return $computer;
});

// Lấy ra một computer instance với dependency đã được inject
$photo = IoC::resolve('computer');

// Without IoC
$keyboard = new Keyboard();
$monitor = new Monitor();
$computer = new Computer($monitor, $keyboard);

Như ta thấy thì khi cần khởi tạo một instance của Computer, thay vì khởi tạo một cách thông thường bằng từ khóa new rồi truyền các dependency vào cho nó thông qua constructor, thì với IoC, ta sẽ lấy ra khỏi Container bằng hàm resolve, các xử lý tạo dependency cũng như đưa dependency vào trong class cần khởi tạo đều được thực hiện trong hàm callback mà ta đã register với IoC Container.

Với mô hình này thì ta có thể khởi tạo Computer bất cứ khi nào mà không cần phải nhớ xem nó cần những dependency gì. Khi bạn cần thêm module mới cho Computer thì chỉ cần sửa lại hàm callback mà ta đăng ký với IoC Container là xong.

Thật là tuyệt vời là Laravel support IoC out of the box, chúng ta chỉ việc sử dụng.

Như đã nói ở phần đầu, IoC Container ở phiên bản Laravel 4.2 đã được đổi tên lại thành Service Container ở phiên bản 5, với nhiều tính năng mới, tiện dụng hơn được thêm vào. Nhưng nhìn chung thì tư tưởng và cách hoạt động của nó không thay đổi. Service Container vẫn là một nơi quản lý class dependency và thực hiện dependency injection.

Laravel sử dụng hai khái niệm bind để chỉ việc đăng ký một class hay interface với Container, và resolve để lấy ra instance từ Container. Chẳng hạn như ta có một ví dụ về cách bind cũng như cách resolve như sau:

// Binding
App::bind('computer', function() {
    $keyboard = new Keyboard();
    $monitor = new Monitor();
    $computer = new Computer($monitor, $keyboard);
    return $computer;
}

// Resolving.
App::make('computer');
app('computer');
app()->make('computer');
app()['computer']
// Bạn có thấy có quá nhiều cách để bind và resolve không :D
// Hãy khoan nói về chuyện đó vội.
// Những bài sau mình sẽ giải thích kỹ càng về cách thức hoạt động của chúng.

Giống như một ví dụ ở phần trước, ta bind vào Container bằng một callback có xử lý khởi tạo, rồi dùng make để lấy ra, đó là một cách dùng thường thấy. Tuy nhiên ví dụ sau sẽ cho bạn thấy được Service Container của Laravel mạnh mẽ đến thế nào             </div>
            
            <div class=

0