Laravelは「名前を規約どおりに付ければ設定を書かなくて済む」設計です。モデル名からテーブル名を、リレーションのメソッド名から外部キーを、マイグレーションのファイル名から対象テーブルを推論します。テーブル名や外部キーなど推論に使われる名前を変える場合は、対応する設定を明示する必要があります。この記事では、Laravel 13.36.0(2026年10月15日にcreate-projectで作成)で各推論を実行して確かめた結果をもとに、対象別の命名規則・PHPの規約(PSR)との関係・規約を外れるときの上書き方法・命名を機械的に守る手段をまとめます。
まとめ:Laravelの命名規則の要点
- ケースは3つ:クラスはStudlyCase(
OrderItem)、メソッドと変数はcamelCase($orderTotal)、テーブル・カラム・ルートパラメータはsnake_case(order_items)。定数と.envのキーは大文字のUPPER_SNAKE_CASE。 - テーブルはモデル名から推論:単数StudlyCaseのモデル
OrderItemは複数snake_caseのorder_itemsへ。Personはpeople、Indexはindicesのように英語の不規則変化にも従う。 - 外部キーはリレーションのメソッド名から:
belongsToはメソッド名+_id(author()ならauthor_id)を探す。中間テーブルは2モデルの単数形をアルファベット順に連結(role_user)。 - 規約を外れるならLaravel 13は
#[Table]属性:テーブル名・主キー・型・連番・タイムスタンプを1行で宣言できる。12系では従来の$tableなどのプロパティを使う。 - Pintは名前を直さない:
pint --testはクラス名order_serviceのような命名違反をPASSにする。命名の機械検査にはPHP_CodeSnifferのPSR1標準を使う。
PHPの命名規則とLaravelの土台|PSR-1・PSR-12
Laravelの命名は、PHPの標準規約PSR(PHP Standards Recommendations)の上にフレームワークの推論規約を重ねたものです。PHP全体の決まりとLaravelの都合を分けておくと、チームで揉める範囲が狭まります。
PSR-1の命名規定|クラス・定数・メソッドとプロパティの扱い
PSR-1が命名について「MUST」で定めているのは3点だけです。クラス名はStudlyCaps、クラス定数はすべて大文字のアンダースコア区切り、メソッド名はcamelCaseです。プロパティ名については、4.2節で「$StudlyCaps・$camelCase・$under_scoreのどれを使うかの推奨は意図的に避ける」と明記し、一定の範囲(ベンダー・パッケージ・クラス単位)で一貫させるべき(SHOULD)とだけ書いています。メソッド内のローカル変数名には触れていません。「PHPの変数はsnake_caseが正しい」「camelCaseが正しい」という断定は、どちらもPSRには根拠がありません。
PSR-2の非推奨化|PSR-12への移行とLaravelの書式設定
Laravelの命名を解説する記事には「PSR-2準拠」と書かれたものが今も多くありますが、PSR-2は2019年8月10日に非推奨となり、後継としてPSR-12が推奨されています。紛らわしいのは、Laravel自身のコントリビューションガイドが13.x版でも「Laravel follows the PSR-2 coding standard」と書いている点です。実際の整形は後述のLaravel Pintが担い、既定のプリセットlaravelはLaravel本体のコードスタイルに合わせて整えます。新しく規約を決めるなら、書式の判定はチームで固定したPintの設定に合わせ、命名規則は別途明文化してください。
変数名|camelCaseへの統一方針
PSRが決めていない変数名は、フレームワーク本体に合わせるのが最も摩擦の少ない選択です。laravel/framework v13.36.0のsrc配下をPHPのトークナイザ(token_get_all)で走査し、コメント・引数の既定値・プロパティ宣言を除いた代入文の変数のうち複数語のものを数えると、camelCase($orderTotal = の形)が1,478件、snake_caseは失敗ジョブの日時を入れる$failed_atの1件だけでした。アプリ側の変数もcamelCaseで統一し、snake_caseはデータベースのカラム名と、そのカラムを読むときの$user->created_atに限定すると、本体のコードと並べても違和感が出ません。言語をまたいだケースの考え方はプログラミングの命名規則まとめ|キャメルケース・スネークケースの違いとPythonのファイル名など6言語の書き方で整理しています。
対象別の命名規則一覧(早見表)
Laravelで名前を付ける主な対象を一覧にしました。「推論される」の列が○の対象は、名前を外すとLaravelが自動で結び付けられなくなります。
| 対象 | ケース・形 | 例 | 推論される |
|---|---|---|---|
| モデル | StudlyCase・単数 | OrderItem | ○ |
| テーブル | snake_case・複数 | order_items | ○ |
| カラム | snake_case | created_at | ― |
| 外部キー | メソッド名_id | author_id | ○ |
| 中間テーブル | 単数_単数(英字順) | role_user | ○ |
| コントローラー | StudlyCase+Controller | OrderItemController | ― |
| リソースのアクション | 7つの固定名 | index / store / destroy | ○ |
| メソッド・変数 | camelCase | $orderTotal | ― |
| リレーション | camelCase・単複 | user() / orderItems() | ○ |
| ルート名 | URI.アクション | order-items.index | ○ |
| ルートパラメータ | snake_case・単数 | {order_item} | ○ |
| マイグレーション | 日時_動作_テーブル | …_create_order_items_table | ○ |
| Seeder | モデル名+Seeder | OrderItemSeeder | ― |
| Factory | モデル名+Factory | OrderItemFactory | ○ |
| Policy | モデル名+Policy | OrderItemPolicy | ○ |
| FormRequest | 動作+モデル名+Request | StoreOrderItemRequest | ― |
| Bladeコンポーネント | kebab-case | user-card.blade.php | ○ |
| 定数 | UPPER_SNAKE_CASE | MAX_LOGIN_ATTEMPTS | ― |
| 設定ファイル・.env | snake_case / UPPER_SNAKE | services.php / DB_DATABASE | ― |
テーブル・モデル・コントローラーの命名
テーブル名|snake_caseの複数形と不規則な複数形
Eloquentはモデルのクラス名を複数形にしてsnake_caseへ変換し、テーブル名とみなします(公式ドキュメントの例はAirTrafficController→air_traffic_controllers)。複数形化には英語の辞書が使われるため、単純に「s」を付けるわけではありません。Laravel 13.36.0で推論結果を出力すると次のとおりでした。
| モデル名 | 推論されるテーブル名 |
|---|---|
| Person | people |
| Category | categories |
| Status | statuses |
| Index | indices |
| Criterion | criteria |
| Mouse | mice |
| UserData | user_data |
| News / Equipment / Media | news / equipment / media |
落とし穴になりやすいのはIndexとUserDataです。Indexモデルに対してindexesテーブルを作ると、Eloquentはindicesを探して失敗します。DataやNewsは不可算名詞として扱われ、複数形にもなりません。テーブルを先に作る場合は、モデルを作ってから(new OrderItem)->getTable()で推論結果を確かめるのが確実です。カラム名もsnake_caseで、主キーはidが既定です。
モデル名|StudlyCaseの単数形
モデルはテーブルと対になるStudlyCaseの単数形にします。app/Modelsに置き、名前空間App\Models\OrderItemとファイルパスをPSR-4で一致させます。1インスタンスが1行を表すので単数形です。
コントローラー名|StudlyCase+Controllerとリソースの7アクション
コントローラーはStudlyCaseで末尾にControllerを付けます。php artisan make:controller OrderItemControllerならapp/Http/Controllers/OrderItemController.phpが作られます。CRUDを担うリソースコントローラーでは、メソッド名がindex・create・store・show・edit・update・destroyの7つに固定されています。Route::resourceの1行がこの7つにルートを割り当てるため、listやdeleteのような独自名にはしません。
メソッド名|camelCaseと動詞始まり
メソッド名はPSR-1どおりcamelCaseで、calculateTotal・markAsShippedのように動詞から始めます。真偽値を返すものはisPaid・hasStockの形にします。Eloquentのアクセサもメソッド名はcamelCaseで、firstName()がfirst_nameカラムに対応します(ミューテタのドキュメント)。Eloquentのモデル定義全体はLaravel Eloquentとは|モデル定義・リレーション・eager loadingの基礎とクエリビルダの使い分けで解説しています。
リレーション・外部キー・中間テーブルの命名
リレーションは、名前がそのままSQLのカラム名になる箇所です。推論の元になる名前が関係の向きで違うため、取り違えると規約どおりに書いたつもりでもUnknown columnが出ます。
belongsToの外部キー|メソッド名と関連先主キー名からの推論
belongsToは、相手のモデル名ではなくリレーションのメソッド名をsnake_caseにし、アンダースコアと関連先モデルの主キー名を付けた列を外部キーとみなします。関連先の主キー名が既定のidなら、末尾は_idです。Postモデルでauthor()メソッドにbelongsTo(User::class)と書くと、探しに行く列はuser_idではなくauthor_idです。したがって列名がauthor_idなら第2引数は不要で、第2引数が必要になるのは列名が推論とずれたとき(checked_by列をreviewer()で読むなど)だけです。
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Post extends Model
{
// author_id を自動で探す(第2引数は不要)
public function author(): BelongsTo
{
return $this->belongsTo(User::class);
}
// 列名がメソッド名と違うときだけ明示する
public function reviewer(): BelongsTo
{
return $this->belongsTo(User::class, 'checked_by');
}
}
一方、hasManyの外部キーは親モデルのクラス名から作られます。Userのposts()ならposts.user_id、PostのorderItems()ならorder_items.post_idです。子側から見るbelongsToと親側から見るhasManyで推論の元が違うので、メソッド名をauthor()にしたら、親側のhasManyには'author_id'を明示する必要があります。
中間テーブル名|単数形のアルファベット順による連結
多対多の中間テーブルは、2つのモデル名をsnake_caseの単数形にし、アルファベット順に並べてアンダースコアでつなぎます。実測ではUserとRoleがrole_user、PostとTagがpost_tag、OrderItemとProductがorder_item_productでした。並べ替えはsnake_caseにした2つの名前を文字列として比べるため、迷ったら$user->roles()->getTable()で確かめてください。中間テーブルの列はrole_id・user_idの単数形です。
リレーション名とJSONのキー
リレーションのメソッド名は、1件を返すもの(belongsTo・hasOne)を単数のuser()、複数を返すもの(hasMany・belongsToMany)を複数のorderItems()にします。注意したいのは、camelCaseで定義したリレーションがtoArray()やJSONではsnake_caseのキーになることです。orderItemsを読み込んだモデルをJSONにすると、キーはorder_itemsになります(シリアライズのドキュメントにも同じ記述があります)。フロントエンドでorderItemsを参照してundefinedになる場合は、レスポンスのキーがorder_itemsになっていないか確認してください。
ルーティング・マイグレーション・Bladeの命名
ルート名とURI|order-items.index
URIは小文字の複数形をハイフンでつなぐ形(/order-items)が慣例です。Route::resource('order-items', OrderItemController::class)と書くと、ルート名はorder-items.index・order-items.showのようにURIの文字列がそのまま使われ、ルートパラメータは単数形のsnake_caseで{order_item}になります。users.order-itemsのようにネストすると、ルート名はusers.order-items.indexです。ビューやリダイレクトではroute('order-items.show', $item)のように名前で参照します。
ルートモデル結合|ルートパラメータ名と引数名の対応
暗黙のルートモデル結合は、型宣言した引数の変数名がルートパラメータ名と一致したときだけ働きます(ルーティングのドキュメント)。Laravelは変数名をsnake_caseに変換しても照合するので、{order_item}に対してOrderItem $orderItemは結合されます。危ないのは名前がずれたときです。Laravel 13.36.0で検証すると、次の2本は動作が分かれました。
// {order_item} と $orderItem は一致 → 該当行を取得、無ければ404
Route::get('/order-items/{order_item}', fn (OrderItem $orderItem) => $orderItem->id);
// 名前が違う → 404にも例外にもならず、空の OrderItem が渡る
Route::get('/x/{order_item}', fn (OrderItem $item) => var_export($item->exists, true));
2本目は存在するIDを渡してもfalseを返しました。エラーにならないため、更新処理で新しい行が作られて初めて気付くことがあります。make:controller --resource --model=OrderItemで生成すれば引数名は$orderItemで揃うので、手で書き換えるときだけ注意します。
マイグレーション|ファイル名からテーブルを推論
マイグレーションは「日時_動作_テーブル」で名付け、日時はartisanが付けます。Laravelはファイル名から対象テーブルと新規作成かどうかを推測し、生成するコードに埋め込みます(マイグレーションのドキュメント)。推測に使われる形は次の4つです(TableGuesserの正規表現)。
create_order_items_tableまたはcreate_order_items→Schema::create('order_items')add_status_to_order_items_tableのように_to_・_from_・_in_の後ろにテーブル名 →Schema::table('order_items')
この形から外れた名前(update_order_itemsなど)でも作成はできますが、up()とdown()が空のひな形になります。make:migration CreateFlightsTableとStudlyCaseで渡してもcreate_flights_table.phpに変換されました。マイグレーションの実行と巻き戻しはLaravelマイグレーションの使い方|php artisan migrateとrollback・freshの挙動を13.xで検証で扱っています。
Blade・ビューファイル|コンポーネントはkebab-case
通常のビューファイル名には公式の強制規約がなく、新規アプリのひな形にあるのもwelcome.blade.phpの1つだけです。複数語ならsnake_caseかkebab-caseのどちらかにプロジェクトで統一します。一方、Bladeコンポーネントは規約で決まっています。php artisan make:component UserCardはクラスapp/View/Components/UserCard.phpとビューresources/views/components/user-card.blade.phpを作り、タグは<x-user-card>です。コンストラクタ引数はcamelCase、HTML属性ではkebab-caseで渡します(Bladeのドキュメント)。
定数・設定ファイル・.envのキー
クラス定数はPSR-1どおりUPPER_SNAKE_CASE(const MAX_LOGIN_ATTEMPTS = 5;)です。config配下のファイル名とキーはsnake_case(config/services.phpの'slack' => ['notifications' => ['bot_user_oauth_token' => ...]])、.envのキーはUPPER_SNAKE_CASE(DB_DATABASE)にします。設定ファイル名の単複は同梱のservices.php・queue.phpでも混在しており、規約はありません。
Seeder・Factory・Policy・FormRequestの命名
Laravel 13.36.0でphp artisan make:model OrderItem -mfsc --policyを実行すると、次の名前でファイルが作られました。
| 種類 | 生成されたファイル | 名前が外れたとき |
|---|---|---|
| Seeder | database/seeders/OrderItemSeeder.php | 自分で呼ぶので動く |
| Factory | database/factories/OrderItemFactory.php | factory()が見つけられない |
| Policy | app/Policies/OrderItemPolicy.php | 自動検出されない |
| Controller | app/Http/Controllers/OrderItemController.php | ルート定義で指定するので動く |
2020年前後の記事に多いUsersTableSeederは古い慣習で、現在の公式ドキュメントの例はUserSeederです。SeederはDatabaseSeederから明示的に呼ぶため推論には使われませんが、モデル名+Seederに揃えます。投入してよいデータの線引きはLaravel Seederの使い方|Factory連携と本番投入してよいデータの線引きを参照してください。
FactoryとPolicyは名前で自動検出されます。HasFactoryはDatabase\Factories名前空間の「モデル名+Factory」を探し(Factoryのドキュメント)、Policyはモデルのあるディレクトリ以上のPoliciesディレクトリで「モデル名+Policy」を探します(認可のドキュメント)。名前を変えたい場合は、モデルに#[UseFactory]・#[UsePolicy]属性を付けて明示します。FormRequestは推論されませんが、StoreOrderItemRequest・UpdateOrderItemRequestのように「アクション+モデル名+Request」にすると、どのアクション用かが名前で分かります。実装はLaravelのバリデーション|validateとFormRequestの使い分け・カスタムルール・JSON応答で扱っています。
Eloquentの規約を外れるときの上書き方法|#[Table]属性
既存の業務システムのDBでは、テーブルがm_members、主キーが文字列のmember_idのように規約と合わないことがあります。DBを改名するのではなく、モデル側で実際の名前を宣言します。Laravel 13では#[Table]属性で1行にまとめられます。
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Model;
#[Table('m_members', key: 'member_id', keyType: 'string', incrementing: false, timestamps: false)]
class Member extends Model
{
}
このモデルでgetTable()・getKeyName()・getKeyType()・getIncrementing()・usesTimestamps()を出力すると、m_members・member_id・string・false・falseが返りました。#[Table]は2026年2月13日にマージされたPR #58578で入り、v13.0.0には存在しますが、確認対象の12系タグv12.70.0にはありません。13.xの公式ドキュメントはこの属性で説明しているため、12系のプロジェクトでドキュメントを写すとクラスが見つからないエラーになります。12系では従来どおりプロパティで書きます。
class Member extends Model
{
protected $table = 'm_members';
protected $primaryKey = 'member_id';
public $incrementing = false;
protected $keyType = 'string';
public $timestamps = false;
}
プロパティの書き方は13でも動くので、12から13へ上げても書き直しは必須ではありません。規約に乗れば宣言はゼロで、外れた分だけ宣言が増える。合わない箇所だけをモデルで宣言し、それ以外は規約に任せます。上書きが多くても、命名差だけならモデル側の宣言で対応します。DBビューを採用する場合は、利用するDBで必要な更新操作が可能か、ビューの保守工数が増えないかを確認します。なおLaravel 12のバグ修正は2026年8月13日で終了し、セキュリティ修正は2027年2月24日までです(リリースノート)。版ごとの対応はLaravelの最新バージョンは13|対応PHPバージョン・サポート期限一覧とアップグレード判断にまとめています。
命名規則の自動検査と生成支援|Pint・artisan・PHP_CodeSniffer
コーディング規約を守る道具は、書式を揃えるものと名前を検査するものが別です。混同すると、CIは通るのに命名がばらばらになります。
Laravel Pintの担当範囲|書式の整形と命名検査の限界
Laravel Pintは新規のLaravelアプリに同梱されるコードフォーマッタで、2026年10月15日のcreate-projectではv1.32.1が入りました。プリセットはlaravel(既定)・per・psr12・symfony・emptyの5つです(Pintのドキュメント)。命名についての効果を確かめるため、クラス名order_service・定数maxCount・メソッドGet_user_nameを含むファイルにvendor/bin/pintをかけました。Pintは波括弧の位置と空行を直しただけで、3つの名前はそのまま残りました。書式を整えた後の同じファイルにpint --testをかけると結果はPASSで、終了コードは0です。
つまりpint --testをCIに入れても、命名規則の違反は止まりません。プリセットの選び方とCIでの差分チェックはLaravel Pintとは|プリセット選定とCI差分チェック運用の判断基準で解説しています。
命名の検査はPHP_CodeSnifferのPSR1標準
同じファイルをPHP_CodeSniffer 4.0.4でvendor/bin/phpcs --standard=PSR1にかけると、3件のエラーで終了コード2になりました。
4 | ERROR | Class name "order_service" is not in PascalCase format
6 | ERROR | Class constants must be uppercase; expected MAXCOUNT but found maxCount
8 | ERROR | Method name "order_service::Get_user_name" is not in camel caps format
検出されたのはPSR-1が「MUST」としているクラス名・定数・メソッド名の3種類だけで、変数$User_Nameは報告されません。PSR-1が変数名を規定していないためです。変数名はレビュー基準で揃えます。Pintで書式、PHP_CodeSnifferで命名を分担すれば、両方をCIで止められます。型や未定義参照の検査はPHPStanとは?レベル0〜10の違いと導入・ベースライン運用【2.3対応】の守備範囲です。
php artisan make系による関連ファイル名の統一
最初から規約どおりの名前にするには、ファイルを手で作らずartisanで生成します。make:model OrderItem -mfsc --policyなら、モデルに対応するマイグレーション・Factory・Seeder・コントローラー・Policyが前章の名前で一度に揃います。各コマンドの生成先とオプションはphp artisan makeコマンド一覧|Laravel 13対応 生成先・オプション早見表で確認できます。社内の業務システムをLaravelで作る際の命名ルールの策定から開発までは、フルスクラッチ開発でも支援しています。
よくある質問
Laravelのコーディング規約と命名規則は何が違いますか?
命名規則は名前の付け方(クラスはStudlyCase、テーブルはsnake_caseの複数形など)で、コーディング規約はインデントや波括弧の位置を含む書き方全般です。Laravelでは書式をPintが自動で整えますが、Pintは名前を変えないため、命名はartisanでの生成とPHP_CodeSnifferなどの検査で守ります。
PHPの変数名はcamelCaseとsnake_caseのどちらが正しいですか?
PSR-1はローカル変数名のケースを規定していません。プロパティ名についてはケースの推奨を意図的に避け、一定の範囲で一貫させることを推奨しています。Laravelでは本体のソースがcamelCaseで書かれているため、アプリの変数もcamelCaseに揃え、snake_caseはデータベースのカラム名に使うのが一般的です。
モデル名とテーブル名がずれても動きますか?
動きますが、モデルに実際のテーブル名を宣言する必要があります。Laravel 13なら#[Table('m_members')]属性、12以前ならprotected $table = 'm_members';です。推論は英語の複数形に従うため、Indexモデルはindicesテーブルを探す点にも注意してください。
StudlyCaseとは何ですか?
単語の先頭をすべて大文字にしてつなぐ書き方で、PascalCase(アッパーキャメルケース)とほぼ同じ意味です。PSR-1は「StudlyCaps」と呼び、LaravelではStr::studly('order_item')がOrderItemを返します。クラス名に使います。
Laravelでコントローラーを作るときの命名は?
php artisan make:controller OrderItemControllerのように、StudlyCaseのモデル名にControllerを付けます。CRUD用なら--resource --model=OrderItemを付けると、7つの標準アクションと、ルートパラメータに一致する$orderItem引数が生成されます。