Laravelを使用していると、「optional()」関数を目にすることがあるかもしれません。この関数はLaravelにおけるエレガントなコードを助け、多くの場合、ネストされたプロパティへのアクセスでのエラーを回避するのに役立ちます。この記事では、optional()関数の基本的な使い方や活用事例を詳しく解説します。
optional()関数とは?
optional()は、Laravelに搭載されている便利なヘルパー関数の一つです。主に、オブジェクトや値がnullの場合に発生しうるエラーを未然に防ぐために使用されます。これにより、例えばnullなオブジェクトからメソッドを呼び出そうとしたときの厄介な「Call to a member function on null」というエラーを回避できます。
optional()の基本構文
$value = optional($object)->property;
この構文を使うと、$objectがnullの場合でもエラーが発生せず、さらにプロパティが未定義でもnullを返します。
なぜoptional()を使うのか?
1. 安全なネストされたプロパティアクセス
例えば、Eloquentモデルから関連モデルのプロパティにアクセスする場合、関連モデルがnullの場合が考えられます。このとき、optional()を使用することで、nullチェックを前もって書く必要がなくなります。
// 通常の方法
$user = User::find($id);
$companyName = $user && $user->company ? $user->company->name : null;
// optional()を使用
$companyName = optional(optional($user)->company)->name;
2. クリーンで読みやすいコード
以下のように多くのnullチェックを書くコードは非常に煩雑になり、読むのが難しくなります。
// 煩雑なnullチェック
if ($user !== null && $user->profile !== null) {
$age = $user->profile->age;
} else {
$age = null;
}
optional()を使うことで、これは以下のように簡単になります。
// optional()を使った簡潔なコード
$age = optional(optional($user)->profile)->age;
活用事例
エラーなしでチェーンアクセス
あるAPIレスポンスやデータモデルから複数階層にわたるオブジェクトを扱う際、optional()は助けになります。
// データモデルにネストされたオブジェクトアクセス
$city = optional(optional($order->user)->profile)->city;
この例では、orderがnullであるか、そのuserプロパティがnullであるか、そのprofileがnullである場合、いずれの場合もエラーが発生せずにnullが返ってきます。
関数実行を使う
optional()は単にプロパティをチェックするだけでなく、メソッドを安全に呼び出すのにも使用します。
// optional()でメソッド呼び出し
echo optional($user->profile)->formatAge();
メソッド formatAge() が存在しない場合や、profileがnullである場合でも安全にnullを返します。
特定条件のガード
特定の条件に基づいて処理を続行するかどうかのガードとしてoptional()を使うという手法もあります。
$billingInfo = optional($user->billingDetails)->first();
// $billingInfoがnullの場合後続処理を行わない
if (!$billingInfo) {
// 必要な処理を書いておく
}
optional()とnull合体演算子の違い
PHP 7で導入されたnull合体演算子(??)とはどう違うのでしょうか。null合体演算子は、nullかどうかに基づいてデフォルトの値を指定できます。この点で用途が重なる部分がありますが、optional()はもう一歩進んで、メソッドチェーンに対しても安全に操作が行えます。一方で、null合体演算子はオブジェクトのプロパティのみを扱います。
// null合体演算子の使用例
$username = $user->profile->username ?? 'ゲスト';
PHP8のnullsafe演算子(?->)との使い分け
PHP 8.0からは、言語標準の機能としてnullsafe演算子(?->)が使えるようになりました。単純にプロパティやメソッドチェーンの途中がnullかどうかだけを気にするなら、こちらのほうが記述もシンプルです。
// nullsafe演算子を使った書き方(PHP 8以降)
$city = $order?->user?->profile?->city;
ではoptional()は不要になったのかというと、そうではありません。optional()はnullの場合に空のオブジェクトを返すという特徴があり、Bladeテンプレート内でメソッドチェーンをそのまま書きたい場合や、Carbonインスタンスのように「nullでもメソッド呼び出し自体は失敗させたくない」場面では今でも有効です。単純なnullチェックはnullsafe演算子、Bladeでの安全なメソッドチェーンや第2引数にクロージャを渡す用途にはoptional()、という使い分けが実務的です。
よくある質問
Q. optional()はLaravelの新しいバージョンで非推奨になりましたか?
A. いいえ、optional()は現在も現行のLaravelで利用できるヘルパー関数です。PHP 8のnullsafe演算子と役割が重なる部分はありますが、廃止予定のアナウンスはありません。
Q. optional()に第2引数を渡すとどうなりますか?
A. optional($user, function ($user) { return $user->name; })のようにクロージャを第2引数に渡すと、第1引数がnullでない場合のみクロージャが実行されます。単純なプロパティアクセスだけでなく、値がある場合にだけ処理を行いたいケースにも活用できます。
Q. optional()は配列に対しても使えますか?
A. optional()はオブジェクトのプロパティ・メソッドアクセスを想定したヘルパーです。配列に対してはArr::get()など配列操作用のヘルパーを使うほうが適切です。
結論
Laravelのoptional()は、コードの冗長さをなくし、データの扱いやすさを提供する強力なツールです。特に「nullなオブジェクト」や「存在しないプロパティ」に対処する場合に大いに役立ちます。これを利用することにより、エレガントで読み取りやすいコードベースの作成を促進します。このガイドを参考にして、プロジェクトでoptional()を活用してみてください。
Eloquentやブレード内でのnull判定の全体像はLaravelでのnull判定方法まとめでも解説しています。あわせてご覧ください。

コメント