🍣

PHP __get()と__isset()とNull合体演算子と

2021/02/02に公開

PHPの __get() __isset() そしてNull合体演算子ではまりました。

事象

Laravel環境でEloquentのModelの __get() を拡張した際にこのような事象にあいました。

<?php
// hogeは存在しないプロパティ
// __getで動的に値を返している
echo $obj->hoge; // -> 'hoge'
echo $obj->hoge ?? 'fuga'; // -> 'fuga'

$obj->hogenull ではないのにNull合体演算子で null 判定される?
という感じで悩みました。

Null合体演算子

Null合体演算子 ?? はPHP7から入った新機能です。
isset($hoge) ? $hoge : 'fuga'$hoge ?? 'fuga' と書けます。

https://www.php.net/manual/ja/migration70.new-features.php#migration70.new-features.null-coalesce-op

つまり今回の事象は isset($obj->hoge) === false であったということなのです。

__isset()

__isset() は、 isset() あるいは empty() をアクセス不能(protected または private)または存在しないプロパティに対して実行したときに起動します。

https://www.php.net/manual/ja/language.oop5.overloading.php#object.isset

存在しないプロパティに対して isset() empty() を実行すると __isset() がコールされるのでそこで適切な値を返さないといけないわけでした。

解決

Illuminate\Database\Eloquent\Model__isset を追いまして、自分用の存在チェックを滑り込ませました。
ということで__get() を触る時は __isset() もセットでお願いします。(なるべくマジックメソッド使うべからず)

Discussion