Laravel Service Container
# Description
- Service Container là nơi quản lí và thực hiện các dependency của Laravel.
- Để hiểu hơn về dependency, refer Dependency injection và Invertion of Control.
# Binding & Resolving
- Binding: Register 1 dependency vào container.
- Resolving: Lấy ra dependency trong container để sử dụng.
Với lập trình truyền thống, muốn sử dụng 1 class bạn phải chủ động khởi tạo class. Còn Laravel, các class đó đã được register tại service container, chỉ cần resolving để lấy ra sử dụng thôi. Đó là ý nghĩa của Invertion "đảo nghịch" trong IoC.
Các dependency mặc định của Laravel có thể xem tạo config/app.php
# Binding method:
Một vài method binfing cơ bản:
Singleton: Chỉ trả về 1 object instance dù resolved ở bất kì đâu. Thường sử dụng cho logger, configure,...
use App\Services\Logger; $this->app->singleton(Logger::class, function () { return new Logger(); }) // $logger1 = App::make(Logger::class); $logger1->setOutputFile("logs/app.log"); // $logger2 = App::make(Logger::class); echo $logger2->getOuputFile(); // "logs/app.log"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Instance: Binding 1 object instance và resolved instance ở trong application.
use App\Services\Transistor; use App\Services\PodcastParser; $service = new Transistor(new PodcastParser); $this->app->instance(Transistor::class, $service); // $transistor = App::make(Transistor::class); // Không cần set PodcastParser trong contructor của Transistor, // vì PodcastParser đã được inject vào contructor của Transistor tại container rồi
1
2
3
4
5
6
7
8
9
10
11Interface: Binding interface cho implement. Linh hoạt khi muốn thay đổi lớp implement, maintain, test,..
Có thể type hinting interface ở mội nơi trong application. Container sẽ tự động resolved implement đã được binding cho interface đó.
"program to an interface, not an implementation"
use App\Contracts\UserRepository; use App\Services\User; $this->app->bind(UserRepository::class, User::class); // ------ public function __construct(UserRepository $userRepository) { $this->userRepository = $userRepository; } // $userRepository: hiện tại là 1 instance của User // Muốn thay đổi lớp implement chỉ cần binding lại lớp implement khác trong container // mà không cần thay đổi code ở Logic khi sử dụng interface UserRepository
1
2
3
4
5
6
7
8
9
10
11
12
13
14- Contextual: Inject lớp implement khác nhau cho từng class
$this->app->when(FooController::class) ->needs(Notification::class) ->give(function () { return SlackNotification(); }); $this->app->when([Bar1Conttoller::class, Bar2Conttoller::class]) ->needs(Notification::class) ->give(function () { return MailkNotification(); }); // FooController container sẽ tự động inject SlackNotification cho interface Notification // Bar1Conttoller, Bar2Conttoller là MailkNotification
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Auto Inject:
Laravel Container sẽ auto inject các dependency được type hinting trong application.
// extends example of UserRepository
// App\Services\User;
class User {
protected $userModel;
public function __construct(UserModel $userModel) {
$this->userModel = $userModel;
}
}
// UserController đang type-hint UserRepository()
// UserService đang type-hint UserModel() -- UserRepository đã được binding với UserService
2
3
4
5
6
7
8
9
10
11
12
13
Nếu không có container, khi sử dụng sẽ cần:
new UserController(new UserService(new UserModel()));
Laravel Container auto tìm các instance dependency và inject cho bạn. Nhờ sử dụng DI Container, ReflectionClass và đệ quy.
Xem thêm: DI Container (opens new window) Tạo DI Container (opens new window)