フィルタリングは『ろ過』のことで『データを1回通して見る』『データを選別する』こと。ある条件で排除することが多いですね?
PHPもフィルタリングができます。array_filter()です。
array_filter()の使い方をサンプルプログラムで分かりやすく説明します。
フィルタリングとは?
Webではよく『フィルタリング』という言葉を聞きますよね?
URLフィルタリング
IPフィルタリング
etc...
これらは、転送データを監視してある条件のものを排除します。
フィルタリングは直訳すると『ろ過』で、そのままでは『1回データを通して見る』なんですが、そこからデータを選別する・分類するという大きな意味になり、どちらかといえば特定のデータを消す・排除することが多いです。
『データを通して見る』から『監視』の意味で使うこともあります。
コールバック関数とはなにか?
コールバック関数は、
関数の引数で渡す関数
のこと。
array_filter($array, function($value) {
return false;
});
ここでは無名関数を使ってます。
無名関数は名前がない関数で、変数に入れられる関数のこと。
関数は、
この処理をして結果をちょうだい。
と処理を任せてしまうことですが、コールバック関数は、
この関数を使って処理してよ。最終結果だけちょうだい。
と関数(コールバック)は指定しますが、処理の実行と結果の使い道はコールバック関数を引き受けた関数が行ないます。
<?php
/**
* callback function
*/
function cb_sample() {
return "hello";
}
/**
* function
*/
function sub_sample( $cb ) {
return $cb() . " world!";
}
echo sub_sample( 'cb_sample' );
hello world!
PHPのフィルタリングでは、
削除するデータの条件を決める
仕事をコールバック関数がします。
コールバック関数はフィルタリングのルールを書く。
array_filter()のコールバック関数は、boolean(true, false)を返さないといけません。
戻り値 | データはどうなる? |
---|---|
false | 削除 |
true | 残す |
フィルタリングしてみよう!
いろんなフィルタリングをしてみましょう。
基本的なことだけ行ないます。あとは応用していろいろ試してみてください。
偶数・奇数
偶数をはじくフィルタリング、奇数をはじくフィルタリングをします。
サンプルコードです。
<?php
$array = [1,2,3,4,5,6,7,8,9,10];
/**
* odd callback
*/
function cb_odd($value) {
return $value & 1;
}
/**
* even callback
*/
function cb_even($value) {
return !($value & 1);
}
var_dump(array_filter($array, 'cb_odd'));
var_dump(array_filter($array, 'cb_even'));
array(5) {
[0]=>
int(1)
[2]=>
int(3)
[4]=>
int(5)
[6]=>
int(7)
[8]=>
int(9)
}
array(5) {
[1]=>
int(2)
[3]=>
int(4)
[5]=>
int(6)
[7]=>
int(8)
[9]=>
int(10)
}
いろいろな計算式をコールバック関数に入れれば、計算結果でフィルタリングできます。
文字列をフィルタリングする
'abc'が含まれる文字列をフィルタリングするサンプルです。
'abc'が含むものを抽出・削除してみましょう。
<?php
$array = ['abc','bcd','zzzabc','abczzz', 'zzabczz', 'aabbcc',];
/**
* take out callback
*/
function cb_take_out($value) {
if(strpos($value, 'abc') === false) {
return false;
} else {
return true;
}
}
/**
* delete callback
*/
function cb_delete($value) {
if(strpos($value, 'abc') === false) {
return true;
} else {
return false;
}
}
var_dump(array_filter($array, 'cb_take_out'));
var_dump(array_filter($array, 'cb_delete'));
array(4) {
[0]=>
string(3) "abc"
[2]=>
string(6) "zzzabc"
[3]=>
string(6) "abczzz"
[4]=>
string(7) "zzabczz"
}
array(2) {
[1]=>
string(3) "bcd"
[5]=>
string(6) "aabbcc"
}
正規表現を使った文字列検索をすればいろんなことができそうですね?
空要素を削除する
array_filterには、空要素の削除が用意されています。
コールバックなしで実行
します。
<?php
$array = ['abc','','0','1',0, 1,[1,2,3],[],null];
var_dump(array_filter($array));
array(4) {
[0]=>
string(3) "abc"
[3]=>
string(1) "1"
[5]=>
int(1)
[6]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
}
削除の条件は、empty()と同じ。
この処理は完ぺきではないので注意が必要です。
'0'
0
が消えます。また、コールバック関数にstrlen()を使う方法をよく見ますがこれも問題があります。
このあたりはまとめたのでそちらを見て下さい。
クラスをフィルタリングする
特定のクラスを抽出・削除します。
<?php
class TEST1 {}
class Test1_1 extends TEST1 {}
class Test1_2 extends TEST1 {}
class Test1_3 extends TEST1 {}
class TEST2 {}
class TEST3 {}
$array = [new TEST1(),new TEST1_1(),new TEST1_2(),new TEST1_3(), new TEST2(), new TEST3(),];
/**
* take out callback
*/
function cb_take_out($value) {
return ! ($value instanceof TEST1);
}
/**
* delete callback
*/
function cb_delete($value) {
return $value instanceof TEST1;
}
var_dump(array_filter($array, 'cb_take_out'));
var_dump(array_filter($array, 'cb_delete'));
array(2) {
[4]=>
object(TEST2)#5 (0) {
}
[5]=>
object(TEST3)#6 (0) {
}
}
array(4) {
[0]=>
object(TEST1)#1 (0) {
}
[1]=>
object(Test1_1)#2 (0) {
}
[2]=>
object(Test1_2)#3 (0) {
}
[3]=>
object(Test1_3)#4 (0) {
}
}
サンプルのように親クラスを指定して、子クラスもろともフィルタリングできます。
もちろん子クラスだけもできます。くわしくは公式ドキュメントを見てください。
連想配列のフィルタリング
ここまでのフィルタリングは、連想配列をパラメータにわたしても同じ結果になります。
こんどは、連想配列のキーを使う方法をご紹介します。
array_filter()の第3パラメータ(flag)を指定するだけです。
flag | callbackの引数 |
---|---|
ARRAY_FILTER_USE_KEY | キーだけ |
ARRAY_FILTER_USE_BOTH | キー,値 |
なし | 値だけ |
<?php
$array = ['a' => 1,'b' => 2,'c' => 3,'d' => 1,];
/**
* take out callback (key only)
*/
function cb_take_out_key($key) {
if ( $key === 'a' ) {
return true;
} else {
return false;
}
}
/**
* delete callback (key only)
*/
function cb_delete_key($key) {
if ( $key === 'a' ) {
return false;
} else {
return true;
}
}
/**
* take out callback (value, key)
*/
function cb_take_out_both($value, $key) {
if ( $value === 1 && $key === 'd' ) {
return true;
} else {
return false;
}
}
/**
* delete callback (value, key)
*/
function cb_delete_both($value, $key) {
if ( $value === 1 && $key === 'd' ) {
return false;
} else {
return true;
}
}
var_dump(array_filter($array, 'cb_take_out_key', ARRAY_FILTER_USE_KEY ));
var_dump(array_filter($array, 'cb_delete_key', ARRAY_FILTER_USE_KEY ));
var_dump(array_filter($array, 'cb_take_out_both', ARRAY_FILTER_USE_BOTH ));
var_dump(array_filter($array, 'cb_delete_both', ARRAY_FILTER_USE_BOTH ));
array(1) {
["a"]=>
int(1)
}
array(3) {
["b"]=>
int(2)
["c"]=>
int(3)
["d"]=>
int(1)
}
array(1) {
["d"]=>
int(1)
}
array(3) {
["a"]=>
int(1)
["b"]=>
int(2)
["c"]=>
int(3)
}
コールバックのパラメータの順番は決まっています。
(値, キー)
まちがえないようにしましょう。
まとめ
array_filter()は、コールバックに計算式や文字列検索、正規表現を使うとたくさんのフィルタリングができます。
ただし、問題点もあります。
空要素削除が危ない。
多次元配列に対応できない。
このへんに注意しながら使わないといけません。