资讯专栏INFORMATION COLUMN

Laravel 创建自己的 Facade

K_B_Z / 2684人阅读

摘要:使用现在,在任何一个控制器,或者路由的回调函数中,使用你会发现,已经可以好好工作了,参考文章设计模式九外观模式结构型服务容器实例教程深入理解控制反转和依赖注入服务提供者实例教程创建测试实例

我的博客原文: http://www.qinblog.net/Articl...
前言

laravel 提供了一个灵活的模式,那就是 facade 。框架内部的 DB、Auth、File 等功能也有相关的 facade 实现。那么,该如何写自己的 facade 呢?

Facade 是什么?

首先,facade 并不是 laravel 独有的东西,它就是设计模式中的外观模式(Facade)。
当然,这里就不长篇大论去讨论外观模式的定义了。这篇文章写的很不错 : 设计模式(九)外观模式Facade(结构型)。
那么,laravel 的 facade 做了什么?
同样的, laravel 实现了外观模式的开关功能,并且使用魔术方法 __callstatic 实现了静态方式调用、动态创建对象的功能。参考 (官方文档)

当然你可能觉得这些概念很抽象,都什么玩意。那么其实简单的讲,laravel 的 facade 就是将某些功能封装成工具类,而且能以静态方式调用工具类的方法。

建立自己的 facade

首先、以 laravel 5.1 框架,我之前写过的 Geoip facade 为例,说一下怎么去建立自己的 facade。

下载 geoip 扩展

geoip 是一个可以更具 IP 获取国家、地域、城市信息的 PHP 扩展,基于 maxmind 数据库。 github 在此。

首先,为 laravel 添加 geoip 扩展。
打开 composer.json,添加 "geoip2/geoip2": "~2.0" 到 require。
项目根目录运行 composer update ( 需要安装 composer )更新一下,geoip 的依赖和软件包就被下载到 vendor 文件夹中了。

然后下载 geoip 依赖的数据库,免费库的地址 : GeoLite2

我下载了 GeoLite2 Country 和 GeoLite2 City 库,放到了 storage/geoipdb 中。

建立 facade。

在 app 目录下新建 Facades 文件夹,里面新建 Facades/GeoIP/GeoIP.php 和 Facades/GeoIP/Facade/GeoIP.php (建议每个功能新建一个文件夹区分,比如我这里给 GeoIP 新建一个文件夹,关于GeoIP 的东西全放到这里)
注意,Facades/GeoIP 下的 GeoIP.php 是你要对 geoip 扩展进行封装的类, Facades/GeoIP/Facade 下的 GeoIP.php 是你的 facade,用来给 laravel 解析使用,这两个文件可以不同名。

目录结构如图:

Facades/GeoIP/Facade/GeoIP.php 如下


注意你的 facade 现在只有一个方法,返回了一个字符串 "geoip" , 这个字符串是一个标号,用来给 laravel 的服务提供者解析使用的。

Facades/GeoIP/GeoIP.php 如下(吐槽:写的有点随意)

_country_db;
            break;
          case "getCity":
            $path = $this->_city_db;
            break;
          default:
            break;
        }

        $this->_instance = new Reader(storage_path($path));
    }

    /**
     * Get Country infomations.
     *
     * @param  String  $ip
     * @return Array
     */
    public function getCountry($ip)
    {
      $this->init(__FUNCTION__);

      $record = $this->_instance->country($ip);

      // 国家信息
      $data["iso_code"] = $record->country->isoCode;
      $data["country_name"] = $record->country->name;
      $data["country_name_zh_cn"] = $record->country->names["zh-CN"];

      return $data;
    }
 
 /**
     * Get City infomations.
     *
     * @param  String  $ip
     * @return Array
     */
    public function getCity($ip)
    {
      $this->init(__FUNCTION__);

      $record = $this->_instance->city($ip);

      $data["iso_code"] = $record->country->isoCode;
      $data["country_name"] = $record->country->name;
      $data["country_name_zh_cn"] = $record->country->names["zh-CN"];

      // 省、州信息
      $data["sub_division_name"] = $record->mostSpecificSubdivision->name;
      $data["sub_division_name_zh_cn"] = $record->mostSpecificSubdivision->names["zh-CN"];
      $data["sub_division_code"] = $record->mostSpecificSubdivision->isoCode;

      // 城市信息
      $data["city_name"] = $record->city->name;
      $data["postal_code"] = $record->postal->code;

      // 经纬度
      $data["latitude"] = $record->location->latitude;
      $data["longitude"] = $record->location->longitude;

      return $data;
    }

}

OK,现在 geoip 的常用功能已经封装到方法中了。

注册服务

