Laravel5.5: 公式ドキュメントでは言及されていないヘルパー関数

下記のように、公式ドキュメントにはヘルパー関数が列挙されているページがあります。
しかし、調べてみるとこの他にもグローバルに使えるヘルパー関数がありました。
:link: [(日本語) ヘルパ](https://readouble.com/laravel/5.5/ja/helpers.html)
:link: [(英語) Helpers](https://laravel.com/docs/5.5/helpers)

(2017年10月15日 追記)
Laravel5.5では「Miscellaneous(その他)」の欄が設けられたので、ほぼ全てのヘルパー関数が上記のページ内で説明されています。
ただ、それでもまだ4つの関数の説明がありませんでした。


# ヘルパー関数を定義しているファイル
2つのファイルに分けて定義しているようです。

- [vendor/laravel/framework/src/Illuminate/Foundation/helpers.php](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/helpers.php)
- [vendor/laravel/framework/src/Illuminate/Support/helpers.php](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/helpers.php)


## ヘルパー関数である証拠
上のファイルは下記のように`composer.json`の`autoload`に指定されて読み込まれています。
`helpers.php`はクラスファイルではなく単に関数を列挙しただけのファイルなので、`files`キーで指定されてます。
:link: [つべこべ言わずComposerでシンプルにautoloaderを使用したいとき - Qiita](http://qiita.com/ltg_lambda/items/ad37d0ad28e4f8fe9caa)
:link: [(公式解説) autoload](https://getcomposer.org/doc/04-schema.md#autoload)
:link: [(公式解説) files](https://getcomposer.org/doc/04-schema.md#files)

:page_facing_up: [framework/composer.json](https://github.com/laravel/framework/blob/5.5/composer.json#L86)

```json
{
    "autoload": {
        "files": [
            "src/Illuminate/Foundation/helpers.php",
            "src/Illuminate/Support/helpers.php"
        ],
        "psr-4": {
            "Illuminate\\": "src/Illuminate/"
        }
    },
```


# ヘルパー関数の解説ページにはない関数一覧
さて、本題です。
`cookie`のように、ヘルパー関数のページではなくとも[公式ドキュメント内の別のページ](https://readouble.com/laravel/5.5/ja/requests.html#cookies)で説明されているものもあります。
しかし、`windows_os`のように全く言及のない関数も多いです。
車輪の再発明をしないよう、ヘルパー関数を自作する前に確認しておきたいです。

たちの悪いことに、ヘルパー関数はグローバルゆえにどのクラスにも属していないので、[APIリファレンス](https://laravel.com/api/5.5/)にも載っていません。
下記の関数は、ソースコードを読んで見つけるしかありません。
ただ、無秩序に定義されているわけではなく`composer.json`に明記されているので、それほど面倒ではないと思います。

## Foundation/helpers.php
|関数|コメント文|
|:--|:--|
|[elixir](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/helpers.php#L401)|Get the path to a versioned Elixir file.|

## Support/helpers.php
|関数|コメント文|
|:--|:--|
|[append_config](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/helpers.php#L11)|Assign high numeric IDs to a config item to force appending.|
|[object_get](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/helpers.php#L686)|Get an item from an object using "dot" notation.|
|[windows_os](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Support/helpers.php#L1143)|Determine whether the current environment is Windows based.|


# (余談) 上に挙げた関数の見つけ方
定義済みの全ての関数を取得する[get_defined_functions](http://php.net/manual/ja/function.get-defined-functions.php)と、配列同士の差分を取得する[array_diff](http://php.net/manual/ja/function.array-diff.php)を使いました。

```php
// 下記のページの「Available Methods」に列挙されている関数名をコピーして、配列として整形する。
// https://laravel.com/docs/5.5/helpers
$arrDocs = [
    'array_add',
    'array_collapse',
    'array_divide',
    // ...
];

// 下記の2つのファイルの中身を丸ごとコピーして貼り付ける
// vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
// vendor/laravel/framework/src/Illuminate/Support/helpers.php
if (! function_exists('abort')) {
    function abort($code, $message = '', array $headers = [])
    {
        app()->abort($code, $message, $headers);
    }
}
// ...

// 定義済みの全ての関数を取得する
$arr = get_defined_functions();

// 配列同士の差分を取得する
$diff = array_diff($arr['user'], $arrDocs);
foreach ($diff as $val) {
    echo $val.'<br>';
}
```


# (余談) Laravel由来ではないグローバル関数も存在する
`symfony/polyfill-mbstring`や`hamcrest/hamcrest-php`など、Laravel以外のパッケージで定義されたグローバル関数もLaravel内で使えるようです。
下記のようにLaravel内で即席のルートを作り、先ほどと同じく[get_defined_functions](http://php.net/manual/ja/function.get-defined-functions.php)と[array_diff](http://php.net/manual/ja/function.array-diff.php)を使って調査しました。

```php:routes/web.php
// 即席のルートを定義
Route::get('get-global-functions', function() {
    $arrHelpers = [
        // 先ほどの調査で得た、全てのLaravelのヘルパー関数を配列として格納する
        'array_add',
        'array_collapse',
        'array_divide',
        // ...
    ];
    $arr = get_defined_functions();
    $diff = array_diff($arr['user'], $arrHelpers);
    $return = '';
    foreach ($diff as $val) {
        $return .= $val.'<br>';
    }
    return $return;
});
```

結果、下記のようにたくさんのグローバル関数が定義されていることが分かりました。
これらはLaravelが公式に提供しているものではないので、流用しないほうがいいでしょう。
Laravelがそのパッケージに依存しなくなったら使えなくなってしまいますから。
それにしても、ヘルパー関数を定義する前にいちいち`if (! function_exists('関数名'))`で重複を検査する理由は、このように他のパッケージのグローバル関数名と衝突する危険があるからなのだということが分かり、勉強になりました。

`composerrequiredd08af2877ca94bd2ded2cefe5883ad7`, `composer\autoload\includefile`, `assertthat`, `anarray`, `hasiteminarray`, `hasvalue`, `arraycontaininginanyorder`, `containsinanyorder`, `arraycontaining`, `contains`, `haskeyinarray`, `haskey`, `haskeyvaluepair`, `hasentry`, `arraywithsize`, `emptyarray`, `nonemptyarray`, `emptytraversable`, `nonemptytraversable`, `traversablewithsize`, `allof`, `anyof`, `noneof`, `both`, `either`, `describedas`, `everyitem`, `hastostring`, `is`, `anything`, `hasitem`, `hasitems`, `equalto`, `identicalto`, `aninstanceof`, `any`, `not`, `nullvalue`, `notnullvalue`, `sameinstance`, `typeof`, `set`, `notset`, `closeto`, `comparesequalto`, `greaterthan`, `greaterthanorequalto`, `atleast`, `lessthan`, `lessthanorequalto`, `atmost`, `isemptystring`, `emptystring`, `isemptyornullstring`, `nulloremptystring`, `isnonemptystring`, `nonemptystring`, `equaltoignoringcase`, `equaltoignoringwhitespace`, `matchespattern`, `containsstring`, `containsstringignoringcase`, `stringcontainsinorder`, `endswith`, `startswith`, `arrayvalue`, `booleanvalue`, `boolvalue`, `callablevalue`, `doublevalue`, `floatvalue`, `integervalue`, `intvalue`, `numericvalue`, `objectvalue`, `anobject`, `resourcevalue`, `scalarvalue`, `stringvalue`, `hasxpath`, `mb_ord`, `mb_chr`, `mb_scrub`, `psy\sh`, `psy\debug`, `psy\info`, `psy\bin`, `debugbar`, `debug`, `start_measure`, `stop_measure`, `add_measure`, `measure`

なお、[get_defined_functions](http://php.net/manual/ja/function.get-defined-functions.php)で取得した関数名は**強制的に小文字になります**。
上に挙げた関数名は、本来は大文字の場合もあるので気をつけてください。
ただ、PHPの名前空間名、クラス名、メソッド名、関数名はケース・センシティブではない、つまり大文字小文字を区別しないので、問題ないでしょう。
(※変数名、定数名、プロパティ名はケース・センシティブです)
このような事情から、ヘルパー関数の名前はスネークケースにした方がいいと思います。
詳しくは下記をご覧ください。
:link: [PHPのグローバルなユーザー定義関数の名前はスネークケースにするべきだと思う](http://qiita.com/sutara79/items/7dea640035e06ed51fde)