😇

Laravelで定数を使うときにConfigを使う腰抜けはもう死んだ

2021/03/07に公開
6

はじめに

どうも、チキンと呼ばれたらキレる系プログラマーのあおいくんだよ。
みんなはLaravelで定数使うときどうしてる?
僕は数ヶ月前までconfig配下にconst.phpとか作ってそこにバカスカ定義する腰抜けだったんだよね。
でも、そんな腰抜けは背後からナイフで一発、もう死んじまったって噂だよ。
今回はみんながそうならないためにLaravelで定数を定義するときのよりよい方法を紹介するよ。

環境

PHP:7.4系
Laravel:7.x系

config.phpに定義してた腰抜け時代

まるでそれがベストプラクティスかのように世の中に流布されている定数の定義方法として「config/const.phpにバカスカ定義する」ってやつがあるじゃん。
僕もアレに騙されてた腰抜けの一人だったわけ。

config/const.php
<?php

return [

  ~~~他の記述~~~

  // キラメイジャーのメンバー
  'Kirameiger' => [
    'KIRAMEI_RED' => 1,
    'KIRAMEI_YELLOW' => 2,
    'KIRAMEI_GREEN' => 3,
    'KIRAMEI_BLUE' => 4,
    'KIRAMEI_PINK' => 5,
    'KIRAMEI_SILVER' => 6,
    'MEMBER_LIST' => [
      'キラメイレッド' => 1,
      'キラメイイエロー' => 2,
      'キラメイグリーン' => 3,
      'キラメイブルー' => 4,
      'キラメイピンク' => 5,
      'キラメイシルバー' => 6,
    ],
  ],
  
  ~~~他の記述~~~
  
];

これってとりあえず定義はできるけど、冷静に見たらこれはないんじゃないかなってのがなんとなく伝わってくると思うの。
僕が思うにイケてないポイントは少なくとも2つあると思うんだよね。

  1. ファイルがめっちゃ長くなる
    今はキラメイジャーだけだけど、例えば45戦隊シリーズ全部定義しようって思ったら、このファイルの中に45戦隊分全部定義することになって、そうすると900行くらいのファイルになっちゃうよね。
    めちゃめちゃに長いファイルはめちゃめちゃ見通しが悪くなるし、正直全然イケてないよね🤷‍♂️

  2. 変更に弱い
    これ、例えばやっぱ番号0からふるようにしましょうってなったとするよ。
    そしたらそれぞれを定義しているところとメンバーの配列を定義してるとこの2箇所をいじらなきゃいけなくなるよね。
    そうなるとうっかり変更を忘れちゃってメンバーの配列のキラメイレッドは1番始まりのままになってるとかいうことが起こりかねないよね🤷‍♂️

ちなみに表で呼び出すときは

kirameiger.blade.php
@foreach (config('const.Kirameiger.MEMBER_LIST') as $name => $number)
  <p>{{ $name }} => {{ $number }}</p>
@endforeach

みたいな呼び出しになるよ。まぁまぁの見た目だね。

Configの中で用途ごとに個々に分けてた腰抜け時代

バカデカファイルにうんざりした腰抜けは、「用途ごとにファイル分けたらいいんぢゃね?マジで天才ぢゃん😁」って思ったのよ。
つまりconfig/consts/kirameiger.phpにしてみたわけ。新しい戦隊が放送開始したらconfig/consts/zenkaiger.phpとかも作るわけよ。
これ前述の①は解決できると思うんだけど、結局②が残るよね。
そうなるとこれも結局あんまいい方法じゃないって腰抜けが気づくまでに数ヶ月かかったんだよね🤷‍♂️

そして辿り着いた定数クラスを作る時代

そんじゃあ、これどうすればいいんだよって話。
答えは簡単、app配下にConstsフォルダを作るんだよね。
その中で定数として定義して呼び出して上げればよかったんだよね。

app/Consts/KirameigerConsts.php
<?php

namespace App\Consts;

// usersで使う定数
class KirameigerConsts
{
  // キラメイジャーのメンバー
  public const KIRAMEI_RED = 1;
  public const KIRAMEI_YELLOW = 2;
  public const KIRAMEI_GREEN = 3;
  public const KIRAMEI_BLUE = 4;
  public const KIRAMEI_PINK = 5;
  public const KIRAMEI_SILVER = 6;
  public const MEMBER_LIST = [
    'キラメイレッド' => self::KIRAMEI_RED,
    'キラメイイエロー' => self::KIRAMEI_YELLOW,
    'キラメイグリーン' => self::KIRAMEI_GREEN,
    'キラメイブルー' => self::KIRAMEI_BLUE,
    'キラメイピンク' => self::KIRAMEI_PINK,
    'キラメイシルバー' => self::KIRAMEI_SILVER,
  ];
}

