ヤマザキ春のパン祭りが再開されたことを記念して、
こちらは春のコールバック祭りを開催したいと思います。

コールバックって何?
私が思うに「コールバック」という名のとおり、その関数を呼べば、決まった返し方をするわけね。(多分)
コールすれば、バックしてくれるみたいな ね。。。

決まった返し方をすることが事前に分かってることで、機能を載せ換える感じにできるんでしょうかね。

ではコールバックを引数に指定できる代表的な関数を使っていきたいと思います。


と、その前に配列に関することを少々

PHPでいう配列は「キー」と「値」のペアが連続してつながってる感じになります。
「キー」と「値」の1ペアを、1要素とします。
つまり要素が1つもなければ、空っぽの配列です。
ただし、空っぽの配列と言えども未定義とは別物なので、型は配列型です。

$array = array(1, 'foo'); // 要素数が2の配列
$array = array();         // 空っぽの配列
unset($array);            // 未定義の変数(型を持たない状態)
型を持たないということは、文字列でも数値でも配列でもない未定義状態ということです。
型を持たない状態の変数はデフォルト設定の「error_reporting(E_ALL & ~E_NOTICE)」では何も起こらないですが、
「error_reporting(E_ALL)」設定時にNotice表示されます。
そんな時はisset()またはempty()という言語構造を使ってチェックする必要があります。

配列の要素数はcount()関数を使って取得できます。
count()のエイリアス関数であるsizeof()を使っても同じことです。

PHPには配列が2種類あります。
配列なので型は同じ配列型ですが、「キー」が数字の0(ゼロ)から始まる数字添え字の配列と、
文字列をキーとする連想配列の2種類になります。
前者はいわゆる配列で、単に「配列」という場合は数字添え字のものになるでしょう。
$array[0] = 'foo';
$array[1] = 'bar';
一方、後者の連想配列はハッシュとも呼ばれ、キーに文字列を使えることからキーと値のペアに関連性を持たせる使い方をします。
$hash['1999年7の月'] = '恐怖の大王がドタキャンした';
$hash['2011年4の月'] = 'ヤマザキ春のパン祭りが再開される';


以上を踏まえて、春のコールバック祭りのはじまりはじまりぃ~


■array_filter()関数
array array_filter(array $input [, callback $callback])

配列の要素をフィルタリングすることができます。

配列にフィルターをかけ、通り抜けた配列を返します。
このフィルター部分にコールバック関数を使います。

$input = array(1, 3, 5, 6, 4, 2);
$output = array_filter($input, function($val){ return $val < 4;});
print_r($output); // Array ( [0] => 1 [1] => 3 [5] => 2 )


ちょいと数字キーが飛び飛びの配列になってしまいましたので整えましょ
$output = array_merge($output);
print_r($output); // Array ( [0] => 1 [1] => 3 [2] => 2 )


コールバック関数にPHP5.3.0以降からしか使えない無名関数(クロージャ)を使ってしまいましたので別の書き方をば
$output = array_filter($input, create_function('$val', 'return $val < 4;'));


そんなには変更ないッスね

要は配列の「値」を引数にとり、真偽値を返す関数を渡せばいいわけですね。
コールバック内から「真」を返した要素のみを集約する感じですね。


コールバックをとっかえひっかえすれば、いろんなフィルターの出来上がりです。

// "foo"値を除去するフィルター
function($val){ return $val !== 'foo'; }
// 奇数(つまり2で割り切れない)を除去するフィルター
function($val){ return $val % 2 === 0; }
// 偶数(2で割り切れる)を除去するフィルター
function($val){ return $val % 2 === 1; }



■array_map()関数
array array_map(callback $callback, array $arr1 [, array $...])

配列の要素にコールバック関数を適用する

これも先ほどのarray_filter()関数と同様、配列を返します。
但しフィルターは値そのものをいじらずに不要な要素を取り除く系ですが、こちらは全要素をいじった結果の全要素を取得する系です。
つまりarray_map()関数では「渡した配列要素数=返される要素数」になります。

特徴的なのは、配列数を可変で受け入れられるようにコールバックを第1引数に指定するようになっていることです。

$input = array(1, 3, 5, 6, 4, 2);
$output = array_map(function($val){ return 'foo';}, $input);
echo implode(':', $output); // "foo:foo:foo:foo:foo:foo"


コールバックが受け取った値を無視してすべて'foo'を返したら当然のごとく全要素が'foo'になってしまいます。
なので普通は値を利用した成形をします。
$input = array(1, 3, 5, 6, 4, 2);
$output = array_map(function($val){ return '[' . $val . ']';}, $input);
echo implode(':', $output); // "[1]:[3]:[5]:[6]:[4]:[2]"


実践的に使う場合は、もっと制御構造を使ってより複雑なマッピングを施すことになると思います。

<?php

function mapping($val) {

    switch ($val) {

      case  1:
          return "[" . $val . "]";
      case  2:
          return "{" . $val . "}";
      case  3:
          return "#" . $val . "#";
      default:
          return "(" . $val . ")";
    }
}

$input  = array(1, 3, 5, 6, 4, 2);
$output = array_map("mapping", $input);



■array_walk()関数
bool array_walk(array &$array, callback $funcname [, mixed $userdata])

配列のすべての要素にユーザ関数を適用する

