如何在 Laravel 中创建自己的 PHP 辅助函数

file

Laravel 提供了很多优秀的 辅助函数 来处理数组、文件路径、字符串和路由,还有最受欢迎的 dd() 函数。

你还可以利用 Composer 的自动加载为你的 Laravel 应用和 PHP 程序包定义自己的辅助函数。

接下来让我们来看看如何创建可以自动由 Laravel 加载的辅助函数。

在 App 目录中创建一个 Helpers 文件

要在 Laravel 应用程序中引用辅助函数,你可以根据偏好决定辅助函数文件的位置,下面有几个建议的位置:

  • app/helpers.php
  • app/Http/helpers.php

这里更推荐保存在应用程序命名空间的根目录下 app/helpers.php

自动加载

要使用自定义的 PHP 辅助函数,首先要做的是,在运行时将它们加载到程序中。 事实上,在文件顶部看到下面这样的代码并不罕见:

require_once ROOT . '/helpers.php';

PHP 函数不能被自动加载,但是我们有比使用 requirerequire_once 更好的解决方案—— Composer。

你可以在 Laravel 的 composer.json 文件中看到 autoloadautoload-dev 这两个键:

"autoload": {
    "classmap": [
        "database/seeds",
        "database/factories"
    ],
    "psr-4": {
        "App\\": "app/"
    }
},
"autoload-dev": {
    "psr-4": {
        "Tests\\": "tests/"
    }
},

如果你想添加一个辅助函数的文件, composer.json 中有一个 files 键(这是一个文件路径的数组),你可以在 autoload 中定义:

"autoload": {
    "files": [
        "app/helpers.php"
    ],
    "classmap": [
        "database/seeds",
        "database/factories"
    ],
    "psr-4": {
        "App\\": "app/"
    }
},

添加了新的路径到 files 数组中之后,你需要执行以下命令:

composer dump-autoload

现在,在每个请求中,helpers.php 文件将被自动加载,因为 Laravel 需要在 public/index.php 中使用 Composer 的自动加载器:

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

定义函数

在辅助函数类中定义函数是很简单的,但是有些事情要注意:所有的 Laravel 辅助函数文件都包含在一个检查中以避免函数定义冲突:

if (! function_exists('env')) {
    function env($key, $default = null) {
        // ...
    }
}

因为你可能会遇到你正在使用的函数定义,而你根本不知道哪一个是第一个定义的,这可能会变得棘手。

我更推荐在辅助函数文件中使用 function_exists 检查,但是如果在单个文件中定义辅助函数,那就不需要了。

如果跳过检查,你可能随时都会看到你的辅助函数与其他函数发生冲突,这可能对你重新考虑函数的命名来说很有用。

但在实践中,这种冲突不会像你想象的那样频繁发生,你只需要确保定义的函数不是过于通用即可。你也可以为你的函数名添加前缀,确保它们不会与其他依赖相冲突。

辅助函数示例

我喜欢定义一个多功能的路由函数来同时使用变形路径和 URL 辅助函数。例如,一张照片资源路由会暴露路由辅助函数,比如 new_photo_pathedit_photo_path 等。

当我在 Laravel 中使用资源路由时,我喜欢添加一些辅助函数能够在模板中定义路由更容易。在我的实现中,我喜欢有一个 URL 助手函数,我可以传递一个 Eloquent 模型并使用我定义的约定返回资源路由,例如:

create_route($model);
edit_route($model);
show_route($model);
destroy_route($model);

以下是在 app/helpers.php 文件中定义 show_route 的方法(其他类似):

if (! function_exists('show_route')) {
    function show_route($model, $resource = null)
    {
        $resource = $resource ?? plural_from_model($model);

        return route("{$resource}.show", $model);
    }
}

if (! function_exists('plural_from_model')) {
    function plural_from_model($model)
    {
        $plural = Str::plural(class_basename($model));

        return Str::kebab($plural);
    }
}

