Laravel 標準ヘルパ関数を自作ヘルパ関数でオーバーライドする


概要

前回 Laravel 自作のヘルパ関数を追加する 記事を書きましたが、標準のヘルパ関数を上書きして使いたいというのが一定の需要がありそうなので記事にしました。

デフォルトのヘルパ関数を上書きすると新参者が困るので極力は止めた方がいいです。
ヘルパ関数自体も乱用は避けて、適度に利用するのが望ましいです。

環境

  • PHP 7.4.5
  • Laravel 7.9.2

Laravelのヘルパ関数

if (! function_exists('now')) {
    /**
     * Create a new Carbon instance for the current time.
     *
     * @param  \DateTimeZone|string|null  $tz
     * @return \Illuminate\Support\Carbon
     */
    function now($tz = null)
    {
        return Date::now($tz);
    }
}

now 関数だけ抜粋ですが、このように記述されています。
function_exists 関数が定義済みかチェックしてますので、自前で作ったヘルパ関数を先に読み込ませてあげれば良さそうです。

$ php artisan tinker
>>> now()
=> Illuminate\Support\Carbon @1588607807 {#3012
     date: 2020-05-04 15:56:47.513338 UTC (+00:00),
     timezone: "UTC",
   }

こんな感じの挙動です。

やり方

CLI経由、WEB経由の時も vendor/autoload.php は必ず読み込まれるので一番最初に自作のヘルパ関数ファイルを読み込ませる形にします。
(こうしないとLaravelのヘルパファイルが先に読み込まれてしまいます)

自作のヘルパ関数を作る

now() ヘルパ関数を自作します。

app/helpers.php
<?php declare(strict_types=1);

if (! function_exists('now')) {
    /**
     * @return string
     */
    function now(): string
    {
        return date('Y-m-d H:i:s');
    }
}

Carbon を返してたのを string で返す関数にしてみました!

オートローダーを書き換えるコマンドを作成する

オートローダーを書き換える方法ですが、コマンドファイルを作ってあげるのが分かりやすいかなと思いました。

$ php artisan make:command BootstrapAutoloadCommand

作成された app/Console/Commands/BootstrapAutoloadCommand.php を下記の内容に書き換えます。

app/Console/Commands/BootstrapAutoloadCommand.php
<?php declare(strict_types=1);

namespace App\Console\Commands;

use Illuminate\Console\Command;

class BootstrapAutoloadCommand extends Command
{
    protected $signature = 'bootstrap:autoload';
    protected $description = 'app/helpers.php を先読みさせる';
    public function handle(): void
    {
        $autoloadPath = base_path('vendor/autoload.php');
        $helperPath = app_path('helpers.php');

        // オートローダーのファイル内容を読み込む
        $before = file_get_contents($autoloadPath);

        // 先に自作ヘルパファイルを一番最初に読み込むようにする
        $after = str_replace('<?php' . PHP_EOL, "<?php require_once '$helperPath';" . PHP_EOL, $before);

        // オートローダーを上書きする
        file_put_contents($autoloadPath, $after);
    }
}

やってることは vendor/autoload.php を読み込んで自作した app/helpers.php ファイルを読み込んでます。

composer.json
    "scripts": {
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi",
            "@php artisan bootstrap:autoload"
        ],
        // ...
    }

dump-autoload 実行後のイベントフックに php artisan bootstrap:autoload を追加してあげます。

$ composer dump-autoload

オートローダーを更新します。
vendor/autoload.php 下記のように app/helpers.php を読み込むようになってたらokです。

/laravel/vendor/autoload.php
<?php require_once '/laravel/app/helpers.php';

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitf2b4f3f391cdb9fc40ee0b8001495415::getLoader();

お試し

$ php artisan tinker
>>> now()
=> "2020-05-04 15:57:29"

Laravel標準のヘルパ関数を自作のヘルパ関数でオーバーライドできました!

参考