Giao diện
Facades
Giới thiệu (Introduction)
Xuyên suốt tài liệu Laravel, bạn sẽ thấy code tương tác với các tính năng Laravel qua "facades". Facades cung cấp giao diện "static" cho các classes có sẵn trong service container. Laravel ships với nhiều facades cung cấp quyền truy cập hầu hết tính năng của Laravel.
Laravel facades đóng vai trò như "static proxies" cho các underlying classes trong service container, mang lại lợi ích của cú pháp ngắn gọn, biểu cảm trong khi duy trì khả năng testability và flexibility cao hơn so với static methods truyền thống.
Tất cả facades được định nghĩa trong namespace Illuminate\Support\Facades:
php
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Route;
Route::get('/cache', function () {
return Cache::get('key');
});Helper Functions
Bổ sung cho facades, Laravel cung cấp nhiều "helper functions" toàn cục giúp tương tác dễ dàng hơn. Các helpers phổ biến bao gồm view, response, url, config, v.v.
Ví dụ, thay vì dùng Illuminate\Support\Facades\Response facade, bạn có thể đơn giản dùng function response. Vì helper functions có phạm vi toàn cục, bạn không cần import bất kỳ class nào:
php
use Illuminate\Support\Facades\Response;
Route::get('/users', function () {
return Response::json([
// ...
]);
});
Route::get('/users', function () {
return response()->json([
// ...
]);
});Khi nào sử dụng Facades (When to Utilize Facades)
Facades có nhiều ưu điểm: cú pháp ngắn gọn, dễ nhớ, không cần nhớ tên class dài. Nhờ cách sử dụng PHP dynamic methods, chúng dễ test.
Tuy nhiên, cần cẩn thận. Nguy hiểm chính là "scope creep" (phình to phạm vi class). Vì facades dễ dùng, class có thể phình ra và sử dụng nhiều facades. Khi dùng dependency injection, constructor lớn cho bạn tín hiệu trực quan rằng class đang phình. Vì vậy, khi dùng facades, hãy chú ý kích thước class để phạm vi trách nhiệm luôn hẹp.
GỢI Ý
Nếu class phình quá lớn, cân nhắc chia thành nhiều classes nhỏ hơn.
Facades so với Dependency Injection
Một lợi ích chính của dependency injection là khả năng swap implementations. Điều này hữu ích khi testing vì bạn có thể inject mock hoặc stub.
Thông thường, không thể mock static method. Nhưng vì facades dùng dynamic methods để proxy method calls đến objects trong service container, chúng ta thực sự có thể test facades như test injected class instance:
php
use Illuminate\Support\Facades\Cache;
Route::get('/cache', function () {
return Cache::get('key');
});Test với facade testing methods:
php
use Illuminate\Support\Facades\Cache;
test('basic example', function () {
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$response = $this->get('/cache');
$response->assertSee('value');
});php
use Illuminate\Support\Facades\Cache;
public function test_basic_example(): void
{
Cache::shouldReceive('get')
->with('key')
->andReturn('value');
$response = $this->get('/cache');
$response->assertSee('value');
}Facades so với Helper Functions
Nhiều helper functions thực hiện cùng chức năng với facade tương ứng:
php
return Illuminate\Support\Facades\View::make('profile');
return view('profile');Không có sự khác biệt thực tế giữa facades và helper functions. Khi dùng helpers, bạn vẫn test được giống hệt facade tương ứng.
Cách Facades hoạt động (How Facades Work)
Trong ứng dụng Laravel, facade là class cung cấp quyền truy cập đến object từ container. Cơ chế nằm trong class Facade. Tất cả facades kế thừa base class Illuminate\Support\Facades\Facade.
Class Facade sử dụng magic method __callStatic() để defer (chuyển tiếp) các lời gọi từ facade đến object được phân giải từ container:
php
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;
class UserController extends Controller
{
/**
* Hiển thị profile của user.
*/
public function showProfile(string $id): View
{
$user = Cache::get('user:'.$id);
return view('profile', ['user' => $user]);
}
}Nhìn vào class Illuminate\Support\Facades\Cache, không có static method get:
php
class Cache extends Facade
{
/**
* Lấy tên đăng ký của component.
*/
protected static function getFacadeAccessor(): string
{
return 'cache';
}
}Cache facade kế thừa Facade và định nghĩa method getFacadeAccessor(). Method này trả về tên binding trong service container. Khi user gọi static method trên Cache facade, Laravel phân giải binding cache từ service container và chạy method được yêu cầu (trong trường hợp này là get) trên object đó.
Real-Time Facades
Với real-time facades, bạn có thể coi bất kỳ class nào trong ứng dụng như facade. Để tạo real-time facade, thêm prefix Facades vào namespace của class:
php
<?php
namespace App\Models;
use Facades\App\Contracts\Publisher;
use Illuminate\Database\Eloquent\Model;
class Podcast extends Model
{
/**
* Xuất bản podcast.
*/
public function publish(): void
{
$this->update(['publishing' => now()]);
Publisher::publish($this);
}
}Khi real-time facade được sử dụng, implementation sẽ được phân giải từ service container dựa trên phần interface/class name sau prefix Facades. Khi testing, dùng Laravel facade testing helpers:
php
<?php
use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
pest()->use(RefreshDatabase::class);
test('podcast can be published', function () {
$podcast = Podcast::factory()->create();
Publisher::shouldReceive('publish')->once()->with($podcast);
$podcast->publish();
});php
<?php
namespace Tests\Feature;
use App\Models\Podcast;
use Facades\App\Contracts\Publisher;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PodcastTest extends TestCase
{
use RefreshDatabase;
public function test_podcast_can_be_published(): void
{
$podcast = Podcast::factory()->create();
Publisher::shouldReceive('publish')->once()->with($podcast);
$podcast->publish();
}
}Bảng tham chiếu Facade Class (Facade Class Reference)
Bảng dưới đây liệt kê mọi facade và underlying class tương ứng. Key binding trong service container cũng được bao gồm khi áp dụng.
| Facade | Class | Service Container Binding |
|---|---|---|
| App | Illuminate\Foundation\Application | app |
| Artisan | Illuminate\Contracts\Console\Kernel | artisan |
| Auth | Illuminate\Auth\AuthManager | auth |
| Auth (Instance) | Illuminate\Contracts\Auth\Guard | auth.driver |
| Blade | Illuminate\View\Compilers\BladeCompiler | blade.compiler |
| Broadcast | Illuminate\Contracts\Broadcasting\Factory | — |
| Bus | Illuminate\Contracts\Bus\Dispatcher | — |
| Cache | Illuminate\Cache\CacheManager | cache |
| Cache (Instance) | Illuminate\Cache\Repository | cache.store |
| Config | Illuminate\Config\Repository | config |
| Context | Illuminate\Log\Context\Repository | — |
| Cookie | Illuminate\Cookie\CookieJar | cookie |
| Crypt | Illuminate\Encryption\Encrypter | encrypter |
| Date | Illuminate\Support\DateFactory | date |
| DB | Illuminate\Database\DatabaseManager | db |
| DB (Instance) | Illuminate\Database\Connection | db.connection |
| Event | Illuminate\Events\Dispatcher | events |
| File | Illuminate\Filesystem\Filesystem | files |
| Gate | Illuminate\Contracts\Auth\Access\Gate | — |
| Hash | Illuminate\Contracts\Hashing\Hasher | hash |
| Http | Illuminate\Http\Client\Factory | — |
| Lang | Illuminate\Translation\Translator | translator |
| Log | Illuminate\Log\LogManager | log |
Illuminate\Mail\Mailer | mailer | |
| Notification | Illuminate\Notifications\ChannelManager | — |
| Password | Illuminate\Auth\Passwords\PasswordBrokerManager | auth.password |
| Password (Instance) | Illuminate\Auth\Passwords\PasswordBroker | auth.password.broker |
| Pipeline | Illuminate\Pipeline\Pipeline | — |
| Process | Illuminate\Process\Factory | — |
| Queue | Illuminate\Queue\QueueManager | queue |
| Queue (Instance) | Illuminate\Contracts\Queue\Queue | queue.connection |
| RateLimiter | Illuminate\Cache\RateLimiter | — |
| Redirect | Illuminate\Routing\Redirector | redirect |
| Redis | Illuminate\Redis\RedisManager | redis |
| Redis (Instance) | Illuminate\Redis\Connections\Connection | redis.connection |
| Request | Illuminate\Http\Request | request |
| Response | Illuminate\Contracts\Routing\ResponseFactory | — |
| Route | Illuminate\Routing\Router | router |
| Schedule | Illuminate\Console\Scheduling\Schedule | — |
| Schema | Illuminate\Database\Schema\Builder | — |
| Session | Illuminate\Session\SessionManager | session |
| Session (Instance) | Illuminate\Session\Store | session.store |
| Storage | Illuminate\Filesystem\FilesystemManager | filesystem |
| Storage (Instance) | Illuminate\Contracts\Filesystem\Filesystem | filesystem.disk |
| URL | Illuminate\Routing\UrlGenerator | url |
| Validator | Illuminate\Validation\Factory | validator |
| Validator (Instance) | Illuminate\Validation\Validator | — |
| View | Illuminate\View\Factory | view |
| View (Instance) | Illuminate\View\View | — |
| Vite | Illuminate\Foundation\Vite | — |