配列を返すphpファイルをincludeして変数にセットすることで、配列の定義を外部ファイル化できることは結構知られていると思いますが、思いつきで無名関数を返すphpファイルをincludeして同じことをやってみたら、普通に動きました。
<?phpnamespace Acme;
use Acme\Util as U;
class Util{ public static function H($data, $default = null) { if (isset($data) && strcmp($data, '') !== 0) { return htmlspecialchars($data, ENT_QUOTES, 'UTF-8'); } return $default; } public static function is_number($data) { return (ctype_digit($data)); }
}
// 配列を返すファイルをincludeして変数にセットできる$items = include __DIR__ . DIRECTORY_SEPARATOR . 'include_function.items.php';
$orders = array( null, 'name:asc', 'name:desc', 'score:asc', 'score:desc',);
// 無名関数を返すファイルをincludeして変数にセットできる$sort = include __DIR__ . DIRECTORY_SEPARATOR . 'include_function.sort.php';
?><!DOCTYPE html><html><head><meta charset="utf-8" /><style type="text/css">body {font-family:monospace;}table {border-collapse:collapse;border-spacing:0px;width:20em;margin:10px;}caption {background-color:#336;color:#fff;border:inset 2px #669;padding:3px;}th, td {padding:3px;border:solid 1px #999;}tr.row1 td {background-color:#eee;color:#333;}tr.row2 td {background-color:#ddd;color:#333;}td.number {text-align:right;}</style><title>無名関数をincludeしてみるサンプル</title></head><body>
<?php foreach ($orders as $order) : ?><table> <caption><?=U::H((!isset($order)) ? 'no-order' : sprintf('order by %s', $order))?></caption> <thead> <th>name</th> <th>score</th> </thead> <tbody><?php $sort($items, $order); ?><?php foreach ($items as $i => $item) : ?> <tr class="<?= ($i % 2 === 0) ? 'row1' : 'row2' ?>"> <td><?=U::H($item['name'])?></td> <td class="number"><?=U::H(number_format($item['score']))?></td> </tr><?php endforeach ?> </tbody></table><?php endforeach ?>
</body></html>呼び出し元スクリプトです。
配列を定義しているファイルと、配列のソートを行う無名関数を定義しているファイルをincludeして、それぞれ動作させています。
<?phpreturn array( array('name' => 'Abe' , 'score' => 800), array('name' => 'Oda' , 'score' => 1000), array('name' => 'Hosokawa', 'score' => 600),);PHP5.4からは Short syntax for arrays が導入されるので、設定ファイル等でこの手法が流行るかもしれないとは思っていましたが…。
<?phpnamespace Acme\Func;
use Acme\Util as U;
class AssertCallback{ public static function output($file, $line, $code) { // include元に定義されているクラスはオートロードに関係なく利用できる echo U::H(sprintf('Assertion Failed: at %s[%d]', $file, $line)); }}
// 配列をソートする無名関数return function(array &$arr, $order) { if (!isset($arr[0]) || !isset($order)) { return $arr; } $key = $order; $asc = true; if (false !== ($pos = strpos($order, ':'))) { $key = substr($order, 0, $pos); $asc = (strcmp('asc', substr($order, $pos + 1)) === 0); } if (!array_key_exists($key, $arr[0])) { throw new \RuntimeException('Invalid key is specified.'); } usort($arr, function($row1, $row2) use ($key, $asc) { return ($asc) ? strnatcasecmp($row1[$key], $row2[$key]) : strnatcasecmp($row2[$key], $row1[$key]); });
assert_options(ASSERT_ACTIVE, 1); assert_options(ASSERT_WARNING, 0); assert_options(ASSERT_QUIET_EVAL, 1); // 関数のスコープ外に定義されているクラスも利用できる assert_options(ASSERT_CALLBACK, array('Acme\Func\AssertCallback', 'output')); assert(U::is_number($arr[0]['score'])); assert(U::is_number($arr[0]['name']));
return $arr;};実は無名関数を外部ファイルに定義することもできたんです。
無駄に読みづらくなるだけかもしれませんが、呼び出し元に定義されているクラスを利用することもできます。
名前空間を使えば、SilexのようなURLに無名関数をマッピングするフレームワークで、無名関数で扱うクラスを同一ファイルに定義、共通処理の実装はtraitで外部に定義するような手法にも使えるかな?
実用性は微妙かもしれませんが、こんなこともできるということで。
動作サンプルはこちらです。
http://k-holy.sakura.ne.jp/example/include_function.php







