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

  • ---

    LINEで送る
  • -

    ブックマーク
  • -

    pocket
  • -

    rss
他言語サイト
en_US en_US
イラストACの画像をもとに加工しています。

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"
}

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

  • 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行弱の処理でおわりです。これだけの作業でバグになる可能性を消すことができます。

バグになったとしてもdelete_empty_array()をなおすだけで済みます。

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

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

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

tadtadya.com

_

SNSでも記事を配信しています。

コメント

    コメントを残す

    *

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

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