ファサード レイアウトは、オブジェクト指向プログラミングでよく使用されるソフトウェア設計レイアウト手法です。 Facade は実際には、より簡潔で読みやすいインターフェイスを提供する複雑な関数ライブラリを含むクラスです。ファサード レイアウトは、一連の複雑で適切に設計されていない API に対して、統合された適切に設計された API を提供することもできます。
Laravel フレームワークは、ファサードとも呼ばれるこのレイアウトと同様の特性を共有します。このチュートリアルでは、Laravel の「ファサード」を他のフレームワークに適用する方法を学びます。次に進む前に、IOC コンテナについて簡単に見てみましょう。
まず、Laravel のファサードの内部の仕組みを理解します。後で、それを適応させて他のコンテキストで使用する方法について説明します。
Laravel ファサードは、コンテナ内のサービスに同様の静的インターフェイスを提供するクラスです。ドキュメントによると、ファサードはコンテナ サービスの基盤となる実装に影響を与えるプロキシです。
しかし、PHP コミュニティでは、その名前について議論が続いています。この名前は Facade レイアウトを完全には実装していないため、開発者の混乱を避けるためにこの名前の変更を主張する人もいます。この名前にも困った場合は、エイリアスを付けても構いません。ただし、以下で使用する Laravel フレームワークの基本クラスは Facade と呼ばれることに注意してください。
コンテナ内の各サービスには一意の名前があることもご存知でしょう。 laravelアプリケーションでは、App::make()メソッドまたはapp()ヘルパー関数を使用して、コンテナからサービスを直接取得できます。
<?phpApp::make('some_service')->methodName();
前に述べたように、Laravel がファサード クラスを使用する利点は、開発者がサービスを使用するのがより便利になることです。ファサード クラスを使用した後、次のコードでも同じ効果を実現できます。
// ...someService::methodName();// ...
Laravel では、すべてのサービスにファサード クラスが含まれています。これらのファサード クラスは、Illuminate/Support パッケージの Facade 基本クラスを継承します。実装する必要があるのは、コンテナ内のサービス名を返す getFacadeAccessor メソッドだけです。
上記の例では、someService はファサード クラスを表します。 MethodName は、実際にはコンテナ内の元のサービスのメソッドです。 Laravel のコンテキストの外で上記の例を見ると、someService という名前のクラスが、methodName() という名前の静的メソッドをエクスポートすることを意味します。しかし、これはLaravelがインターフェースを実装する方法ではありません。次のセクションでは、Laravel の Facade 基本クラスが舞台裏でどのように動作するかを見ていきます。
Facade クラスには、値がサービス コンテナへの参照である $app というプライベート プロパティが含まれています。 Laravel の外部でファサードを使用する場合は、コンテナーで setFacadeApplication() メソッドを明示的に使用する必要があります。
ファサード基本クラスの内部では、実際には存在しない静的メソッドへの呼び出しを処理するために __callStatic マジック メソッドが使用されます。 Laravel ファサード クラスの静的メソッドを呼び出すと、ファサード クラスはこのメソッドを実装していないため、__callStatic メソッドがアクティブ化されます。したがって、__callStatic はコンテナからそれぞれのサービスを取得して呼び出します。
次に、ファサード基本クラスの __callStatic メソッドの実装を示します。
<?php// .../** * Handle dynamic, static calls to the object. * * @param string $method * @param array $args * @return mixed */ public static function __callStatic($method, $args) { $instance = static::getFacadeRoot(); switch (count($args)) { case 0: return $instance->$method(); case 1: return $instance->$method($args[0]); case 2: return $instance->$method($args[0], $args[1]); case 3: return $instance->$method($args[0], $args[1], $args[2]); case 4: return $instance->$method($args[0], $args[1], $args[2], $args[3]); default: return call_user_func_array([$instance, $method], $args); } }
上記のメソッドでは、getFacadeRoot() がコンテナからサービスを取得します。
各ファサード クラスは基本クラスから継承します。実装する必要があるのは、コンテナ内のサービス名を返す getFacadeAccessor() メソッドだけです。
<?php namespace App\Facades;use Illuminate\Support\Facades\Facade as BaseFacade;class SomeServiceFacade extends BaseFacade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'some.service'; }}
Laravel ファサードは PHP クラスであるため、使用する前にインポートする必要があります。 PHP はネームスペースと自動インポートをサポートしているため、これらのクラスは完全修飾名を呼び出すだけで自動的にロードできます。 PHP は、クラスのエイリアスとして use ディレクティブの使用もサポートしています:
use App\Facades\SomeServiceFacadeSomeServiceFacade:SomeMethod();
ただし、特定のファサード クラスが必要な場合は、各スクリプト ファイルに上記のコードを記述する必要があります。 Laravel には、ファサードのエイリアスを処理する独自の方法、つまりエイリアス ローダーがあります。
すべてのエイリアスは、/config ディレクトリに保存されている app.php 設定ファイルのエイリアス配列に保存されます。
配列を見ると、各エイリアスが完全修飾クラス名に対応していることがわかります。これは、ファサード クラスに任意の 名を選択できることを意味します。
// ..'aliases' => [ // ... 'FancyName' => 'App\Facades\SomeServiceFacade',],
したがって、use ディレクティブを使用する場合のように、クラスをインポートして使用する前にそのエイリアスを作成する必要はありません。存在しないクラスを使用しようとすると、PHP は __autoload キューで適切なオートローダーを確認します。この時点で、AliasLoader はすべての __autoload 関数を記録しました。各オートローダーはクラス名を選択し、エイリアス配列に基づいて対応する初期クラス名を導出します。最後に、そのエイリアスを作成します。次のメソッド呼び出しを参照してください:
<?php// FancyName is resolved to App\Facades\SomeServiceFacade according to the aliases arrayFancyName::someMethod()
现在,我们已经了解 Laravel 如何处理 facades 与别名,我们可以将 Laravel 的 facade 方法运用到其他环境中。接下来,我们会在 Silex 框架使用 facades。然而,只要遵循同样的理念,你也可以将之用在别的框架。
Silex 拥有继承自 Pimple 的容器。使用 $app 对象即可调用容器内的服务:
<?php$app['some.service']->someMethod()
有了 facade 类,我们可以为 Silex 服务提供一个类似静态的接口。此外,我们也可以使用 AliasLoader 服务为这些 facades 创建有意义的别名。因此,我们可以重组上面的代码:
<?phpSomeService::someMethod();
为了使用 facade 基类,我们要使用 composer 指令安装 Illuminate\Support 包:
composer require illuminate\support
此包还包含其他服务。但目前我们只需要 facade 基类。
只需继承 Facade 基类并实现 getFacadeAccessor 方法,即可为服务创建 facade。
在本文中,所有 facades 都会保存在 src/Facades 路径下。例如:名为 some.service 的服务,其 facade 类如下:
<?phpnamespace App\Facadesuse Illuminate\Support\Facades\Facade;class SomeServiceFacade extends Facade { /** * Get the registered name of the component. * * @return string */ protected static function getFacadeAccessor() { return 'some.service'; }}
请注意,此类位于 app\facades 命名空间下。
现在只剩下设定 facade 类的应用容器。如前所述,在静态语境下调用 facade 类的方法,会触发 __callStatic 方法。该方法会用 getFacadeAccessor() 返回的数据识别容器内的服务,并试图获取之。在 Laravel 之外使用 facade 基类时,容器对象并不是自动设定的,需要手动设定。
为此,使用 facade 基类的 setFacadeApplication 方法,可以设定 facade 类的应用容器。
在 app.php 文件,添加以下代码:
<?phpIllumiante\Support\Facade::setFacadeApplication($app);
这会给继承自 facade 基类的所有 facades 设定容器。
现在,无需直接从容器获取服务,我们可以使用刚刚创建的 facade 类来获取,该类还允许我们调用静态语境下的所有方法。
为了给 facade 类创建别名,我们将使用之前介绍过的 AliasLoader。AliasLoader 类由 illuminate\foundation 包提供,可以下载整个包,也可以拷贝部分代码保持为文件。
如果你想拷贝源文件,建议将其保存在 src/Facades 目录下。你可以根据项目的结构为 AliasLoader 类创建命名空间。
在本例中,我们将拷贝代码并将其保存在 app/facades 命名空间下。
在 config 目录下创建 aliases.php 文件,并填入 alias-facade 绑定:
<?phpreturn [ 'FancyName' => 'App\Facades\SomeService',];
FancyName 是我们给 App\Facades\SomeService 建立的别名。
注册别名AliasLoader 是一种单例服务。要创建或得到别名载入器(alias loader)的实例,需调用 getInstance 方法并以别名数组为参数。最后,为了注册这些别名,需调用其 register 方法。
再次打开 app.php 文件,加入以下代码:
<?php// ...$aliases = require __DIR__ . '/../../config/aliases.php';App\Facades\AliasLoader::getInstance($aliases)->register();
现在,大功告成了!我们可以这样使用该服务:
<?phpFancyName::methodName();
一个 Facade 类只需实现 getFacadeAccessor 方法即可,后者会返回容器内的服务名。若要在 Laravel 环境外使用 facade,必须使用 setFacadeApplication() 方法明确设定服务容器。
要引用 facade 类,我们可以使用全限定类名或使用 PHP 的 use 指令导入之。或者,遵循 Laravel 给 facades 创建别名的方法,使用 alias loader。
原文链接:http://www.sitepoint.com/how-laravel-facades-work-and-how-to-use-them-elsewhere/ (作者:Reza Lavaryan)本文系 OneAPM 工程师编译整理。
OneAPM for PHP 能够深入到所有 PHP 应用内部完成应用性能管理 能够深入到所有 PHP 应用内部完成应用性能管理和监控,包括代码级别性能问题的可见性、性能瓶颈的快速识别与追溯、真实用户体验监控、服务器监控和端到端的应用性能管理。想阅读更多技术文章,请访问 OneAPM 官方技术博客。
本文转自 OneAPM 官方博客