php array_filter: 配列の空要素削除に使うのはダメ!

他言語サイト
us us
PHP ロゴ

array_filter(), array_values()を使って、配列から空要素を削除する方法があります。

しかし、この方法を使うのは絶対に避けるべきです。その理由をサンプルコードで説明します。

array_filter(), array_values()を使った空要素削除の方法

使ってはいけない理由の前に、array_filter(), array_values()ではどのようにして空要素を削除するのか見てみましょう。

<?php

$array = [
    'data1',
    '',
    'data2',
    '',
    'data3',
    '',
    'data4',
    '',
    'data5',
];
$tmp = array_filter($array, 'strlen');
$array = array_values($tmp);

echo "Intermediate results:\n";
echo var_dump($tmp) . "\n\n";

echo "result:\n";
echo var_dump($array) . "\n\n";

実行結果はこのようになります。

Intermediate results:
array(5) {
  [0]=>
  string(5) "data1"
  [2]=>
  string(5) "data2"
  [4]=>
  string(5) "data3"
  [6]=>
  string(5) "data4"
  [8]=>
  string(5) "data5"
}


result:
array(5) {
  [0]=>
  string(5) "data1"
  [1]=>
  string(5) "data2"
  [2]=>
  string(5) "data3"
  [3]=>
  string(5) "data4"
  [4]=>
  string(5) "data5"
}

すばらしい!意図した結果が出ましたね?

  • array_filter()で各配列のデータに対してstrlen()を実行します。
  • 0が返るものは配列から削除します。実際は0はfalseと判定されています。
  • このままでは、削除しただけで配列のインデックスは変わっていません。インデックスを振りなおすためにarray_values()を実行します。

このように、array_filter(), array_values()で空要素を削除します。

しかしアプリケーション開発では、データの型が変わることは頻繁に起こります。もし、配列のデータの型がクラスのインスタンスや配列になったらどうなるでしょう?

実はここに問題があります。

配列やインスタンスは空でなくても消えてしまう

配列のデータに、配列やクラスのインスタンスが含まれているサンプルプログラムで、空要素の削除処理を実行してみましょう。

<?php

class TEST {
    private $property = 'property';
}

$array = [
    new TEST(),
    '',
    ['array1-1', 'array1-2', 'array1-3'],
    '',
];

$array = array_filter($array, 'strlen');
$array = array_values($array);

echo "result:\n";
echo var_dump($array) . "\n\n";

実行結果はこのようになります。

result:
array(0) {
}

配列も、クラスのインスタンスも消えてしまいました。これはかなりまずい状況です。

array_filter()では、配列やクラスのインスタンスは空でなくても消えてしまう

array_filter(), array_values()で空要素を削除してはいけない理由

ソースコードにarray_filter()が多く使われている場合どうなるでしょうか?

配列データやクラスのインスタンスのデータが消える原因を調査しないといけません。人によっては本当にデータが生成されているのか確認する人もいるでしょう。これには膨大な時間がかかることもあります。

ちょっとデータの型を変更しただけでデータが消えるプログラムをどう思いますか?誰にとってもいいことはありません。

しかも厄介なのは、PHP5.3より前のバージョンでは、配列データは消えませんでした。これは、strlen()で配列を指定した場合、"Array"の文字列長(5)を返していたからです。PHP5.3以降は0が返るようになっています。

この仕様変更は、PHPのドキュメントにも記載されています。strlen()のPHPの公式ドキュメント

このように、array_filter(), array_values()を使った空要素の削除処理は使えば使うほどバグの温床となります。

素直にプログラムを書いてしまおう!

こういうときは素直にプログラムを書いてしまうのがベストです。処理自体も難しい処理は行いません。

サンプルプログラムを見てみましょう。

<?php

class TEST {
    private $property = 'property';
}

$array = [
    new TEST(),
    '',
    'data2',
    '',
    ['data3-1', '', 'data3-2', '', 'data3-3'],
    '',
    'data5',
];

function delete_empty_array($array) {
    $tmp;
    foreach($array as $item) {
        if( is_array($item) ) {
              $tmp[] = delete_empty_array($item);
        } else {
              if( ! empty($item)) {
                  $tmp[] = $item;
              }
        }
    }
    return $tmp;
}

$array = delete_empty_array($array);

echo "result:\n";
echo var_dump($array);

実行結果はこのようになります。

result:
array(4) {
  [0]=>
  object(TEST)#1 (1) {
    ["property":"TEST":private]=>
    string(8) "property"
  }
  [1]=>
  string(5) "data2"
  [2]=>
  array(3) {
    [0]=>
    string(7) "data3-1"
    [1]=>
    string(7) "data3-2"
    [2]=>
    string(7) "data3-3"
  }
  [3]=>
  string(5) "data5"
}

空要素を削除する関数delete_empty_array()を用意して、配列の各データを走査します。

走査するデータの中に配列データがある場合、この関数の中で再帰的にdelete_empty_array()を呼び出します。これで、多次元配列(2次元以上の配列)のすべての階層の空要素を削除します。

配列データ以外で空要素でないものはそのままデータをコピーします。

たった10行弱の処理で終わりです。これだけの作業でバグになる可能性を消すことができます。

 

最近Webカテゴリでよく読まれている記事です。
post-cta-image
blog image

ドメイン取得の意味が分からない人へ。王道の方法を紹介します。

ドメインの登録業者を選ぶのに悩む必要はないです。サイトを簡単に早く公開するには全くいらないことで、むしろ邪魔です。『お名前.com』というサービスは必ず耳にします。そのお名前.comのメリットとデメリットと一緒に、ドメインの意味が分からない人が一番失敗しないドメインの取得方法を紹介します。

tadtadya.com

_

SNSでも記事を配信しています。
コメントを残す

*

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

この記事を気に入ったらぜひシェアも!!