编程

学习如何在 Laravel 中创建自定义 Facade

360 2024-09-02 03:58:00

Laravel Facade 是 Laravel 框架的一个出色特性,通过简单的接口提供对服务的便捷访问。初学 Laravel时,有一件事让我感到困惑,那就是 Facade 访问器方法。

一旦你理解了 Facade 是访问 Laravel 服务容器中底层服务的便捷方式,你就可以轻松地跟踪 Facade 背后的服务。每个 Facade 都提供一个指向已注册服务名称的 getFacadeAccessor() 方法。

以下是 DB Facade 的 Facade 访问器示例:

// Illuminate\Support\Facades\DB;
 
protected static function getFacadeAccessor()
{
    return 'db';
}

db 字符串指向了容器中的一个服务,该 Facade 会调用此服务。如果你跳到 tinker 会话,你可以自己尝试一下:

有些 Facade 可能会解析到 Manager 类,然后会动态将方法传递给底层的 macro 或数据库连接列:

public function __call($method, $parameters)
{
    if (static::hasMacro($method)) {
        return $this->macroCall($method, $parameters);
    }
 
    return $this->connection()->$method(...$parameters);
}

当在没有连接的情况下调用时,DatabaseManager 将使用默认连接(上例中为 sqlite),并调用该连接上的方法。

我建议阅读 Laravel 文档中的了解 Facade 如何工作。

在 Laravel 中创建自己的 Facade

如果你没有创建插件或直接使用 Laravel 框架,为什么要在应用中创建 Facade?一些开发人员更喜欢只对应用代码中定义的服务使用依赖注入,这很好。但是,我发现通过 helper 或 App\Facades 命名空间为我经常使用的服务定义 Facades 很方便。我喜欢 Laravel 的灵活性,同时仍然制定了在不熟悉的代码库中提高效率的惯例。

要在应用中创建 Facade,我建议使用 make:class 命令来生成 Facade,你可以按如下方式操作:

php artisan make:class App/Facades/Example

假设你在应用的服务提供者中定义了一个名为 App\ExampleService 的服务,你可以在生成该类后,为其创建一个 Facade;

namespace App\Facades;
 
use Illuminate\Support\Facades\Facade;
 
class Example extends Facade
{
    public static function getFacadeAccessor()
    {
        return 'example_service';
    }
}

如果你没有在服务提供者中定义别名或使用字符串来定义它,你也可以很容易地将 Facade 访问器设置为完全限定类的字符串:

public static function getFacadeAccessor()
{
    return \App\ExampleService::class;
}

Facades 对于在测试中直接模拟底层服务类提供了便利:

use App\Facades\Example;
 
Example::shouldReceive('getLatestPosts')
   ->with($after_date)
   ->andReturn($test_posts);

如果你并未使用 Facade,Laravel 提供了其他方便的模拟方法,比如 partialMock(),可以在测试中方便地将服务交换为模拟。使用该服务,你可以直接在测试中这样做:

$mock = $this->partialMock(MyApiService::class, function (MockInterface $mock) {
    $mock->shouldReceive('getLatestPosts')
        ->with($after_date)
        ->andReturn($test_posts);
});

采取哪种方法取决于你,但如果在应用中大量使用某个服务,请考虑创建一个 Facade,以便在使用服务时提供一些便利,而不会丢失依赖注入提供的功能。