今度は配列を返すわけではないですが、第1引数に渡す配列がリファレンス渡しになるのでコールバックの引数もリファレンス渡しすることで、いじった結果を取得することはできます。
$input = array(1, 3, 5, 6, 4, 2);
array_walk($input, function(&$val){ $val = 'foo';});
echo implode(':', $input); // "foo:foo:foo:foo:foo:foo"

array_map()関数で書いたのと同じ挙動になりました。
でもこの使い方をするくらいならarray_map()関数を使った方がいいので、array_walk()関数が用意されてる意味とはなんなんでしょうか?

戻り値取得が不要なので、例えばコールバック内だけで処理を完結させる場合が思いつきます。

$input = array(1, 3, 5, 6, 4, 2);
array_walk($input, function($val){ echo "#{$val}#/";});

こんな感じでしょうか

あと違う点は、コールバックに2つの引数を渡すことができます。
つまりキーと値を渡せることから、単なる配列よりも連想配列で使うことになるでしょう。
$input = array('foo'=>'a1', 'bar'=>'b2', 'baz'=>'c3');
array_walk($input, function($val,$key){ echo "{$key}:{$val}/"; });

※コールバック引数は「値」「キー」の順番になります。(値のみの引数渡しもできるように)


■array_reduce()関数
mixed array_reduce(array $input, callback $function [, mixed $initial = NULL])

コールバック関数を用いて配列を普通の値に変更することにより、配列を再帰的に減らす

reduceは減らす、切り詰めるという意味

これもコールバックに引数を2つ渡す形になる。
が、これまでとは少し違って連想配列のキーと値の2つを渡してるわけではない。
$input = array(1, 3, 5, 6, 4, 2);
$result = array_reduce($input, function($v,$w){ return 'foo'; });
echo $result; // "foo"

上記の挙動を見るとわかるとおり、固定で"foo"を返し続けると最終的に取得する結果も同じものになる。
$input = array(1, 3, 5, 6, 4, 2);
$output = array_reduce($input, function($v,$w){ $v .= ':' . $w; return $v; });
echo $output; // ":1:3:5:6:4:2"

上記の挙動を見るとわかるように、コールバックの第1引数は結果として返す値保持用のもの。
第2引数は配列の値が順にセットされてくるようです。

つまりコールバック部分をもっとわかりやすく書き直すと以下のようになる。
function($result, $val){ $result .= ':' . $val; return $result; }

array_reduce()関数の戻り値がmixedとなっているので文字列以外にも返せるということになる。
// こうすれば数値を返すようになる。
function($result, $val){ $result *= $val; return $result; }

// こうすると配列を返すことになる。
function($result, $val){ $result[] = $val; return $result; }



■usort()関数
bool usort(array &$array, callback $cmp_function)

ユーザ定義の比較関数を使用して、配列を値でソートする

usort()関数の場合は配列の値のみで並び替えを行います。
なので連想配列に使うことはありません。

ソート系関数の仕様を見れば分かるとおり、第1引数に渡した配列変数そのものに並び替えが施されます。
なので戻り値を代入する必要はありません。
ソート系に渡すコールバックの場合は、引数が隣り合った2つの値で、戻り値は「-1」「0」「1」を返すことになります。

なのでコールバックはこんな感じになります。
function($a,$b){ if ($a == $b) return 0; return $a < $b ? -1 : 1; }


$array = array(1, 3, 5, 6, 4, 2);
usort($array, function($a,$b){
    if ($a == $b) return 0; return $a < $b ? -1 : 1;
});
echo implode(':', $array); // "1:2:3:4:5:6"

配列の値が文字列ならもちろんコールバックを載せ換える必要があります。
幸いにも文字列比較関数はビルトイン関数のstrcmp()を使えそうです。
$array = array("08", "02", "a5", "x8", "b2", "22");
usort($array, "strcmp");
echo implode(':', $array); // "02:08:22:a5:b2:x8"

でもこれって、既存のsort()関数と同じ挙動なのでもっとコールバックを複雑な比較のものに載せ換えられたときに初めて意味があるっちゅーことでしょうな。

なのでほとんどの一般的な比較だったら既存の関数で事足りるようです。
したがって、ケッタイな比較を行ってみます。
$array = array("08", "02", "a5", "x7", "b4", "20");
usort($array, function($a,$b){
   return substr_compare($a, substr($b, 1, 1), 1, 1);
});
echo implode(':', $array); // "20:02:b4:a5:x7:08"

上記は文字列の第2バイト文字でソートさせた例です。


■uksort()関数
bool uksort(array &$array, callback $cmp_function)

ユーザ定義の比較関数を用いて、キーで配列をソートする

こちらはusort()関数と違って、関数名にキーを表す "k" の文字が入っているように、連想配列のキーに基づいた並び替えを行います。
$array = array('09'=>'a', '59'=>'b', '21'=>'c', '00'=>'d');
uksort($array, "strcmp");
print_r($array); // Array ( [00] => d [09] => a [21] => c [59] => b )

これもやはり既存のksort()関数と挙動は同じになります。使う場合はもっと複雑なコールバック仕様になるでしょう。


■uasort()関数
bool uasort(array &$array, callback $cmp_function)

ユーザ定義の比較関数で配列をソートし、連想インデックスを保持する

こちらもやはりstrcmp()関数を比較に用いただけでは、既存のasort()関数と同じ挙動になります。
uasort($array, "strcmp") と asort() もまた、同じ挙動になります。