Ginq はPHPの配列やイテレータを統一的に(そのうえ楽しく!)操作するための DSL です。
Ginq は LINQ to Object にインスパイアされましたが、クローンではありません。PHPの配列やイテレータの事情にできるだけ寄り添ってデザインされています。
Ginq の多くの機能は、その結果を実際に取り出すまで処理を実行しません。この 遅延実行 という性質は、さまざまなメリットをもたらしてくれます。
require_once('Ginq.php');
Ginqをインポートします。
$xs = Ginq::from(array(1,2,3,4,5,6,7,8,9,10))
->where(function($x) { return $x % 2 != 0; })
->select(function($x) { return $x * $x; })
;
Ginqにデータを渡して、クエリを組み立てます。 ここでは配列から偶数の要素だけを抽出して、されにそれを2乗しています。
この段階ではまだ Ginq は何もしません。 「必要な結果は、元の配列を選択(where)・射影(select)したものである」 、ということをGinqに伝えただけです。
実際に Ginq を駆動して結果を得るために、foreach
で Ginq を反復してみます。
foreach ($xs in $x) { echo "$x "; }
1 9 25 49 81
欲しい結果が得られました!
今度はtoList()
を使って配列を得ましょう。
$xs->toList();
array(1,9,25,49,81);
Ginq には、ここで紹介した select()
、where()
以外にも、join()
orderBy()
groupBy()
のような、SQLでお馴染みの機能も備わっています。
Ginq のほとんどのメソッドは、引数にクロージャをとります。
クロージャと聞くと、使いなれない人はちょっと怯んでしまうかもしれませんが、実のところまったく難しくありません。Ginqが要求するクロージャのほとんどは 「述語」 「セレクタ」 「結合セレクタ」 のたったの3種類に分けられ、すぐに覚えられます!
where()
のような 選択 を行うメソッドに渡すクロージャを、述語(predicate)いいます。述語は要素のキーと値のペアをとり、条件を満たすかどうかを真理値で返す次のようなクロージャです。
function ($v, [$k]) { return $v % 2 == 0; }
このクロージャをwhere()
に渡すと、クロージャの結果がTrue
となるような要素、つまり偶数だけを選んで返してくれます。
もしもキーに関心がないなら、第2引数を省略しても問題ありません。
select()
のような 射影 を行うメソッドに渡す関数を、セレクタ といいます。セレクタは要素のキーと値をのペアをとり、そこから新しい値(場面によってはキー)を作って返します。
function ($v, [$k]) { return $v * $v ; }
このクロージャをselect()
に渡すと、元の要素の値を2乗した並びが得られます。
また、射影という基本的な用途以外にも、groupBy()
ではグループ化のキーを、orderBy()
では並び替えのキーを指定するために使われます。
結合セレクタ は左右2つの要素を1つにまとめるセレクタの一種で、join()
や zip()
などで使われます。
function ($v0, $v1, [$k0, $k1]) { return array($v0, $v1) ; }
左右2つの値と左右2つのキー、合計4つの引数をとり、それを使って新しい値(あるいはキー)を作って返します。
もちろん、関心のない引数は省略しても大丈夫ですよ;-)
さて、2つの並びを要素ごとに綴じ合わせる、zip()
の例を見てみましょう。
$foods = array("お肉", "パスタ", "サラダ");
$spices = array("タイム", "バジル", "ディル");
$xs = Ginq::from($foods)
->zip($spices, function($f, $s) {
return "$fに$s!";
})
;
foreach ($xs in $x) { echo "$x\n"; }
お肉にタイム!
パスタにバジル!
サラダにティル!
セレクタ にかぎり、クロージャのかわりに文字列を渡すことができます。
Ginq::from($xs)->select('[key].property');
は、
Ginq::from($xs)->select(
function ($v, $k) { return $v['key']->property; }
);
と同じ意味をもちます。 これはSymfonyのプロパディアクセスの記法に準じます。
http://symfony.com/doc/current/components/property_access/index.html