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

PHP8.1, array_is_list, 配列か連想配列か判定する関数

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

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()がいい、というように。

前の投稿
PHP8.1, fsync, ファイルの同期をする関数。ついにPHPでも来たか。

コメントを残す