PHP8.1から配列か連想配列かを判定する関数が追加されました。array_is_list()。
PHP公式ドキュメントでは、要素がない(0から始まる連番の要素)のことをリストと呼んでいます。
この関数は配列がリストかどうかを判定し true or false を返す。
array_is_list() の結果をパターン別に見る
この関数はかんたんで、『これまでなかったんだ...』と思うほどすんなり入ってくるものです。
いきなりサンプルコードで一気に見てみましょう。
今回、この関数を実行してテストします。
function output_result($arr)
{
var_dump($arr);
$result = array_is_list($arr);
var_dump($result);
}
要素のない通常の配列
$arr = ['aaa', 'bbb', 'ccc'];
output_result($arr);
array(3) {
[0]=>
string(3) "aaa"
[1]=>
string(3) "bbb"
[2]=>
string(3) "ccc"
}
bool(true)
要素を指定しない通常の配列は、自動で0から連番の要素が振られます。つまりリストになる。
trueになるのは必然。
要素に0から連番を振った連想配列
今度は連想配列で要素に0から連番を振ってみましょう。結果的に通常の配列と同じになるので結果は分かりますね?
$arr = [0 => 'aaa', 1 => 'bbb', 2 => 'ccc'];
output_result($arr);
array(3) {
[0]=>
string(3) "aaa"
[1]=>
string(3) "bbb"
[2]=>
string(3) "ccc"
}
bool(true)
リストなので予想通りtrueです。
要素が0以外から始まる連番の連想配列
$arr = [1 => 'aaa', 2 => 'bbb', 3 => 'ccc'];
output_result($arr);
array(3) {
[1]=>
string(3) "aaa"
[2]=>
string(3) "bbb"
[3]=>
string(3) "ccc"
}
bool(false)
連番でも、要素が0から始まってないとリストになりません。もちろん、マイナス値の連番もリストではない。
要素が連番じゃない連想配列
$arr = [0 => 'aaa', 2 => 'bbb', 1 => 'ccc'];
output_result($arr);
array(3) {
[0]=>
string(3) "aaa"
[2]=>
string(3) "bbb"
[1]=>
string(3) "ccc"
}
bool(false)
0から始まっても連番じゃないとリストになりません。
PHPでのリストの定義
- 要素は0から始まること
- 要素は連番であること
この条件をすべて満たさないものはリストではない。
要素を指定しない通常の配列は強制的にリストになる。
0から連番を振るが要素が文字列の連想配列
これはどうでしょう。0から始まる連番なんだけど、文字列で要素を作ってみます。
$arr = ['0' => 'aaa', '1' => 'bbb', '2' => 'ccc'];
output_result($arr);
array(3) {
[0]=>
string(3) "aaa"
[1]=>
string(3) "bbb"
[2]=>
string(3) "ccc"
}
bool(true)
数字(文字列の数値)の要素は、integer型に変換されます。リストになる。
array_is_list() の結果で一番のポイント。ぱっと見、falseになりそうだけど結果はtrueになります。
$arr =['0' => 'aaa', '-10' => 'bbb', 'c' => 'ccc', '100' => 'ddd'];
var_dump($arr);
array(4) {
[0]=>
string(3) "aaa"
[-10]=>
string(3) "bbb"
["c"]=>
string(3) "ccc"
[100]=>
string(3) "ddd"
}
配列を参照するとき、数字(string)と数値(integer)、どちらでもかまいません。
$arr =['0' => 'aaa', '-10' => 'bbb', 'c' => 'ccc', '100' => 'ddd'];
var_dump($arr[100]);
var_dump($arr['100']);
string(3) "ddd"
string(3) "ddd"
このパターンで結果がtrueになる秘密はここ。PHPは型がゆるいので内部で自動変換され同じものとして扱われます。
数字以外の要素の連想配列
$arr = ['a' => 'aaa', 'b' => 'bbb', 'c' => 'ccc'];
output_result($arr);
array(3) {
["a"]=>
string(3) "aaa"
["b"]=>
string(3) "bbb"
["c"]=>
string(3) "ccc"
}
bool(false)
これまで見てきたら想像できることですが、数字じゃない文字列はリストになりません。
最大の注意点。空配列はtrueを返す。
array_is_list() の最大の注意点は、空の配列はtrueを返します。
$arr = [];
$result = output_result($arr);
array(0) {
}
bool(true)
こうならないように、array_is_list()を使う際は条件を付けるのがベスト。
function is_list($arr)
{
if (!empty($arr) && array_is_list($arr))
{
echo 'is list' . PHP_EOL;
} else {
echo 'not list' . PHP_EOL;
}
}
$arr = [];
is_list($arr);
$arr = ['aaa', 'bbb', 'ccc'];
is_list($arr);
$arr = [1 => 'aaa', 2 => 'bbb', 3 => 'ccc'];
is_list($arr);
not list
is list
not list
配列以外の型で使うとエラー例外が発生
最後に、もし、配列以外のデータで使ったときはどうなるか見てみましょう。
<?php
function is_list($arr)
{
if (!empty($arr) && array_is_list($arr))
{
echo 'is list' . PHP_EOL;
} else {
echo 'not list' . PHP_EOL;
}
}
$number = 1;
is_list($number);
PHP Fatal error: Uncaught TypeError: array_is_list(): Argument #1 ($array) must be of type array, int given in /home/vagrant/php-test.php:5
Stack trace:
#0 /home/vagrant/php-test.php(5): array_is_list()
#1 /home/vagrant/php-test.php(14): is_list()
#2 {main}
thrown in /home/vagrant/php-test.php on line 5
TypeErrorの例外が発生します。Fatal Errorなので致命的。
array_is_list() を使うときは、さっきの条件にさらに、ほかの型が入力されたときの条件も付けましょう。
function is_list($arr)
{
if (is_array($arr) && !empty($arr) && array_is_list($arr))
{
echo 'is list' . PHP_EOL;
} else {
echo 'not list' . PHP_EOL;
}
}
$number = 1;
is_list($number);
$str = 'sample';
is_list($str);
$boo = true;
is_list($boo);
class Test{}
$obj = new Test();
is_list($obj);
$arr = ['aaa', 'bbb', 'ccc'];
is_list($arr);
$arr = ['a' => 'aaa', 'b' => 'bbb', 'c' => 'ccc'];
is_list($arr);
not list
not list
not list
not list
is list
not list
例外をキャッチして避ける方法もありです。
function is_list($arr)
{
try {
if (!empty($arr) && array_is_list($arr))
{
echo 'is list' . PHP_EOL;
} else {
echo 'not list' . PHP_EOL;
}
} catch( TypeError $e ) {
echo 'not list' . PHP_EOL;
echo 'function end (error)' . PHP_EOL;
return;
}
echo 'function end' . PHP_EOL;
}
$number = 1;
is_list($number);
$str = 'sample';
is_list($str);
$boo = true;
is_list($boo);
class Test{}
$obj = new Test();
is_list($obj);
$arr = ['aaa', 'bbb', 'ccc'];
is_list($arr);
$arr = ['a' => 'aaa', 'b' => 'bbb', 'c' => 'ccc'];
is_list($arr);
not list
function end (error)
not list
function end (error)
not list
function end (error)
not list
function end (error)
is list
function end
not list
function end
どっちで例外を避けてもいいですが、使い分けは必要です。
クラスベースで書いているなら、is_list()に例外発生の可能性を明示するために例外スローした方がいい。
is_list()内でエラー発生の可能性をつぶすならis_array()がいい、というように。
PHP公式ドキュメント