I. Khái niệm Service Container
Theo Laravel docs mô tả:
The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection.
Tạm dịch là:
Laravel service container là một tool mạnh mẽ để quản lý các class dependencies(class phục thuộc) và triển khai dependency injection.
Thế trong đầu lại hiện lên câu hỏi, thế "class dependencies" và "dependency injection" là gì?. Thật là rắc rồi phải không nào😅😅😅 Thế mình sẽ đi qua "class dependencies" và "dependency injection" trước đã nhé, nắm bắt được các khái niệm này thì sẽ giúp ta dễ hiểu hơn rất nhiều.
II. Class dependencies
Khi một Class A sử dụng một số function của Class B thì người ta nói rằng: Class A có quan hệ phụ thuộc(dependency) với Class B
Code minh họa
<?php class Http
{ function get($url) { // todo }
} Class Crawler
{ function crawl($url) { $http = new Http(); $res = $http->get($url); }
}
Ta thấy rằng trong function crawl() của class Crawler dùng tới function get() của class Http.
III. Dependency injection
Dependency injection(DI) là một kĩ thuật lập trình bla bla ... nếu đọc thấy sẽ hơi khó hiểu. Chúng ta hiểu đơn giản ntn. DI là một kĩ thuật giúp ta triển khai bằng cách "tiêm" class phụ thuộc vào class chính. Về tiêm thì chúng ta có 3 cách:
1. Constructor Injection
Tiêm thông qua hàm khởi tạo (function __contstructor)
2. Setter Injection
Tiêm thông qua hàm setter/gettter
3. Interface Injection
Tiêm thông qua interface
Trong Php thì chúng ta hay gặp trường hợp thứ nhất tức là Constructor Injection. Nên các vị dụ của chúng ta sẽ sử dụng cách triển khai tiêm qua contructor. Đây là một ví dụ code php thuần:
<?php Class Http
{ function get($url) { echo 1; }
} Class Crawler
{ private $http; function __construct() { $this->http = new Http(); } function doCraw($url) { $res = $this->http->get($url); }
}
Như ta thấy để triển khai DI ta cần làm 3 điều:
- Khai báo 1 property $http
- Trong hàm khởi tạo(constructor) của class Crawler ta triển khai tiêm instance của class Http vào property $http
- Khi dùng function của Http trong class Crawler thì chỉ cần gọi $this->http->get()
Đây là code trong Laravel:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;
use App\Repositories\UserRepository;
use App\Models\User;
use Illuminate\View\View; class UserController extends Controller
{ /** * Create a new controller instance. */ public function __construct( protected UserRepository $users, ) {} /** * Show the profile for the given user. */ public function show(string $id): View { $user = $this->users->find($id); return view('user.profile', ['user' => $user]); }
IV. Quay lại Service Container
Giờ chúng ta đã nắm được 2 khái niệm "class dependencies" và "dependency injection" rồi, hãy trở về Laravel nhé! Nhắc lại khái niệm đã nêu ở đầu bài.
Laravel service container là một tool mạnh mẽ để quản lý các class dependencies(class phục thuộc) và triển khai dependency injection.
Luận giải: Laravel cung cấp một cái gọi là "Service container" rất là mạnh mẽ. Chốc bằng code mình sẽ cho các bạn nhìn thấy cái tool mạnh mẽ của laravel này. Cái tool này sinh ra để nhằm mục đích là triển khai DI tức là nó sẽ tiếp nhận các class phụ thuộc và có cách thức lôi các class phụ thuộc này ra dùng. Như vậy Service container là nơi chứa và triển khai các class phụ thuộc. Tại sao nó lại quan trọng trong thiết kế của Laravel Architecture, bởi vì đây là nơi quản lý mọi class lớn nhỏ trong Laravel. Nó vô cùng quan trọng.
Bài toán triển khai thực tế dưới dạng kịch bản:
Coder: Ê Laravel, tao có vài function của class này này muốn dùng trong Laravel, mày có cách nào ko?
Laravel Architecture: Có chứ mày, mày vứt class đó vào Service container đi, để nó quản lý, lúc nào mày cần dùng thì nó có phương thức để mày lôi ra dùng thôi.
Coder: Ok mày, tao hiểu rồi. Thế triển khai coding như thế nào?
Laravel Architecture: Đây, đọc đi, dễ hiểu mà
<?php use Illuminate\Support\Facades\Route; /*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
class FirstClass
{ public function print1() { echo 'print1'; } public function dodo() { echo 'baby shark dodo'; }
} class SecondClass
{ public function print2() { echo 'print2'; }
} Route::get('/', function () { // 1. khởi tạo 1 service container $serviceContainer = new Illuminate\Container\Container(); // 2. binding vào service container $serviceContainer->bind('class1', function () { return new FirstClass(); }); // 3. lôi instance của class đã đăng ký vào $instanceOfClass1 = $serviceContainer->make('class1'); // 4. sử dụng các function của class1 $instanceOfClass1->print1(); echo "<br>"; $instanceOfClass1->dodo(); })->name('top');
Giải thích xíu nhé:
- Khởi tạo 1 service container, cái mà gọi là 1 tool mạnh mẽ đấy
- Binding 1 class FirstClass vào service container và đặt tên nó là "class1"
- Resolve hay gọi cách khác lôi instance của class đó ra
- Sử dụng các hàm của "class1"
Và đây là kết quả
print1
baby shark dodo
Đến đây thì mọi người đã hiểu Service container là gì, sử dụng để làm gì và cách sử dụng rồi. Bài sau mình sẽ nói thêm 1 chút về việc dùng Service container như thế nào cho chuẩn và có các kiểu binding nào!