Posted on

array_filterの邪道?

まだまだ修行中です。最近は二度手間をできる限り抑えたいので
PHPのリファレンスを読み込んでみて、こんな関数既にあるんだなっていうのを見つけているところです。
しっかり覚えていなくても、頭の片隅に引っかかっていればいずれ使えるよな…という魂胆です。

そんな中でarray_filterの使い方がどうしても気になりました
http://php.net/manual/ja/function.array-filter.php

配列のキーや値を関数に通して、trueが返ってくるものだけを配列に詰め込んで返す、
使う関数は関数名を指定しても無名関数を渡してもいい、と。

ここで、手元のリファレンス書籍には「一次元配列のみに対応」と、
こちらのオンラインマニュアルには書いていない記述があったのがどうにも引っかかったんです。

「なぜ渡したらダメなのか、あるいはダメだったのか」

とりあえず、php5.4環境で渡してみてどうか調べてみました。

$order=array( 'Alice'=>array(
		'coffee'=>array(
			'milk'=>false,
			'sugar'=>true,
		),
	),
	'Bob'=>array(
		'coffee'=>array(
			'milk'=>true,
			'sugar'=>true,
		),
	),
	'Chalie'=>array(
		'coffee'=>array(
			'milk'=>true,
			'sugar'=>false,
		),
		'cake'=>array('chocolate')
	),
	'Deborah'=>array(
		'coffee'=>array(
			'milk'=>false,
			'sugar'=>false
		),
	),
	'Eve'=>array(
		'doughnut'=>array(
			'plain','strawberry'
		),
	),
	'Fred'=>null,
	'George'=>array(
		'coffee'=>array(
			'milk'=>true,
			'sugar'=>false
		)
	),
);

function order_filter($v){
	/* TODO:ここに検索条件を書く */
}

var_dump(array_filter($order,'order_filter'));

ここのorder_filter($v)をいくつか変えて出力を調べてみました。

//コーヒー注文
return isset($v['coffee']);

/* Output:
array (size=5)
  'Alice' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean false
          'sugar' => boolean true
  'Bob' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean true
          'sugar' => boolean true
  'Chalie' => 
    array (size=2)
      'coffee' => 
        array (size=2)
          'milk' => boolean true
          'sugar' => boolean false
      'cake' => 
        array (size=1)
          0 => string 'chocolate' (length=9)
  'Deborah' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean false
          'sugar' => boolean false
  'George' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean true
          'sugar' => boolean false
*/
//砂糖有りコーヒーまたはコーヒー注文無し
return (isset($v['coffee']['sugar'])&&$v['coffee']['sugar'])||empty($v['coffee']);

/* Output:
Notice:Undefined index: coffee in (file) on line 43 //43行目=上の条件を書いた行

array (size=4)
  'Alice' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean false
          'sugar' => boolean true
  'Bob' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean true
          'sugar' => boolean true
  'Eve' => 
    array (size=1)
      'doughnut' => 
        array (size=2)
          0 => string 'plain' (length=5)
          1 => string 'strawberry' (length=10)
  'Fred' => null
*/
//砂糖有りコーヒーまたはコーヒー注文無し 改
return (isset($v['coffee']['sugar'])&&$v['coffee']['sugar'])||empty($v['coffee']);

/* Output:
array (size=4)
  'Alice' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean false
          'sugar' => boolean true
  'Bob' => 
    array (size=1)
      'coffee' => 
        array (size=2)
          'milk' => boolean true
          'sugar' => boolean true
  'Eve' => 
    array (size=1)
      'doughnut' => 
        array (size=2)
          0 => string 'plain' (length=5)
          1 => string 'strawberry' (length=10)
  'Fred' => null
*/

結論としては、「キーの存在」を追加して調べる必要がある(ない場合noticeが出る)…みたいなところです。
この試行だけでは結局「なぜ渡したらダメなのか」という理由はわかりませんでした。
もっと未定義みたいな挙動が出てくるかと思ったら、そういうわけでもなく。
あるいは、バージョンが上がったことで渡せるようになったとか、そういうことなのかもしれないです。
(手元の書籍は5.1ぐらいに対応するよう書いていた9年以上前のものだからあり得る話)

可読性で言えば使わずにforeachループ回すのと五分五分、ってところかなと思います。
array_filterが何をしている関数かピンとこないと読みづらい、みたいな。

他の関数についても、気になったら実験を進めます。
それがリファレンスを頭の片隅に置くために役立つ気がしています。