Facades
Giới thiệu
Facades cung cấp interface "tĩnh" (static) cho các services đã đăng ký trong Container. Thay vì phải resolve service thủ công, bạn có thể gọi trực tiếp qua static methods:
// Không dùng Facade
$cache = app('cache');
$cache->get('key');
// Dùng Facade
Cache::get('key');
Facades không phải là static classes thực sự - chúng sử dụng PHP magic method __callStatic để proxy calls đến service instance trong Container.
Cách Facades hoạt động
Tất cả Facades kế thừa class Vietiso\Core\Support\Facade:
<?php
namespace Vietiso\Core\Support;
use Vietiso\Core\App;
abstract class Facade
{
abstract protected static function getFacadeAccessor(): string|object;
public static function __callStatic(string $name, array $arguments): mixed
{
$accessor = static::getFacadeAccessor();
if (is_string($accessor)) {
$container = App::getInstance();
if ($container->has($accessor)) {
$accessor = $container->get($accessor);
} else {
throw new ServiceNotFoundException("$accessor service does not exist");
}
}
return $accessor->$name(...$arguments);
}
}
Khi bạn gọi Cache::get('key'):
- PHP gọi
__callStatic('get', ['key']) getFacadeAccessor()trả về service ID ('cache')- Container resolve
'cache'thànhCacheManagerinstance - Gọi
$cacheManager->get('key')
Tạo Facade
Facade cơ bản
Chỉ cần implement getFacadeAccessor() trả về service ID:
<?php
namespace App\Facades;
use Vietiso\Core\Support\Facade;
class Payment extends Facade
{
protected static function getFacadeAccessor(): string
{
return 'payment'; // Service ID trong Container
}
}
Sử dụng:
use App\Facades\Payment;
Payment::charge($amount);
Payment::refund($transactionId);
Facade với Helper Methods
Facades có thể thêm các static methods riêng:
<?php
namespace Vietiso\Core\Database;
use Vietiso\Core\Support\Facade;
use Vietiso\Core\App;
class DB extends Facade
{
protected static function getFacadeAccessor(): string|object
{
return static::query();
}
public static function query(): Builder
{
return static::connection()->query();
}
public static function connection(?string $connection = null): ConnectionInterface
{
return App::service('database')->getConnection($connection);
}
public static function raw(string $sql, array $bindings = []): QueryRaw
{
return new QueryRaw($sql, $bindings);
}
}
// Tất cả đều hoạt động
DB::table('users')->get();
DB::connection('mysql')->query()->table('users')->get();
DB::raw('SELECT * FROM users');
Facade trả về Object
getFacadeAccessor() có thể trả về object trực tiếp thay vì string:
<?php
namespace Vietiso\Core\Log;
use Vietiso\Core\Support\Facade;
use Vietiso\Core\App;
class Log extends Facade
{
protected static function getFacadeAccessor(): string|object
{
// Trả về Logger instance trực tiếp
return App::service('log')->get();
}
public static function get($name = 'vietiso', $group = 'default'): Logger
{
return App::service('log')->get($name, $group);
}
}
// Sử dụng default logger
Log::info('User logged in', ['user_id' => 1]);
Log::error('Payment failed', ['order_id' => 123]);
// Sử dụng named logger
Log::get('audit')->info('Admin action', ['action' => 'delete_user']);
Facades có sẵn
| Facade | Service ID | Service Class |
|---|---|---|
DB | database | ConnectionManager |
Cache | cache | CacheManager |
Log | log | LoggerFactory |
Event | event_dispatcher | EventDispatcher |
Mail | mailer | Mailer |
Hash | hash.driver | HashDriver |
Filesystem | filesystem | FilesystemManager |
Redis | redis | RedisManager |
Http | http_client | HttpClient |
Bus | messenger | MessageBus |
Cache
use Vietiso\Core\Cache\Facade\Cache;
Cache::set('key', 'value', 3600);
$value = Cache::get('key', 'default');
Cache::delete('key');
Cache::remember('users', 300, fn () => User::get());
Event
use Vietiso\Core\Event\Facade\Event;
Event::dispatch(new UserRegistered($user->id));
Event::listen(UserRegistered::class, SendWelcomeEmail::class);
Mail
use Vietiso\Core\Mail\Facade\Mail;
Mail::to('user@example.com')
->subject('Welcome!')
->html('<h1>Hello</h1>')
->send();
// Sử dụng driver khác
Mail::driver('sendgrid')->to($email)->send($mailable);
Hash
use Vietiso\Core\Hashing\Facade\Hash;
$hashed = Hash::make('password');
$valid = Hash::check('password', $hashed);
Filesystem
use Vietiso\Core\Filesystem\Facade\Filesystem;
Filesystem::write('file.txt', 'content');
$content = Filesystem::read('file.txt');
Filesystem::disk('s3')->write('uploads/photo.jpg', $data);
Bus (Messenger)
use Vietiso\Core\Messenger\Facade\Bus;
Bus::dispatch(new SendEmailMessage($to, $subject, $body));
Bus::dispatch(new ProcessOrder($orderId))->delay(60)->onQueue('high');
Facade vs Dependency Injection
Cả hai cách đều hợp lệ. Facades tiện lợi cho code ngắn gọn, DI tốt hơn cho testability:
// Facade - ngắn gọn, tiện lợi
class UserController
{
#[Get('/users')]
public function index()
{
return Cache::remember('users', 300, fn () => User::get());
}
}
// DI - dễ test, explicit dependencies
class UserController
{
public function __construct(
private CacheManager $cache,
) {}
#[Get('/users')]
public function index()
{
return $this->cache->remember('users', 300, fn () => User::get());
}
}
Khuyến nghị
- Dùng Facades trong controllers, commands, và application code
- Dùng DI trong services, libraries, và code cần unit testing
- Không nên dùng Facades trong Service Providers (dùng
$this->app->get()thay thế)
Helper Functions
Framework cung cấp các helper functions hoạt động tương tự Facades:
// app() - resolve service từ Container
$cache = app('cache');
$db = app('database');
// env() - đọc environment variable
$debug = env('APP_DEBUG', false);
// config() - đọc config value
$timezone = config('app.timezone');
// base_path() - đường dẫn từ root
$path = base_path('storage/logs');
// now() - thời gian hiện tại
$time = now();