小技巧大用处:自定义任意 Laravel 帮助函数

何时需要重写框架内置的帮助函数?

  • 内置的帮助函数绝大多数都是简单的调用了相应的类,所以我们一般是扩展相应的类来实现自定义功能,但是某些内核类不好扩展,这时可以直接重写这个帮助函数。
  • 如果要给帮助函数指定默认参数值,除了再写一个函数调用内置函数外,我们也可以直接重写内置的函数。
  • 还有种情况,比如 elixirmix ,这两个没有对应的类
  • 为第三方扩展包改变 Laravel 内置函数的默认行为
  • 重写扩展包里的帮助函数的行为

如何实现?

很简单,只需要在加载 Composer 的 autoload 之前定义我们的同名函数就可以了。Laravel 5.5 是在 public/index.php 里,5.5 以前的版本是在 bootstrap/autoload.php 里。例如:

function url($path = null, $parameters = [])
{
    // ...
}

require __DIR__.'/../vendor/autoload.php';

或者将自定义函数放到一个文件里:

require __DIR__.'/../app/custom_helpers.php';

require __DIR__.'/../vendor/autoload.php';

因为内置函数都使用了 function_exists 判断,所以内置的同名函数不会创建,也不会有重定义错误。该方法适用于任何 Composer 管理的项目。

举个栗子

我们一般会为 js,css,icon,font 等资源文件使用独立域名来达到 cookie-free ,或者使用 CDN 来加速。Laravel 提供了 asset 函数用来生成资源文件的 URL ,但是对应类 UrlGenerator 不支持为 asset 方法自定义 root URL ,导致 asset 函数很鸡肋,我们一般会定义一个自己的函数,比如:

function cdn($path)
{
    return config('cdn.url').'/'.ltrim($path, '/');
}

但是,第三方扩展包里还是用的 asset ,比如做后台的那些 admin 包。如果我们要让扩展包里的资源文件使用独立域名或者 CDN ,不得不在 vendor:publish 后替换 assetcdn ,而且每次更新包后重新 publish 后得再替换一次。当然我们可以在 Gulp 或 Mix 等前端构建里自动替换。

asset 所调用的 app('url') 是在内核服务 RoutingServiceProvider 里绑定的,而且其依赖有点复杂,详见 https://github.com/laravel/framework/blob/... 。如果我们自定义了 url 绑定 ,每次 Laravel 框架更新后都要检查这块代码是否有更改。我提交了一个 PR ,让 UrlGenerator 支持自定义 root ,但是被关闭了,见 https://github.com/laravel/framework/pull/...

更优雅的方式应该是重写 asset 函数:

function asset($path, $secure = null)
{
    return app('url')->assetFrom(config('app.assets_url'), $path, $secure);
}

require __DIR__.'/../vendor/autoload.php';
:point_right: Laravel 官网镜像 :cn:
本帖已被设为精华帖!
附言 1  ·  6年前

又一个例子 :sunglasses: 重写 dd 函数解决新版 Chrome 的渲染问题:https://laravel-china.org/articles/7214#reply36840

本帖由 Summer 于 6年前 加精
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 4

我一般习惯写在composer.json里

6年前 评论

@wangxiaomo 写在 composer.json 里不一定能覆盖框架内置的函数吧

6年前 评论

@ElfSundae 执行 composer dumpautoload 后可以吧

6年前 评论

@mingyun 不行的。你可以看看你项目的 vendor/composer/autoload_files.php 这个文件,这个就是 Composer auto load 时加载函数文件的顺序,这个顺序是没规律的(因为 Composer 安装依赖是没有顺序的),如果你定义的同名函数在 Laravel helpers 之后,PHP 会报函数重定义的错误。
所以必须在内置函数的前面定义你的同名函数,而 Laravel 的内置函数都调用了 function_exists 检查,所以不会出现重定义错误而且内置函数根本不会执行定义,就达到了覆盖的目的。

6年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!