はじめに
PHPで実務のコードを書いているとき、こんな風に悩んだことはありませんか?
- 「関数のデフォルト値を設定したのに、途中の引数だけスキップして呼び出せない…」
- 「1つの値を配列に包んで別関数に渡したいとき、どう書くのがスマート?」
- 「関数名や変数名って、結局スネークケースとキャメルケースどっちにすべき?」
今回は、保守点検のバリデーション関数によくある実装例をベースに、初学者エンジニアが知っておくべき 「関数の設計とリファクタリングのベストプラクティス」 をギュッとまとめました!
1. 引数のデフォルト値とPHPDocの「型の一致」
まずは、特定の値が送られてこなくても動くようにする「デフォルト引数」の正しい書き方です。
// ❌ 惜しい例:型とデフォルト値がチグハグ
/**
* @param ?string $category_name <- nullを許容している
*/
public static function check(string $category_name = '') { ... } // <- デフォルトは空文字''
💡 改善策
引数の型 $変数名 = デフォルト値 の書き方自体はこれで正解です。しかし、PHPDoc側で ?string(null許容)と書きつつ、実装では空文字 '' をデフォルト値にすると、静的解析ツール(PHPStanなど)やIDEで型矛盾の警告が出る原因になります。
値がない時に空文字として扱いたいなら、PHPDoc側も string に統一しましょう。
/**
* @param string $category_name 保守点検カテゴリ名(デフォルトは空文字)
*/
public static function check(string $category_name = ''): ?string
2. 途中の引数をスキップして関数を呼び出したいとき
PHPでは、以下のようにカンマの間を空けて特定の引数をスキップすることは文法エラー(Syntax Error)になります。
// ❌ 動かないコード(文法エラー)
$result = KeepPatrolService::getErrorMessage($db, $id, $article_id, , true);
💡 解決策:PHP 8.0以降なら「名前付き引数」を使う
引数の名前(変数名から $ を抜いたもの)にコロン : をつけることで、途中の引数をすっ飛ばしてピンポイントで値を渡せます。
// ⭕️ 名前付き引数でスマートに解決
$result = KeepPatrolService::getErrorMessage(
$db,
$id,
$article_id,
delete_flag: true // $category_name を省略して指定!
);
これなら「最後の true が何のためのフラグか」が一目でわかるため、可読性も爆上がりします。
3. 単一の数値を関数内で配列に包む(ラップする)方法
「基本は1つのIDしか来ないけれど、内部で呼び出す別関数が配列(複数ID)を要求している」というケースです。
// ⭕️ シンプルに四角カッコ `[]` で囲む
$equipment_ids = [$equipment_id];
// 別関数には配列として渡す
$unsetFlag = self::getUnsetFlag($pdo, $equipment_ids, $article_id);
プチ小技: 配列に変換した後は、変数名を $equipment_id(単数形)から $equipment_ids(複数形) に変えてあげると、後からコードを読む人が「あ、これは配列だな」と一瞬で理解できます。
4. フラグで分岐させるより「関数を2つに切り出す」
「更新」と「削除」の処理を1つの関数内でフラグ($delete_flag)を使って切り分けるよりも、最初から2つの関数に完全に分けるほうが圧倒的に綺麗なコードになります。
❌ 修正前:1つの関数でがんばる
public static function getErrorMessage($db, $id, $article_id, $category_name = '', $delete_flag = false)
⭕️ 修正後:役割ごとに2つに切り出す
「何に対して(KeepPatrol)」「どんな操作の(BulkUpdate / BulkDelete)」「検証を行うのか(Validate)」を名前に込めます。
// 1. 保守点検のまとめて更新バリデーション
public static function validateBulkUpdateKeepPatrol(PDO $pdo, int $equipment_id, int $article_id, string $category_name = ''): ?string
// 2. 保守点検のまとめて削除バリデーション
public static function validateBulkDeleteKeepPatrol(PDO $pdo, int $equipment_id, int $article_id): ?string
関数を分けたことで、削除時の呼び出しの際に不要な $category_name を気にしなくてよくなり、呼び出し側の引数迷子が完全に解消されます。
5. 変数の命名規則:スネークケース vs キャメルケース
「引数はスネークケース、関数内のローカル変数はキャメルケースにしたい」と使い分けに悩むことがあります。
結論:関数内ではどちらか片方に「100%統一」すべき!
PHPの標準規約である PSR-12 や PER Coding Style では、「どの命名規則を使うにしても、一貫して適用されるべき(SHOULD)」とされています。つまり、混ぜるのが一番よくありません。
混ぜてしまうと、以下のような罠にハマります。
- 上書きの罠: 引数(スネーク)を関数内で加工して新しい変数に代入するとき、キャメルに変えるべきか迷う。
- 名前付き引数の罠: 引数をスネークにすると、関数を呼び出す外側のコードまでスネークケースになってしまい、境界線が曖昧になる。
迷ったらどう決める?
- 既存のコードのルールに合わせる(最優先)
-
DBのカラム名に合わせる(
equipment_idなど、DBから取ってきた値をそのまま扱うならスネークケースで統一した方が直感的です)
同じ関数内に出てくる変数は、すべて同じルールで統一して、タイピング時の「どっちだっけ?」という迷いをゼロにしましょう。
まとめ
- デフォルト値を持たせるときは PHPDocの型表記と実装を一致 させる。
- 途中の引数を省略したいときは 名前付き引数 を使う。
- 1つの変数を配列にするときは
[]で包んで複数形の名前にする。 - フラグで処理を分岐させるくらいなら 関数を綺麗に2つに分ける。
- 引数と変数名は どちらか片方のケースに100%統一 する。
日々のコーディングで「おや?」と思ったら、これらの設計原則を思い出してみてください。可読性の高い、綺麗なコードへの第一歩になります!