PHPの開発において、変数が未定義であったり値がNULLであったりする場合の処理は非常に頻繁に発生します。
以前のPHPでは三項演算子とisset関数を組み合わせて記述していましたが、PHP 7.0以降では「Null合体演算子(??)」の登場により、これらを非常に簡潔に記述できるようになりました。
本記事では、PHPプログラミングにおける効率化の鍵となるNull合体演算子の基本的な使い方から、実務で役立つ応用テクニック、さらには間違いやすい注意点までを詳しく解説します。
Null合体演算子(??)の基本概念
Null合体演算子は、左側のオペランド(値)が「NULLではない」かつ「定義されている」場合にその値を返し、それ以外の場合に右側の値を返す演算子です。
具体的には、$a ?? $b という形式で記述します。
これは従来の isset($a) ? $a : $b と全く同じ挙動を示します。
以下のコードで、実際の動作を確認してみましょう。
// 変数がNULLの場合
$userName = null;
$displayName = $userName ?? 'ゲストユーザー';
echo $displayName;
ゲストユーザー
上記の例では、$userName がNULLであるため、右側の値である「ゲストユーザー」が代入されています。
もし $userName に「山田太郎」という文字列が入っていれば、その値がそのまま採用されます。
この演算子の最大の特徴は、変数が定義されていない場合でも「Notice」エラーが発生しないという点にあります。
三項演算子(?:)やエルビス演算子との違い
PHPには似たような記述方法として「三項演算子」や、その省略形である「エルビス演算子(?:)」が存在します。
これらの違いを正しく理解しておくことは、バグを防ぐために非常に重要です。
主な違いを以下の表にまとめました。
| 演算子 | 名称 | 判定基準 | 未定義変数の扱い |
|---|---|---|---|
$a ?? $b | Null合体演算子 | $a が NULL でなければ $a | エラーが発生しない |
$a ?: $b | エルビス演算子 | $a が true と評価されれば $a | Noticeエラーが発生する |
エルビス演算子(?:)は、値が「空文字(””)」や「数値の0」の場合も「false」と判定し、右側の値を返します。
対して、Null合体演算子はあくまでNULLか未定義かのみを判定するため、0や空文字を有効な値として扱いたい場合に最適です。
具体的な挙動の比較
次のコードは、値が「0」の場合の挙動の違いを示しています。
$count = 0;
// Null合体演算子の場合
echo $count ?? 10; // 結果: 0
// エルビス演算子の場合
echo $count ?: 10; // 結果: 10
このように、数値の0を許容したい設定値の取得などでは、Null合体演算子を使用するのが一般的です。
Null合体演算子の連結(チェイン)
Null合体演算子は、複数を連結して記述することが可能です。
これにより、優先順位に従って「最初に見つかったNULL以外の値」を取得するロジックを1行で書くことができます。
// 優先順位:ユーザー設定 > デフォルト設定 > システム既定値
$userTheme = null;
$defaultTheme = 'Dark';
$systemTheme = 'Light';
$activeTheme = $userTheme ?? $defaultTheme ?? $systemTheme;
echo $activeTheme;
Dark
この例では、$userTheme がNULLであるため次に $defaultTheme を参照し、それがNULLでないため「Dark」が採用されています。
条件分岐(if文)を重ねる必要がないため、コードの可読性が大幅に向上します。
Null合体代入演算子(??=)の活用
PHP 7.4からは、さらに便利な「Null合体代入演算子(??=)」が導入されました。
これは、「もし変数がNULLまたは未定義なら、値を代入する」という処理を短縮して書くためのものです。
$config = [];
// 従来の書き方
if (!isset($config['timeout'])) {
$config['timeout'] = 30;
}
// Null合体代入演算子を使用した書き方
$config['timeout'] ??= 30;
echo $config['timeout'];
30
配列の初期値をセットする場合などに非常に重宝します。
すでに値が存在する場合は代入が行われないため、既存の値を上書きしてしまう心配もありません。
実務での活用シーン:ユーザー入力の処理
最も実用的なケースの一つは、HTMLフォームから送信されたデータ($_GETや$_POST)の処理です。
特定のキーが存在しない可能性がある場合でも、Null合体演算子を使えばスマートに記述できます。
// クエリパラメータ 'page' があればその値を、なければ 1 を代入
$page = $_GET['page'] ?? 1;
// 複数の入力をまとめて処理する例
$search = [
'keyword' => $_POST['keyword'] ?? '',
'category' => $_POST['category'] ?? 'all',
'sort' => $_POST['sort'] ?? 'newest'
];
print_r($search);
この方法を使えば、isset() によるチェックを繰り返す必要がなくなり、タイプミスの削減や保守性の向上に繋がります。
使用上の注意点と落とし穴
非常に便利なNull合体演算子ですが、使用にあたって注意すべき点がいくつかあります。
1. NULL以外は「存在」とみなされる
先述の通り、空文字列 "" や空の配列 []、数値の 0、論理値の false は「NULLではない」ため、これらは有効な値として返されます。
もし「値が空の場合もデフォルト値にしたい」という意図がある場合は、Null合体演算子ではなく三項演算子と empty() 関数を組み合わせるべきです。
2. ネストされた配列へのアクセス
Null合体演算子は、深い階層の配列アクセスに対しても安全に使用できます。
$data = [
'user' => [
'profile' => null
]
];
// 途中のキーが存在しなくてもエラーにならない
$city = $data['user']['address']['city'] ?? '未登録';
echo $city;
このように、'address' というキーが存在しない場合でも、自動的に右側の値が返されます。
ただし、意図しない構造のデータを許容してしまう可能性もあるため、データの整合性が重要な箇所では注意が必要です。
まとめ
PHPのNull合体演算子(??)は、冗長になりがちなNULLチェックを簡潔に記述するための非常に強力なツールです。
「変数が定義されているか」「NULLではないか」という2点を同時に、かつ安全に判定できる点が最大のメリットです。
最後に、本記事のポイントを振り返ります。
$a ?? $bはisset($a) ? $a : $bの短縮形である。- 未定義の変数にアクセスしてもNoticeエラーが発生しない。
- 0や空文字、falseはNULLではないため、左側の値として採用される。
- 複数を繋げて記述することで、優先順位に基づいた値の取得が可能。
- PHP 7.4以降は
??=による簡潔な代入も可能。
現代のPHP開発において、Null合体演算子の活用は標準的な作法となっています。
特性を正しく理解し、読みやすく、かつ堅牢なコードを記述するために積極的に活用していきましょう。
