💡 今日の3行まとめ
  • 未定義キーや null に初期値を入れるときは、Null合体演算子 ?? を使う
  • empty() や ?: を使うと、有効な 0 まで初期値で上書きされるので注意
  • 配列の未設定キーにそのまま初期値を代入したいときは ??= で1行にまとめる

1. 今日のお題とゴール

会員データの連想配列から「ニックネーム」と「保有ポイント」を取り出して一覧表示する処理を作ります。

  • nickname が未設定または null の場合は 'ゲスト' と表示する
  • points キーが存在しない場合は初回特典の 100 を初期値にする
  • 保有ポイントが 0 の会員は上書きせず、そのまま 0pt と表示する
// 期待する出力結果
佐藤: 500pt
ゲスト: 0pt
田中: 100pt

2. ❌ やりがちなNGコード vs ⭕ コピペで動く正解コード

❌ やりがちなNGコードBefore
<?php
$user = ['name' => null, 'points' => 0];

// ❌ 存在しないキーを直接参照すると Warning(警告)が出る
$nickname = $user['nickname']; // Warning: Undefined array key "nickname"
// ❌ empty() は「0」も空と判定するため、0ptが100ptに化けてしまう
$points = !empty($user['points']) ? $user['points'] : 100;

echo "{$nickname}: {$points}pt\n";

存在しない配列キーを直接読むとPHP 8以降では Warning: Undefined array key が発生します。また、empty() や ?: で初期値を設定すると、数値の 0 まで「空(false)」と判定されて初期値に置き換わってしまいます。

⭕ コピペで動く正解コード(PHP 8.3+)After
<?php
declare(strict_types=1);

$users = [
    ['nickname' => '佐藤', 'points' => 500],
    ['nickname' => null, 'points' => 0], // 0ポイントはそのまま残したい
    ['nickname' => '田中'],              // pointsキー自体が存在しない
];

foreach ($users as $user) {
    // ?? は「キーが未定義」または「null」のときだけ右側の初期値を使う
    $nickname = $user['nickname'] ?? 'ゲスト';
    $points   = $user['points'] ?? 100;

    echo "{$nickname}: {$points}pt" . PHP_EOL;
}

// 配列自体に初期値を直接セットしたい場合は「??=」が便利
$config = ['theme' => 'dark'];
$config['theme'] ??= 'light'; // すでに値があるのでそのまま(dark)
$config['limit'] ??= 20;      // 未定義なので 20 が代入される

3. ここだけ押さえる!3つのポイント

1?? は未定義キーでも警告を出さずに初期値を返せる

$a ?? '初期値' は内部的に isset($a) ? $a : '初期値' と同じ動きをするため、存在しないキーを指定しても警告が出ません。左辺が「未定義」または null のときだけ右辺の値が使われます。

20 や '0' を守るなら empty() ではなく ??

PHPの empty() やエルビス演算子 ?: は、数値の 0 や文字列の '0' も「空」とみなしてしまいます。個数やポイントのように 0 が意味を持つデータでは必ず ?? を使いましょう。

3配列の中身を直接補完するなら ??=(Null合体代入)

$config['limit'] ??= 20; と書けば、「キーが未定義または null のときだけ代入する」処理を1行で書けます。設定配列のデフォルト値をまとめて埋めたいときに重宝します。

4. 1分ミニチャレンジ

🚀 手を動かしてみよう

正解コードの13行目にある $user['points'] ?? 100 を、エルビス演算子の $user['points'] ?: 100 に書き換えて実行すると、2人目(ゲスト)と3人目(田中)の結果はどう変わるでしょうか?(ヒント:?: は未定義キーのチェックを行わず、0 を false と判定します)