Request Lifecycle
Tổng quan
Hiểu rõ cách PHP Framework xử lý một HTTP request từ đầu đến cuối sẽ giúp bạn nắm vững framework và xây dựng ứng dụng hiệu quả hơn. Vietiso được xây dựng trên Swoole - một PHP extension hỗ trợ async I/O, nên lifecycle có một số điểm khác biệt so với các PHP framework truyền thống.
Khởi động ứng dụng
1. Entry Point
Mọi thứ bắt đầu từ file vietiso ở thư mục gốc - đây là CLI entry point của framework:
<?php
// vietiso
// Load core
require_once 'core/constants.php';
require_once 'core/functions.php';
require_once 'vendor/autoload.php';
// Khởi tạo App singleton
App::getInstance()
->setBasePath(__DIR__)
->withMiddleware(static function (MiddlewareCollection $middlewares): void {
$middlewares->use([
LogRequest::class,
HandleCors::class,
HandleException::class,
TrimStrings::class,
ConvertEmptyStringsToNull::class,
]);
})
->start();
2. Boot Service Providers
Khi start() được gọi, framework sẽ boot tất cả Service Providers đã đăng ký trong core/providers.php. Quá trình này gồm 2 pha:
- Register phase: Mỗi provider đăng ký các services vào Container
- Boot phase: Sau khi tất cả services đã đăng ký, mỗi provider thực hiện khởi tạo (ví dụ: load config, kết nối database)
EnvironmentServiceProvider → Load .env
ConfigServiceProvider → Load config files
DatabaseServiceProvider → Setup database connections
RoutingServiceProvider → Register routes
ModuleServiceProvider → Discover & install modules
... (33 providers)
3. Swoole HTTP Server
Sau khi boot xong, Swoole HTTP Server bắt đầu lắng nghe connections:
// core/Http/Server.php
$swooleServer = new \Swoole\Http\Server($host, $port);
$swooleServer->start();
Server chạy với nhiều worker processes, mỗi worker xử lý nhiều requests đồng thời nhờ coroutines.
Xử lý Request
4. Nhận Request
Khi có HTTP request đến, Swoole gọi event handler onRequest:
#[Event('Request')]
public function onRequest(SwooleRequest $swooleRequest, SwooleResponse $swooleResponse): void
{
// Đăng ký cleanup sau khi request kết thúc
Coroutine::defer([$this, 'terminateRequest']);
// Khởi tạo Request object
$request = $this->app->get('request');
$request->initRequest($swooleRequest);
// Dispatch qua routing và middleware
$response = $this->app->get('route.dispatcher')->handle($request);
// Gửi response
$response->prepare($request);
$response->send($swooleResponse);
}
5. Request Initialization
Request object được tạo mới cho mỗi request (scoped binding) và parse dữ liệu từ Swoole:
- Headers: Từ
$swooleRequest->header - Query Parameters: Từ
$swooleRequest->get - POST Data: Từ
$swooleRequest->post - JSON Body: Tự động parse nếu
Content-Type: application/json - Files: Từ
$swooleRequest->files - Cookies: Từ
$swooleRequest->cookie
6. Route Matching
RouteDispatcher sử dụng FastRoute để match URI với routes đã đăng ký:
$routeInfo = $this->dispatch($request->method(), $request->uri());
switch ($routeInfo[0]) {
case Dispatcher::NOT_FOUND:
// 404 Not Found
break;
case Dispatcher::METHOD_NOT_ALLOWED:
// 405 Method Not Allowed
break;
default:
// Route found → lấy controller action
$route = $routeInfo[1];
$params = $routeInfo[2];
break;
}
7. Middleware Pipeline
Request đi qua chuỗi middleware trước khi đến controller. Middleware được thực thi theo thứ tự từ ngoài vào trong (request) và từ trong ra ngoài (response):
Request → LogRequest
→ HandleCors
→ HandleException
→ TrimStrings
→ ConvertEmptyStringsToNull
→ [Route Middleware]
→ Controller Action
← [Route Middleware]
← ConvertEmptyStringsToNull
← TrimStrings
← HandleException
← HandleCors
← LogRequest
Response ←
Pipeline được xây dựng bằng pattern nested closures:
$response = $this->stackMiddleware
->send($request)
->through($middlewares)
->then($controllerCallback);
8. Parameter Resolution
Trước khi gọi controller method, framework sử dụng Reflection để tự động resolve parameters.
- Constructor: inject được mọi service từ Container (UserService, CacheManager...)
- Controller method: chỉ inject được Request, ValidatedDTO, Model binding, Enum và route params
class UserController
{
// Constructor injection - inject services
public function __construct(
private UserService $userService,
) {}
#[Post('/users')]
public function store(Request $request, CreateUserDTO $dto)
{
// $request: inject Request instance hiện tại
// $dto: tự động validate từ request data
// Services dùng qua $this->userService
return $this->userService->create($dto);
}
#[Get('/users/{id}')]
public function show(User $user)
{
// $user: Route Model Binding - tự động query findOrFail($id)
return $user;
}
}
Các loại parameter hỗ trợ trong controller method:
| Type | Hành vi |
|---|---|
Request | Inject Request instance hiện tại |
ValidatedDTO | Validate request data và tạo DTO |
Model | Route Model Binding - query findOrFail() theo route param |
Enum | Cast route parameter sang PHP Enum |
| Scalar types | Lấy từ route parameters (int $id, string $slug) |
9. Controller Execution
Controller được instantiate qua Container (hỗ trợ constructor injection cho services), sau đó method được gọi với các parameters đã resolve.
10. Response
Controller trả về Response object. Framework hỗ trợ nhiều kiểu return:
// Array → tự động chuyển thành JSON
return ['status' => 'success'];
// Response object
return Response::json($data, 201);
// Responsable interface
return $user; // Model implement Responsable
Kết thúc Request
11. Prepare & Send
Response được chuẩn bị (thêm headers cần thiết) và gửi qua Swoole:
$response->prepare($request); // RFC 2616 compliance
$response->send($swooleResponse); // Gửi headers + content
12. Terminate & Cleanup
Sau khi response được gửi, Coroutine::defer() thực hiện cleanup:
public function terminateRequest(): void
{
// Chạy terminate callbacks
$terminateRequest = $this->app->getTerminateRequest();
if (!empty($terminateRequest)) {
$terminateRequest($this->app);
}
// Xóa scoped instances (Request, RouteDispatcher...)
$this->app->forgetScopedInstances();
// Xóa context data
Context::delete();
}
Điểm quan trọng: Server không restart sau mỗi request (khác với PHP-FPM). Swoole giữ application state trong memory, chỉ scoped instances được cleanup.
Tổng kết Lifecycle
┌─────────────────────────────────────┐
│ Swoole nhận Request │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ Request::initRequest() │
│ Parse headers, body, files │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ RouteDispatcher::handle() │
│ FastRoute matching │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ Middleware Pipeline │
│ Global → Module → Route │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ Parameter Resolution │
│ DI, DTO validation, Model binding│
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ Controller Action │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ Response::prepare() & send() │
└──────────────┬──────────────────────┘
▼
┌─────────────────────────────────────┐
│ Cleanup: scoped instances, │
│ context, terminate callbacks │
└─────────────────────────────────────┘
Khác biệt với PHP truyền thống
| PHP-FPM | Vietiso (Swoole) |
|---|---|
| Mỗi request khởi tạo lại toàn bộ | Application state giữ trong memory |
| Không có connection pooling | Connection pool cho DB, Redis |
| Blocking I/O | Non-blocking async I/O |
| Process-per-request | Coroutine-per-request |
| Autoload mỗi request | Autoload một lần khi boot |