编程

在 Laravel 中创建自己的辅助函数 helpers

2194 2022-01-01 03:44:18

Laravel 提供了很多优秀的辅助函数,让诸如数组、文件路径、字符串、路由等的使用更加便利。比如,dd() 函数。

通过 Composer 自动引入,你也可以为你的 Laravel 应用和 PHP 包定义一套辅助函数。

如果你是 Laravel 或者 PHP 新手,让我们一起看看如何通过 Laravel 自动加载创建自己的 helper 函数。

在 Laravel 应用中创建一个 Helpers 文件

你需要做的第一步是在 Laravel 应用中引入 helper 函数。取决于你自己的偏好,你可以自己组织你 helper 文件的位置。尽管如此,这是一些建议位置:

  • app/helpers.php
  • app/Http/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 有一个 files 键(文件路径数组) ,你可以在 autoload 里面定义:

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

一旦你在 files 数组中添加了新的路径,你需要 dump autoload 对自动加载进行更新:

composer dump-autoload

现在每个请求,helpers.php 文件都会被自动加载。因为 Laravel 在 public/index.php 中 引入 Composer 自动加载器:

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

定义函数

虽然有很多需要警惕的事项, helpers 中定义函数还是很容易的。为了避免函数定义冲突,所有的 Laravel helper 文件都使用如下代码包裹:

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

这样有时候会有些棘手,你可能会遇到这样的情况:你所使用的函数可能不是你自定义的、而是来自于第一次定义的。

我倾向于在我的应用的 helpers 中使用 function_exists 检查,如果你在应用的上下文环境中定义 helpers, 你可以忽略function_exists 检查。跳过这步检查,你每次重定义函数的时候都会看到冲突。

真实的实践中,冲突并不会那么常见,你应该确保你定义的函数名不会过于通用。你也可以给你的函数名加上前缀,以减少和其他依赖包冲突的可能。

Helper 实例

我喜欢对定义路径及 URL 的辅助函数。比如,photos 资源路由可以暴露路由辅助函数如 new_photo_path, edit_photo_path 等。

当我在 Laravel 中使用资源路由时,我喜欢添加一些 helper 函数,让模板中的路由定义更容易一些。在我的实现中,我会使用 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() 函数是 helper 路由函数用来预测路由资源名称的代码重用, 使用短横线隔开式复数调用模型。

比如,以下是模型资源名:

$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');