Kiến thức phần này sẽ hơi dài và khó hiểu cho người mới bắt đầu.
Các bạn có thể tham khảo tại đây: https://laravel.com/docs/11.x/container#binding
Tuy nhiên nó sẽ hơi khó hiểu cho người mới bắt đầu. Mình sẽ chắt lọc và giải thích một cách “dân giã”, dễ hiểu nhất cho các bạn. Hãy chuẩn bị một tách coffee và một tinh thần thoải mái trước khi bắt đầu nhé.
1. Lý do khởi đầu
Gỉa sử các bạn có 2 classes là: UserController và UserInfo
trong đó
UserController: đơn giản nhiệm vụ là trả về thông tin người dùng
UserInfo: làm nhiệm truy xuất thông tin người dùng
Có nghĩa là UserController muốn trả về thông tin người dùng thì phải thông qua UserInfo
Với PHP đơn thuần, các bạn sẽ làm như thế này
$userInfo = new UserInfo() ;
/* Tiếp theo UserController sẽ dựa vào thông tin lấy được bên trên để xử lý tiếp
và trả về kết quả. */
$userInformation = new UserController($userInfo);Chuyện gì sẽ xảy ra nếu chúng ta có thêm 2 classes:
UserAddress – làm nhiệm vụ cung cấp thông tin của user.
UserAccount – làm nhiệm vụ trả ra các thông tin chung như: tên, tuổi, số điện thoại,…
Về mặt coding chúng ta sẽ phải làm như thế này
// khởi tạo và truy xuất thông tin user address.
$userAddress = new UserAddress();
// khởi tạo và truy xuất thông tin user account.
$userAccount= new UserAccount();
// UserRepository cần address để cung cấp đầy đủ thông tin user.
$userInfo = new UserInfo($userAddress, $userAccount);
// cuối cùng rồi đến UserController
$userController = new UserController($userInfo);
Ở đây chúng ta nhìn thấy sự phụ thuộc lẫn nhau ở mức đơn giản. Nhưng hãy tưởng tượng trong một dự án thì sự phụ thuộc sẽ rất nhiều, tạo ra sự cồng kềnh và phức tạp trong quá trình phát triển.
Ví dụ: Sau này nếu muốn sử dụng UserInfo ở một chỗ khác (Chẳng hạn như OrderController – làm nhiệm vụ trả ra thông tin về đơn hàng), các bạn sẽ lại phải khái báo như trên một lần nữa. Hoặc UserAccount lại có thêm sự phụ thuộc khác (Chẳng hạn như phụ thuộc vào UserBankInfo – làm nhiệm vụ cung cấp thông tin thanh toán của user), các bạn lại phải khai báo thêm sự phụ thuộc, update lại code ở những nơi các bạn đã từng khai báo,… Nói chung rất rườm rà tốn công.
Vậy làm thế nào để giải quyết vấn đề này ?
2. Inversion Of Control Container (IoC container)
Dịch nghĩa là “Đảo ngược sự kiểm soát” =)). Cơ bản hiểu như sau
Với ví dụ truyền thống ở trên, muốn UserController trả về thông tin user thì bạn phải khai báo UserInfo trước UserController. Tương tự, muốn có có thông tin về UserAccount thì các bạn lại phải khai báo UserAccount trước UserInfo…
Phương pháp “Inversion Of Control” sẽ “đảo ngược” điều này.
Hiểu như sau:
IoC Container sẽ “đăng ký” sự phụ thuộc trước
// Trước hết đừng quan tâm tới đoạn mã dưới đây, nó chỉ là đoạn mã giả để minh họa
// Đăng ký dependences với IoC Container
Ioc::register('userInfo', function(){
$account = new UserAccount();
$address = new UserAddress();
return new UserInfo($account, $address);
});
// Sau khi đăng ký UserInfo với Ioc Container rồi. Chúng ta có thể sử dụng UserInfo ở bất kỳ đâu chúng ta muốn mà không quan tâm UserInfo đang cần những phụ thuộc nào
// Giờ muốn sử dụng cho UserController thì đơn giản là gọi UserInfo ra và xài
$userInfo = IoC::resolve('userInfo');
$userController = new UserController($userInfo)
// Hoặc sử dụng cho OrderController
$userInfo = IoC::resolve('userInfo');
$orderControlelr = new OrderController($userInfo)Như vậy, với việc chỉ cần đăng ký một lần, các bạn có thể sử dụng các class mà không cần quan tâm tới sự phụ thuộc của nó nữa. Rất tiện phải không
Trong laravel, tư tưởng giải quyết bài toán cũng tương tự như trên, họ gọi nó là Service Container. Trong bài sau chúng ta sẽ xem laravel làm như nào nhé.
Hay nghỉ ngơi và chuẩn bị xem bài tiếp nhé ! 🙂