plural_from_model() 函数只是一些可重用的代码,辅助函数 route 是用来根据我喜欢的命名约定来预测路由资源名称——模型的 kebab-case 复数形式命名。

例如,以下是由模型派生出来的资源名称示例:

$model = new App\LineItem;
plural_from_model($model);
=> line-items

plural_from_model(new App\User);
=> users

使用这个约定,你可以在 routes/web.php 中这样定义资源路由:

Route::resource('line-items', 'LineItemsController');
Route::resource('users', 'UsersController');

然后在 Blade 模板中,执行以下操作:

<a href="{{ show_route($lineItem) }}">
    {{ $lineItem->name }}
</a>

这会产生如下的 HTML:

<a href="http://localhost/line-items/1">
    Line Item #1
</a>

你的 Composer 软件包也可以使用辅助文件添加任何辅助函数来让你的软件包可用于项目。

你只需要在包的 composer.json 文件中采用相同的方法,使用你的辅助函数文件的数组定义 files 键。

在这里你就必须得添加 function_exists() 来检查你的辅助函数,以便使用了你的代码的项目不会由于命名冲突而中断。

你应该选择适合你的包的函数名,如果你害怕你的函数名太泛化,可以考虑使用一个简短的前缀。

更多

查看 Composer 的 自动加载 文档,了解更多有关引用文件以及自动加载类的信息。

另一个建议是了解框架中所有的 Laravel 辅助函数,并通过阅读 Illuminate\Foundation helpersIlluminate\Support helpers 的源代码来了解它们的工作原理。

本文译自 Creating Your Own PHP Helpers in a Laravel Project

本作品采用《CC 协议》,转载必须注明作者和本文链接
Stay Hungry, Stay Foolish.
本帖由 Summer 于 6年前 加精
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 15

@Seaony :confused:没事,就让单身狗在家写翻译就好

6年前 评论

为琳姐打 Call,本来想翻译这篇的,结果女朋友拉我出去逛街了:joy:

6年前 评论

为琳姐打 Call,本来想翻译这篇的,结果女朋友拉我出去逛街了:joy:

6年前 评论

@Seaony :confused:没事,就让单身狗在家写翻译就好

6年前 评论
mouyong

@JokerLinly 琳姐棒棒的.

6年前 评论

关于引入helper.php文件的,我有个问题,麻烦你有空解答一下,谢谢。

  • 这个helper.php文件应该是全局引入的,这里会不会导致一些函数用不上,而导致内存浪费??(个人觉得,helper.php会被读到内存,然后,在需要的用到地方才调用helper里定义好的方法)
6年前 评论

@huid 我觉得你可以先自己去熟悉一下 Composer 的自动加载

6年前 评论

@JokerLinly 这种方式,在调用的时候有问题

<?php

namespace App\Http\Controllers;

use function App\Http\array_increase;

class SomeClass 
{
    function doSometime() {
        ...
        $array = array_increase($array, 'image_url');
        ...
    }
}

按照文档操作之后,在调用的时候,居然要用 use function App\Http\array_increase; 这个实在是不能忍啊

6年前 评论

@Nixus 你确定你照着文档做了么.....另外你贴出来的写法也不对,请参考 Illuminate\Foundation helpersIlluminate\Support helpers 的源代码

6年前 评论

@JokerLinly 谢谢,参考了这两个源码,原来是因为声明了namespace造成的
谢谢

6年前 评论

手动点赞o( ̄▽ ̄)d:smile:

帮助函数还是很好用的:cat: :hamster:

6年前 评论

个人偏向于使用Trait,而不是帮助函数 :smile:

6年前 评论

@Seaony 我一直以为你是女生
file

6年前 评论
panda-sir

composer nice :smile:

6年前 评论

如果我想覆盖 vendor/laravel/lumen-framework/src/helpers.php 里的方法应该怎么做?

3个月前 评论

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