2024.12.25
STAFF BLOG
スタッフブログ
TECHNICAL
テクログ
はじめに
結論から述べると、
▼ isset()
falseになるパターンだけ覚える!
・null
・未定義
▼ empty
trueになるパターンだけ覚えて、引数の型ごとにパターンを整理する!
・int:0
・float:0.0, -0.0
・string:’0′, 空文字
・bool:false
・array:空配列
・null
・未定義
※基本はこれらのパターンだけですが、例外がいくつかあるので後述します。
検証環境
・PHP:v8.4.2
issetの戻り値
issetは「変数が宣言されていること、そして null とは異なることを検査する」関数です。
参考:https://www.php.net/manual/ja/function.isset.php
issetの戻り値は、引数が次の値を取るときに「false」になります。(それ以外は「true」です。)
・null
・未定義
<?php
// null
$null = null;
var_dump(isset($null)); // false
// 未定義
var_dump(isset($undefined)); // false
そのため、falseになる2つのパターンだけを覚えて、それ以外はtrue だと押さえておくと混乱しにくくなると思います。
issetの例外
マジックメソッド「__isset」が実装されたクラスのプロパティを引数に取った場合だけ例外です。
__issetは「isset or emptyを、アクセス不能 or 存在しないプロパティに対して実行したときに起動」するマジックメソッドです。
※アクセス不能:protected or private
参考:https://www.php.net/manual/ja/language.oop5.overloading.php#object.isset
そのため、存在しないプロパティをissetの引数に取ったとしても、__issetの戻り値がtrueの場合、issetの戻り値は__issetの戻り値と同じ「true」になります。
ただし、emptyの戻り値は__issetの戻り値に影響しない点に注意が必要です。emptyの戻り値は__issetの有無や戻り値に関わらず、引数に取ったプロパティが存在しない場合は「true」、存在する場合は「false」になります。
<?php
class All_True
{
public function __isset(string $name): bool
{
return true;
}
}
$all_true = new All_True();
var_dump(isset($all_true->hoge)); // true:__issetの戻り値がtrueだから
var_dump(empty($all_true->hoge)); // true:hogeプロパティは存在しないから
class All_False
{
public function __isset(string $name): bool
{
return false;
}
}
$all_false = new All_False();
var_dump(isset($all_false->hoge)); // false:__issetの戻り値がfalseだから
var_dump(empty($all_false->hoge)); // true:hogeプロパティは存在しないから
余談:__issetの用途
__issetは、マジックメソッド「__get」と、「isset」を併用する場合に必要になります。
__issetを実装せずに、__get経由で値を取得しようとしているプロパティをissetの引数に取ったとき、存在しないプロパティへのアクセス判定が先に処理されるため、issetの戻り値は常に「false」になってしまいます。
▼ __issetを実装しない場合
<?php
class Hoge
{
private $data;
public function __construct()
{
$this->data = [];
}
public function __get(string $name)
{
return $this->data[$name] ?? null;
}
public function __set(string $name, $value): void
{
$this->data[$name] = $value;
}
}
$hoge = new Hoge();
$hoge->fuga = 'fuga';
var_dump(isset($hoge->fuga)); // false:存在しないプロパティへのアクセス判定が先のため(ゲッターの処理が後)
▼ __issetを実装した場合
<?php
class Hoge
{
private $data;
public function __construct()
{
$this->data = [];
}
public function __get(string $name)
{
return $this->data[$name] ?? null;
}
public function __set(string $name, $value): void
{
$this->data[$name] = $value;
}
public function __isset(string $name): bool
{
return isset($this->data[$name]);
}
}
$hoge = new Hoge();
$hoge->fuga = 'fuga';
var_dump(isset($hoge->fuga)); // true:__issetメソッドの戻り値が使用されるため
emptyの戻り値
emptyは「変数が空であるかどうかを検査する」関数です。
参考:https://www.php.net/manual/ja/function.empty.php
emptyの戻り値は、引数が次の値を取るときに「true」になります。(それ以外は「false」です。)
・int:0
・float:0.0, -0.0
・string:’0′, 空文字
・bool:false
・array:空配列
・null
・未定義
<?php
// int
var_dump(empty(0)); // true
// float
var_dump(empty(0.0)); // true
var_dump(empty(-0.0)); // true
// string
var_dump(empty('0')); // true
var_dump(empty('')); // true
// bool
var_dump(empty(false)); // true
// array
var_dump(empty([])); // true
// null
var_dump(empty(null)); // true
// 未定義
var_dump(empty($val)); // true
説明文にある「変数が空である」というのが抽象的でわかりづらいですが、emptyは次のコードと同じ役割を果たします。
!isset($var) || $var == false
そのため、emptyの戻り値は次のようにまとめることができます。
・issetの戻り値がfalseなら、emptyの戻り値は「true」
・引数がfalseとの緩やかな比較でtrueになる場合、emptyの戻り値も「true」
bool型との緩やかな比較の結果は下記リンク先から確認できます。
https://www.php.net/manual/ja/language.types.boolean.php#language.types.boolean.casting
緩やかな比較は型ごとに挙動が異なります。そのため、emptyの戻り値は 型ごとに整理して覚えておく のと、trueになる9つのパターンだけを覚えて、それ以外はfalse だと押さえておくと混乱しにくくなると思います。
emptyの例外
bool型へキャストするように動作がオーバーライドされたオブジェクトを引数に取った場合が例外です。例えば、「属性がない空要素から作成されたSimpleXMLオブジェクト」がそれに該当します。
<?php
$xml_obj = new SimpleXMLElement('<a></a>'); // 空要素から作成されたSimpleXMLオブジェクト
var_dump(empty($xml_obj)); // true
$std_obj = new stdClass(); // プロパティが存在しないオブジェクト
var_dump(empty($std_obj)); // false
参考:https://www.php.net/manual/ja/language.types.boolean.php#language.types.boolean.casting
おわりに
issetとemptyの戻り値で混乱している人の一助になれば幸いです。