よくない?見た目もよくない?イケてない?そうでもない?
これならファットなファイルを作らずに済むし、自分の中で定義した定数を使えるからこちゃこちゃした配列とかを定義しても変更漏れとかの問題なくない?

ちなみに表で呼び出すときは

kirameiger.blade.php
@foreach (App\Consts\KirameigerConsts::MEMBER_LIST as $name => $number)
  <p>{{ $name }} => {{ $number }}</p>
@endforeach

みたいな呼び出しになるよ。まぁまぁいいんじゃないかな。
でも、呼び出しちょっと長くない?って思うよね。僕も思う。
そういう人はapp.phpにaliasを設定してあげれば

config/app.php
<?php

return [

  ~~~いろんな記述~~~

  'aliases' => [

    ~~~いろんな記述~~~

    'KirameigerConsts' =>  App\Consts\KirameigerConsts::class,
  ],
];

とか記述してあげれば

kirameiger.blade.php
@foreach (KirameigerConsts::MEMBER_LIST as $name => $number)
  <p>{{ $name }} => {{ $number }}</p>
@endforeach

みたいな呼び出せるようになるよ。スマートになるね。

おわりに

いまのところこれが一番しっくりきてるやり方だよ。
正直aliasを登録するのもなんかちまちましててめんどくさすぎるから、実は一気に解決できる方法があるんじゃないかとは疑ってるよ。
もし知ってる人いたら出し渋らずに教えてくれよな👋

Discussion

おしうみなおきおしうみなおき

何も考えたくない場合はconst.phpを使っています(笑)

ちなみに、enum(laravel-enumとか)を使うのはいかがでしょうか?

あおいくんあおいくん

正直開発メンバーみんなでルール守れてたら何をどこに定義しててもいいと思います!
laravel-enumは使ったことないんでいろいろ言えないんですけど、ドキュメント見た感じもしかしたらenumの方がイケてるのか…?
使用感としてConstsから呼び出すのとここが違うみたいなのあったら知りたいです

おしうみなおきおしうみなおき

例えば、 Gender::getKey(1); で 「男性」を取得したり、 Gender::getValue("男性")で「1」を取得したりできるのですが、 Gender::asSelectArray(); で 下記のように取得できます

[
    1 => "男性",
    2 => "女性",
    3 => "その他",
]

これはフロント側でプルダウンの選択肢を動的に変えたい場合に、Gender::asSelectArrayの結果をフロントにわたしてあげれば、簡単にセレクトボックスに値を渡せます。

みたいな便利さもあれば、
constを使うより視覚的に優しい( Gender::getKey(1) って性別の値が「1」を取得してるんだなって分かりやすい)とかもあると思います !

あおいくんあおいくん

ありがとうございます🙇‍♂️
指摘してもらった件ですけど、functionやarrayの定義ができるのでConstsの運用でも一応同様の処理は可能だと思われます。
Gender::getKey(1)の呼び出し方は視覚的には優しいんですけど、保守性どうなんだ問題があるかなって思います。100箇所にその呼出があったら100箇所修正するのか、とか。
const使うメリットは

  1. 何箇所にも同じ記述をしなくて済む
  2. マジックナンバーを消せる

だと思うので、const定義した上でマジックナンバー使っちゃうと、本当か?🤔な気持ちに個人的にはなりますね。

namizatorknamizatork

僕もちょうどこの方法に行き着いたところでした!
僕の場合はModel(=テーブル)に関連する定数はModelのプロパティで管理して(privateも使えるので)、
逆にModelに紐づかない都道府県や性別などの定数をこの記事の定数クラスを作るやり方でやっています!

ernixernix

config/app.php のように環境毎に定数を env() ヘルパから読み出して設定したい場合、この方法だと定数クラスの中で env() ヘルパを使うことになりますが Laravel のドキュメントは php artisan config:cache が実行された場合 config ディレクトリ以外で実行される env() が常にnullを返す事を警告していますから、どのみち config/const.php の利用は避けられないように見えます。

そもそもPHPの配列は Ordered map とされているので、キラメイジャーの例ではマジックナンバーを振る必要性を感じませんでした。

これで記事の懸念点はすべて消えているように思うのですが。

config/const.php
<?php

return [
  "Kirameiger" => [
    'KIRAMEI_RED' => 'キラメイレッド',
    'KIRAMEI_YELLOW' => 'キラメイイエロー',
    'KIRAMEI_GREEN' => 'キラメイグリーン',
    'KIRAMEI_BLUE' => 'キラメイブルー',
    'KIRAMEI_PINK' => 'キラメイピンク',
    'KIRAMEI_SILVER' => 'キラメイシルバー',
  ],
];
kirameiger.blade.php
@foreach (array_values(config("const.Kirameiger")) as $i => $name)
  <p>{{ $name }} => {{ $i + 1 }}</p>
@endforeach