PHP empty()の仕様について

# はじめに
`empty()`の仕様を忘れがちな方、これから知りたい方に向けての記事になります。
結論を見たい方は下記の「[まとめ](#まとめ)」の表を見てください。

# 前提
* PHP8.1

# emptyの仕様について
公式のドキュメントによると、`empty()`は` !isset($var) || $var == false`と同じ結果になるようです。

> 変数が存在しなくても警告は発生しません。 つまり、empty() は本質的に `!isset($var) || $var == false` と同じことを簡潔に記述しているだけです。

https://www.php.net/manual/ja/function.empty.php


`empty()`の挙動を細かく知るために`!isset()`と`$var == false`それぞれの判定がどのような結果になるのかを見ていきたいと思います。

## !isset()の挙動
まず`isset()`の挙動についてですが、引数が未定義の変数、もしくは`null`の場合に`false`を返します。`!isset()`ではその結果の逆になるので、未定義の変数と`null`の場合は`true`を返します。

https://www.php.net/manual/ja/function.isset.php

下記は`!isset()`の挙動を確認するためのコードです。
```php
<?php
$ary1 = [];
$ary2 = [
	'',
	"",
	[],
	true,
	false,
	0,
	1,
 	'0',
	'1',
	sqrt(-1), // NANを返す
 	null,
 	$foo, // 未定義の変数
 	$ary1['foo'], // 未定義の配列キー
];
foreach ($ary2 as $value) {
	var_dump(!isset($value));
}
```

**処理結果**
```php
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
```
※`$foo`と`$ary['foo]`を配列にセットしているため、警告文が表示されます。 

`$ary['foo']`についてですが、配列に定義されていないキーにアクセスした場合、未定義の変数にアクセスした時と同じ挙動になるので`true`になります。

https://www.php.net/manual/ja/language.types.array.php#language.types.array.syntax.accessing

**値と判定結果の表**
| 値 | 判定結果 |
| ---- | ---- |
| '' | <font color="#ff9642">false</font> |
| "" | <font color="#ff9642">false</font> |
| [] | <font color="#ff9642">false</font> |
| true | <font color="#ff9642">false</font> |
| false | <font color="#ff9642">false</font> |
| 0 | <font color="#ff9642">false</font> |
| 1 | <font color="#ff9642">false</font> |
| '0' | <font color="#ff9642">false</font> |
| '1' | <font color="#ff9642">false</font> |
| NAN | <font color="#ff9642">false</font> |
| null | <font color="#0074cc">true</font> |
| 未定義変数 | <font color="#0074cc">true</font> |
| 未定の配列キー | <font color="#0074cc">true</font> |

## $var == falseの挙動
比較演算子の`==`で各値と`false`と比較した場合にどのような結果になるのか下記のコードで確認してみました。
```php
<?php
$ary1 = [];
$ary2 = [
	'',
	"",
	[],
	true,
	false,
	0,
	1,
 	'0',
	'1',
	sqrt(-1), // NANを返す
 	null,
 	$foo, // 未定義の変数
 	$ary1['foo'], // 未定義の配列キー
];
foreach ($ary2 as $value) {
	var_dump($value == false);
}
```
**処理結果**
```php
bool(true)
bool(true)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)
bool(true)
bool(false)
bool(false)
bool(true)
bool(true)
bool(true)
```

※`$foo`と`$ary['foo]`を配列にセットしているため、警告文が表示されます。 

**値と判定結果の表**
| 値 | 判定結果 |
| ---- | ---- |
| '' | <font color="#0074cc">true</font> |
| "" | <font color="#0074cc">true</font> |
| [] | <font color="#0074cc">true</font> |
| true | <font color="#ff9642">false</font> |
| false | <font color="#0074cc">true</font> |
| 0 | <font color="#0074cc">true</font> |
| 1 | <font color="#ff9642">false</font> |
| '0' | <font color="#0074cc">true</font> |
| '1' | <font color="#ff9642">false</font> |
| NAN | <font color="#ff9642">false</font> |
| null | <font color="#0074cc">true</font> |
| 未定義変数 | <font color="#0074cc">true</font> |
| 未定の配列キー | <font color="#0074cc">true</font> |

`!isset()`との違いは、空文字、空配列、0、'0'で`true`が返ってくるところです。

# まとめ
`!isset()`、`$var == false`、`empty()`それぞれの判定結果は下記のようになります。
| 値 | !isset() | $var == false | empty() |
| ---- | ---- | ---- | ---- |
| '' | <font color="#ff9642">false</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| "" | <font color="#ff9642">false</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| [] | <font color="#ff9642">false</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| true | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> |
| false | <font color="#ff9642">false</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| 0 | <font color="#ff9642">false</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| 1 | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> |
| '0' | <font color="#ff9642">false</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| '1' | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> |
| NAN | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> | <font color="#ff9642">false</font> |
| null | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| 未定義変数 | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |
| 未定の配列キー | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> | <font color="#0074cc">true</font> |

表にしてみるとわかるのですが、`$var == false`と`empty()`の結果は全く同じで、違うところは、`empty()`は「未定義の変数の場合に警告を出さない」ところです。
冒頭で説明した`!isset() || $var == false`の`!isset()`の役割は未定義の変数の場合は警告を出さないようにすることで、判定結果に関しては`$var == false`と全く同じということですね。

# 終わりに
ここまで見ていただきありがとうございました。
言語の細かい仕様って何度も調べがちですよね、、、


# 参考
https://www.php.net/manual/ja/function.empty.php

https://www.php.net/manual/ja/function.isset.php

https://www.php.net/manual/ja/language.operators.comparison.php