ツイート
シェア
LINEで送る
B! はてぶでブックマーク
Pocketでブックマーク
RSSフィード

PHP8, Nullsafe, オブジェクトのnullチェックを省略するプロパティ・メソッド参照

php
イラストダウンロードサイト【イラストAC】
の画像をもとに加工しています。

PHPはメジャーアップデートで8が登場しました。そこで追加されたのがNullsafe演算子(?->)。

『?』とクラスオブジェエクトのメソッドやプロパティを参照する『->』を足したもの。

Null合体演算子を使いながらメソッドやプロパティを見る使ってるイメージだと分かりやすい。

Nullsafe演算子とはなにか?

Nullsafe演算子は『?->』のことです。

クラスオブジェクトのプロパティやメソッドを参照するときに『->』を使いますが、Nullsafeはこの参照演算子の代わりに使います。

Null + safe は、『Null値でも安心して使える』という意味。(くわしくは読んでいくと分かる。)

class Test
{
    public $public_value = 'public value';
    private $private_value = 'private value';

    public function getPrivateValue()
    {
        return $this->private_value;
    }
}

$test = new Test();

// 通常のメソッドやプロパティの参照。
$val1 = $test->public_value;
$val2 = $test->getPrivateValue();

var_dump($val1);
var_dump($val2);

// Nullsafeでの参照
$val1 = $test?->public_value;
$val2 = $test?->getPrivateValue();

var_dump($val1);
var_dump($val2);
実行結果
string(12) "public value"
string(13) "private value"
string(12) "public value"
string(13) "private value"

ということは分かりますね? Nullsafe演算子はクラスオブジェクトで使うもので、クラス以外では使いません。

しかしサンプルコードを見ていると、なんであえて ? を付けたのか分かりません。

『?』は自動で行われるnullチェック(is_null())

Nullsafe演算子はたんにプロパティやメソッドを参照するときには威力を発揮しません。

発揮する場所はこれらの参照のチェインの場合です。チェイン(chain)は日本語訳では鎖、チェーンのこと。

意訳すれば数珠つなぎです。

class Test
{
    public $session = null;
}

class Session
{
    public $user = null;
}

class User
{
    public $id = 0;

    public function __construct($id)
    {
        $this->id = $id;
    }
}

$user = new User(12);

$session = new Session();
$session->user = $user;

$test = new Test();
$test->session = $session;

// idの参照
$id = $test->session->user->id;
var_dump($id);
実行結果
int(12)

このコードでは、Test, Sessionクラス内のプロパティをオブジェクトで埋めてから実行しているので問題ありません。

しかし、次の場合はどうでしょう?

null値オブジェクトの参照は危険

<?php

$test = new Test();

// idの参照
$id = $test->session->user->id;
var_dump($id);
実行結果
PHP Warning:  Attempt to read property "user" on null in /home/vagrant/php-test.php on line 6
PHP Warning:  Attempt to read property "id" on null in /home/vagrant/php-test.php on line 6
NULL

$test 内の session は null なのに user を参照しようとし、user が null なのに id を参照しようとしています。

メッセージの内容は『null値から user を見ようとしているよ?』『null値から id を見ようとしているよ?』。

PHPは警告で済んでますが、ほかのオブジェクト指向言語なら致命的なエラー。

ここで使うのがNullsafe演算子です。

nullオブジェクト参照を回避するNullsafe演算子

$test = new Test();

// idの参照
$id = $test?->session?->user?->id;
var_dump($id);
実行結果
NULL

null参照の警告がすべてなくなりました。Nullsafe演算子でのコーディングはこの処理と同じです。

$id = null;
if (null !== $test) {
    if (null !== $test->session) {
        if (null !== $test->session->user) {
            $id = $test->session->user->id;
        }
    }
}

Nullsafe演算子では左のオブジェクトがnullかどうかを判別し、nullなら右の参照をストップしそこで処理を終え、nullじゃないなら右の参照を続行します。

これを繰り返すのでnull参照はしない(警告も出ない)し処理として安全です。

Nullsafe演算子は、どこかでnullを見つけて参照を途中で止めるとnull値を返します。エラーや例外は発生しないので注意が必要。

復習。三項演算子やNull合体演算子の『?』

Nullsafe演算子の『?』は三項演算子やNull合体演算子と同じような意味です。

三項演算子とNull合体演算子の復習をしましょう。

三項演算子の復習

三項演算子のサンプル
function test($x, $y)
{
    return (5 > $x + $y) ? 'clear' : 'NG';
}

var_dump(test(2, 4));
var_dump(test(1, 3));
string(2) "NG"
string(5) "clear"

三項演算子では式が合っていれば(true)、『?』の次の値を返します。

PHP公式ドキュメント

三項演算子

『それがNullsafeとなんの関係が?』と思うでしょうが、次のNull合体演算子を見ればわかる。

Null合体演算子の復習

Null合体演算子のサンプル
function test($x)
{
    return $x ?? 'non-value';
}

var_dump(test(2));
var_dump(test('sample'));
var_dump(test(null));
実行結果
int(2)
string(6) "sample"
string(9) "non-value"

Null合体演算子はPHP7.0から追加されたもので、nullに特化した三項演算子のことです。

PHP公式ドキュメント

Null合体演算子

三項演算子の『?』にもう1個『?』を足して『??』にすると、左の式がnullだったときに返す値だけを定義します。

もう気づきましたか?

Null合体演算子では『Nullだったら〇〇を返す』の意味で『?』を使い、Nullsafeでは『Nullだったら参照を止める』の意味で使います。

『?』が『Nullだったら』の意味はもともとあるもの。

またNull合体演算子は、複数行の条件分岐を1行で書いて省略するのでシンタックスシュガーです。

シンタックスシュガー(syntax sugar, 糖衣構文)

プログラムで、読みやすさ、書きやすさのために導入された書き方。

ドキュメントや書籍などの書式で多く出てくるものではなく、たまに出てくるので『通好み』『デキる人の書き方』に見られることが多い。

そういう意味ではNullsafeもシンタックスシュガー。

$id = null;
if (null !== $test) {
    if (null !== $test->session) {
        if (null !== $test->session->user) {
            $id = $test->session->user->id;
        }
    }
}

// 上をNullsafeですると、1行ですっきりと書ける。
$id = $test?->session?->user?->id;
前の投稿
PHP8, match式の追加。switchとちがって変数に代入可。
PHP8, 関数のパラメータ順が関係なくなる。名前付きパラメータの追加。
次の投稿
コメントを残す

*