Bỏ qua

Lifecycle & Service Provider

1. Vòng đời Laravel (Laravel Lifecycle)

Khái niệm cơ bản

Vòng đời Laravel là quá trình từ khi nhận request đến khi trả về response. Hiểu đơn giản như "hành trình" của một yêu cầu từ người dùng.

Các bước chi tiết trong vòng đời:

Bước 1: Entry Point (Điểm vào) - Mọi request đều bắt đầu từ file public/index.php - File này load Composer autoloader và khởi tạo Laravel application

Bước 2: HTTP/Console Kernels - Request được gửi đến HTTP Kernel hoặc Console Kernel - HTTP Kernel xử lý web requests, Console Kernel xử lý Artisan commands

Bước 3: Service Providers - Tất cả Service Providers được đăng ký và boot - Đây là nơi các services được binding vào container

Bước 4: Routing - Request được so khớp với routes đã định nghĩa - Middleware được thực thi (before request)

Bước 5: Controller/Action - Controller method được gọi - Business logic được xử lý

Bước 6: Response - Kết quả được trả về dưới dạng Response - Middleware được thực thi (after request)

Bước 7: Terminate - Cleanup và các tác vụ sau khi response được gửi

2. Service Container

Định nghĩa

Service Container là "chiếc hộp" chứa tất cả các services/dependencies của ứng dụng. Nó như một "kho chứa thông minh" biết cách tạo và quản lý objects.

Chức năng chính:

  • Dependency Injection: Tự động inject dependencies vào class
  • Binding: Đăng ký cách tạo objects
  • Resolution: Tạo và trả về objects khi cần

Ví dụ thực tế:

// Binding vào container
app()->bind('PaymentService', function() {
    return new PaymentService(new BankGateway());
});

// Resolve từ container
$paymentService = app('PaymentService');

3. Service Provider

Định nghĩa

Service Provider là nơi đăng ký và cấu hình các services vào Container. Giống như "người quản lý kho" - quyết định có gì trong kho và cách lấy ra.

Hai phương thức chính:

register(): Đăng ký services vào container

public function register()
{
    $this->app->bind('MyService', MyService::class);
}

boot(): Thực hiện các tác vụ sau khi tất cả services đã được đăng ký

public function boot()
{
    // Cấu hình routes, views, etc.
}

4. Các trường hợp load Service Provider

A. Load từ đầu và tắt (Eager Loading)

Khi nào xảy ra: - Service Provider được khai báo trong config/app.php mà KHÔNG có thuộc tính $defer = true - Các core providers như RouteServiceProvider, ViewServiceProvider

Vòng đời:

Khởi tạo App → Load tất cả Eager Providers → register() → boot() → Xử lý request → Terminate

Ví dụ:

// AppServiceProvider - luôn load khi khởi động
class AppServiceProvider extends ServiceProvider
{
    // Không có $defer = true
    public function register() {
        // Đăng ký services ngay khi app khởi động
    }
}

B. Load và chạy mãi (Singleton Services)

Khi nào xảy ra: - Services được bind dưới dạng singleton - Services cần duy trì state trong suốt request lifecycle

Cách hoạt động:

// Bind singleton - chỉ tạo 1 instance duy nhất
$this->app->singleton('CacheManager', function() {
    return new CacheManager();
});

// Mỗi lần resolve đều trả về cùng 1 instance
$cache1 = app('CacheManager'); // Tạo mới
$cache2 = app('CacheManager'); // Trả về instance cũ
// $cache1 === $cache2 (true)

C. Load khi cần - Deferred Providers (Lazy Loading)

Khi nào xảy ra: - Service Provider có $defer = true - Chỉ load khi service thực sự được sử dụng

Ví dụ:

class MailServiceProvider extends ServiceProvider
{
    protected $defer = true; // Đánh dấu là deferred

    protected $provides = ['mailer']; // Khai báo services cung cấp

    public function register()
    {
        $this->app->singleton('mailer', function() {
            return new MailManager();
        });
    }

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

Vòng đời Deferred Provider:

App khởi động → Skip deferred providers → 
Request cần 'mailer' → Load MailServiceProvider → register() → boot() → 
Sử dụng service → End request

5. So sánh các loại Service Provider

Loại Khi load Ưu điểm Nhược điểm Ví dụ
Eager Ngay khi app khởi động Sẵn sàng ngay, nhanh khi sử dụng Tốn memory, chậm boot time RouteServiceProvider
Deferred Khi cần sử dụng Tiết kiệm memory, boot nhanh Chậm lần đầu sử dụng MailServiceProvider
Singleton Lần đầu resolve Tiết kiệm tài nguyên, nhất quán Có thể gây memory leak Database connections

6. Thực hành và Tips phỏng vấn

Câu hỏi thường gặp:

Q: Khác biệt giữa bind() và singleton()? A: - bind(): Mỗi lần resolve tạo instance mới - singleton(): Chỉ tạo 1 instance duy nhất, các lần sau dùng lại

Q: Khi nào nên dùng Deferred Provider? A: Khi service không được sử dụng trong mọi request, ví dụ: Mail, Payment, External APIs

Q: register() và boot() khác nhau như thế nào? A: - register(): Chỉ đăng ký services, KHÔNG sử dụng services khác - boot(): Có thể sử dụng các services đã được đăng ký

Code example cho phỏng vấn:

// Custom Service Provider
class PaymentServiceProvider extends ServiceProvider
{
    protected $defer = true; // Lazy load

    public function register()
    {
        // Đăng ký PaymentService
        $this->app->bind('payment', function($app) {
            return new PaymentService(
                $app['config']['payment.gateway']
            );
        });
    }

    public function boot()
    {
        // Publish config files
        $this->publishes([
            __DIR__.'/config/payment.php' => config_path('payment.php')
        ]);
    }

    public function provides()
    {
        return ['payment']; // Services mà provider này cung cấp
    }
}

7. Tổng kết

Laravel Lifecycle và Service Provider là nền tảng của framework:

  • Container: Quản lý dependencies
  • Service Provider: Cấu hình và đăng ký services
  • Lifecycle: Quy trình xử lý từ request đến response