完成了 facade 的创建和功能封装,下面就要使用它了。自己创建的 facade 要在 laravel 使用是要进行注册的,以便 laraval 在启动时能自动注入依赖(请看 laravel 的依赖注入简介 : laravel 依赖注入 学院君)

编写服务提供者

在 app/Providers 下新建 FacadesServiceProvider.php
可以手动建,也可以用 artisan 命令来生成,随你喜欢。
app/Providers/FacadesServiceProvider.php 代码如下:

app->singleton("geoip", function ($app) {
            return new GeoIP($app);
        });
    }
}

上面代码可知,服务提供者注册时会注册一个单例,标号为 "geoip",也就是我们自己的 facade 返回的那个,然后回调函数会返回一个对象,也就是我们封装 geoip 功能的那个类的实例,不明白的同学可以看看 laravel 的服务提供者和服务容器相关知识哦。(注意要 use 将 facade 和封装类的命名空间引用一下哦)

注册服务提供者

laravel 5.1 以上版本的话, config/app.php 中找到 providers 和 aliases ,将你的服务提供者和 facade 别名配置一下 :

providers 加入 :

AppProvidersFacadeServiceProvider::class,

aliases 加入(不用每次都写很长的命名空间前缀) :

"GeoIP"      => AppFacadesGeoIPFacadeGeoIP::class,

对于 lumen 5.2 以上,需要在 bootstrap/app.php 中添加

$app->register(AppProvidersFacadesServiceProvider::class);

注册完毕后,每次使用 facade::function 的时候,laravel 会自动解析 facade, 然后创建一个对象给用户使用,,而无需用户自己去 new 一个对象出来。

使用

现在,在任何一个控制器,或者路由的回调函数中,使用

$res = GeoIP::getCountry("75.101.195.215");
var_dump($res);

你会发现,facade 已经可以好好工作了,enjoy!

参考文章

【1】设计模式(九)外观模式Facade(结构型)
【2】Laravel 服务容器实例教程 —— 深入理解控制反转(IoC)和依赖注入(DI)
【3】Laravel 服务提供者实例教程 —— 创建 Service Provider 测试实例

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/30581.html

相关文章

  • Laravel框架门面Facade源码分析

    摘要:容器主要的作用就是生产各种零件,就是提供各个服务。的原理我们以为例,来讲解一下门面的原理与实现。当运行时,发现门面没有静态函数,就会调用这个魔术函数。我们看到这个魔术函数做了两件事获得对象实例,利用对象调用函数。 前言 在开始之前,欢迎关注我自己的博客:www.leoyang90.cn这篇文章我们开始讲 laravel 框架中的门面 Facade,什么是门面呢?官方文档: Facade...

    wanghui 评论0 收藏0
  • 通过facade(尤其是realtime facade)来使代码更优雅

    摘要:那么如果用的方式会怎么样呢现在,不仅看起来更简洁优雅,而且也可以测试了,因为可以进行,比如说这样你会发现最有用的地方就是构建简洁优雅的,同时呢又不会影响到代码的可测试性。 本文来自pilishen.com----原文链接; 欢迎作客我们的php&Laravel学习群:109256050 该篇翻译整理自laravel创始人Taylor的文章:Expressive Code & Real ...

    Eric 评论0 收藏0
  • PHP中facade pattern(外观模式)

    摘要:本文来自原文链接欢迎作客我们的学习群该篇属于底层核心技术实战揭秘这一课程底层核心概念解析这一章的扩展阅读。考虑到学员们的基础差异,为了避免视频当中过于详细而连篇累牍,故将一些底层实现相关的知识点以文章形式呈现,供大家预习和随时查阅。 本文来自pilishen.com----原文链接; 欢迎作客我们的php&Laravel学习群:109256050该篇属于《Laravel底层核心技术实战...

    jaysun 评论0 收藏0
  • 深入浅出 Laravel Facade 外观系统

    摘要:外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。将使用者与子系统从直接耦合,转变成由外观类提供统一的接口给使用者使用,以降低客户端与子系统之间的耦合度。接下来将深入分析外观服务的加载过程。引导程序将在处理请求是完成引导启动。 本文首发于 深入浅出 Laravel 的 Facade 外观系统,转载请注明出处。 今天我们将学习 Laravel 核心架构中的另一个主题「Fac...

    KavenFan 评论0 收藏0
  • Laravel 服务提供者和门面模式

    摘要:服务提供者先看看定义服务提供者是所有应用程序启动的中心所在。通过本文,希望大家能够了解服务提供者,,和实际调用的类的实例之间的关系。 以 Laravel 自带的文件系统为例,在 config/app.php 的配置文件的 providers 数组中,注册了一个服务提供者: IlluminateFilesystemFilesystemServiceProvider::class, 在 a...

    e10101 评论0 收藏0

发表评论

0条评论

K_B_Z

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<