0

0

如何使用 Laravel Facades ?

php中文网

php中文网

发布时间:2016-06-20 12:41:29

|

1276人浏览过

|

来源于php中文网

原创

Facade 布局是在面向对象编程中经常使用的一种软件设计布局方式。Facade 实际上是一种包括复杂函数库的类,提供了更加简洁易读的接口。Facade 布局还能为一组结构复杂、设计简陋的 API 提供统一、设计周到的 API。

Laravel 框架与该布局的特点相似,也称为 Facades。在本教程中,我们会学习如何在其他框架应用 Laravel 的 “Facades”。在继续学习之前,让我们简单了解一下 Ioc 容器。

首先,我们了解 Laravel 的 facades 内部工作结构。之后再讨论如何将之改造并用于其他环境。

Laravel 中的 Facades

Laravel facade 是一种为容器内部服务提供类似静态接口的类。据其文档描述,Facades 是可触及容器服务底层实现方式的代理。

不过,在 PHP 社区,有关其名称的争论一直不断。一些人坚持修改此名称以避免开发者的困惑,因为其并未完全实现 Facade 布局。如果你也受此名称困扰,大可以为其取个别名。但是,请注意,下文将会用到的 Laravel 框架基类(base class)将会称为 Facade。

How Facades Are implemented in Laravel

Facades 在 Laravel 中如何实现

你可能也知道,容器内的每个服务都有个唯一名称。在 laravel 应用中,可使用 App::make() 方法或 app() 辅助函数从容器中直接获取服务。

<?phpApp::make('some_service')->methodName();

前面已经提过,Laravel 使用 facade 类的好处是让开发者使用服务时更加便捷。使用 facade 类之后,下面的代码就能达到相同的效果:

// ...someService::methodName();// ...

在 Laravel 中,所有服务都包含一个 facade 类。这些 facade 类继承自 Illuminate/Support 包中的 Facade 基类。它们只需实现 getFacadeAccessor 方法即可,后者会返回容器内的服务名。

在上面的示例中,someService 代表 facade 类。methodName 其实是容器内原服务的一个方法。如果跳出 Laravel 的语境查看上面的示例,则表示一个名为 someService 的类引出名为 methodName() 的静态方法。但 Laravel 并不是这样实现接口的。在下一节,我们将介绍 Laravel 的 Facade 基类在幕后的运作方式。

Base Facade

Facade 类包含一个名为 $app 的私有属性,其值为服务容器的引用。如果要在 Laravel 之外使用 facades,必须使容器明确使用 setFacadeApplication() 方法。

在 facade 基类内部,__callStatic 魔术方法用于处理实际并不存在的静态方法的调用。如果调用 Laravel facade 类的静态方法, __callStatic 方法便会激活,因为 facade 类并未实现该方法。因此,__callStatic 会从容器获取各自的服务,进而调用之。

以下是 facade 基类中 __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() 会从容器获取服务。

Facade 类解析

每个 facade 类均继承自基类。我们只需实现 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 facades 是 PHP 类,在使用之前我们得导入它们。PHP 支持命名空间与自动导入,因此只要调用全限定名,即可自动载入这些类。PHP 还支持使用 use 指令给类取别名:

use App\Facades\SomeServiceFacadeSomeServiceFacade:SomeMethod();

然而,在需要某个特定的 facade 类时,我们必须在每个脚本文件都写一遍上面的代码。Laravel 在处理 facade 别名时有其独特的方法——别名载入器(alias loader)。

Laravel 如何给 Facades 加别名

所有的别名都保存在 app.php 配置文件的 aliases 数组中,该文件保存在 /config 目录下。

查看该数组,会发现每个别名都与一个全限定类名对应。这意味着我们可以给 facade 类选定任意的名字。

// ..'aliases' => [    // ...    'FancyName' => 'App\Facades\SomeServiceFacade',],

现在,让我们看看 Laravel 如何使用该数组给 facade 类取别名。在引导阶段,Laravel 会使用来自 Illuminate\Foundation 包的 AliasLoader 服务。AliasLoader 以该别名数组为参数,遍历其所有元素,使用 PHP 的 spl_autoload_register 创建一个 __autoload 函数队列。各个 __autoload 函数会用 PHP 的 class_alias 函数为各个 facade 类创建别名。

因此,我们无需像使用 use 指令时那样在使用类前导入之并为其创建别名。当我们试图使用一个不存在的类时,PHP 会检查 __autoload 队列以得到合适的 autoloader。这时,AliasLoader 已经记下所有的 __autoload 函数。各个 autoloader 会选定一个类名并根据别名数组推导出对应的初始类名。最后,它会为其创建别名。请参考下面的方法调用:

<?php// FancyName is resolved to App\Facades\SomeServiceFacade according to the aliases arrayFancyName::someMethod()

在幕后,FancyName 会对应至 App\Facades\SomeServiceFacade。

在其他框架使用 Facades

现在,我们已经了解 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 基类。

创建 Facades

只需继承 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 官方博客

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

616

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

194

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

91

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

54

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

15

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

598

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

56

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SQL 教程
SQL 教程

共61课时 | 3.9万人学习

【web前端】Node.js快速入门
【web前端】Node.js快速入门

共16课时 | 2.1万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号