これは、まず、オブジェクト指向スタイルで動作します(PHPですぐに使用できるのは非常に不便です)。 変更不可能なコレクション、オプション値(オプション値)の助けを借りたNPE(Null Pointer Exception)に対する保護、マップ内の手がかりの値(スカラーだけでなく)はすべてです。
設置
Composerからライブラリをインストールするのは簡単です... gitサブモジュールとして接続する方法:)
{ "require": { "alexeyshockov/colada": "dev-master" } }
$ git submodule add git://github.com/alexeyshockov/colada.git vendor/colada
コレクション
インストール後にColadaを使用する方法は? いくつかのオプションがありますが、その中で最も簡単なものは、通常の配列からコレクションを作成することです。ほとんどの場合、すでに使用可能であり、いくつかの変更を加える必要があります。
$counts = to_collection(array(2, 3, 50, 36)); $users = to_set(array('label1', 'label2', 'label3'));
必要な要素がすべて揃っている場合は、自分でコレクションを作成することもできます。
$counts = collection(2, 3, 50, 36); $users = set('label1', 'label2', 'label3');
標準配列()とほぼ同じ!
mapBy()、acceptBy()/ rejectBy()、foldBy()
コレクションの操作の機能的なスタイルの適切な説明は、「 forループの何が問題になっていますか? 」 という記事で既に十分に説明されています。 「。 Coladaマップでは、accept / rejectおよびfoldは、コレクション(Underscore.js、Scalaコレクションなど)を操作するための他のすべてのライブラリとまったく同じ意味を持ちます。
例を考えてみましょう:
$saleCount = $users ->acceptBy(x()->isActive()) ->mapBy(x()->getSales()) ->foldBy(function($count, $posts) { return $count + count($posts); }, 0);
上記のコードがそれ自体を語ってくれることを願っていますが、その意味は読みながら明確になっていますが、...を除いてどのようなx()ですか?
x()
Scalaまたは同様の言語でのプログラミングの経験があり、クロージャーの操作が最初は可能な限り便利になった人にとっては、これはおなじみのように思えるかもしれません。
Scala:
val emails = users.map(x.getEmail());
PHP(コラーダ):
$emails = $users->mapBy(x()->getEmail());
PHPでは、クロージャの操作はScala自体よりも少し冗長です。 ただし、ほとんどの場合、コレクション内のオブジェクトでゲッターを呼び出すだけでよい場合、上記のようにすべてを単純化できます。
x()は、コレクションの将来の要素です。 これを使用することは、単純なクロージャーと同等です。
$emails = $users->mapBy(function($user) { return $user->getEmail() });
あなたはまだ小さなものごとに閉鎖を書いていますか? それから私たちはあなたに行きます! ;)
橋(別名マップ)
コレクションが要素の単なるコレクションである場合、ハッシュはキー/値のペアであり、私たちも毎日遭遇します。 通常のコレクションと同様に、ハッシュを作成できます
$users = to_map(array('managers' => array(1, 3), 'users' => array(2, 3, 4)));
使い慣れたmapBy()およびacceptBy()/ rejectBy()、およびその他の便利で便利なメソッドmapElementsBy()、flip()、pick()を使用して、オブジェクト指向スタイルで操作します。
ある人は、1つのコードリストが1000語よりも優れている場合があると言いました。
$usersByGroups = $users ->mapBy(x()->isActive()) ->groupBy(x()->getGroup()) ->mapElementsBy(x()->count()); foreach ($groups as $group) { echo 'Group "'$group->getName().'" contains '.$usersByGroups->get($group)->orElse(0).' users.'; echo "\n"; }
上記のコードでは、コレクションとハッシュの操作を簡素化する「シュガー」メソッドとは別に、Map :: get()はキーで値を返さないが、前に言及しなかったOptionクラスのラッパーオブジェクトを返す現在の瞬間。
オプション値
NULL値を導入したことで有名なAnthony Hoar irはかつて次のように語っています。
私はそれを10億ドルの間違いと呼んでいます。
NPE(Null Pointer Exception)に対する保護のトピックでは、多くの言葉が言われ、いくつかの解決策が考案されました。 それらの1つは、いわゆるオプション値の導入です。 一部の言語では、最初に存在します。Haskellでは、多分、Scalaでは、Optionです。 Google Guava for JavaのOptionalなど、他の言語用のライブラリがあります。
Coladaのオプションの値は、Scalaの対応する値と非常に似ています。 値の存在を意味するものもあれば、存在しないことを意味するものもあります。 使用中、オプションの値はコレクションに非常に似ています(単純化すると、1つまたは0個の要素のコレクションが返されると考えるかもしれません)。
echo ": "; echo $user->getCity()->mapBy(x()->getName())->orElse('-');
上記の例は、ドメインモデルのクラスにオプション値を適用する方法を示しています。 この場合、ユーザーの都市で作業するとき、それが満たされていない可能性があることを決して忘れません。 同様に、リクエストされたキーがこのハッシュにまったく存在しないことを決して忘れません。
見えないようにする
キーがハッシュに存在することが確実な場合、または他の何らかの理由でオプション値と通信したくない場合は、常にapply()メソッドを使用できます。これは、get()とは異なり、ラッパーなしで要素を返します。
また、要素が表示されなかった場合に例外をキャッチします。
foreach ($groups as $group) { echo 'Group "'$group->getName().'" contains '.$usersByGroups->apply($group).' users.'; echo "\n"; }
また、要素が表示されなかった場合に例外をキャッチします。
オプションの値の使用はかなり広範なトピックであり、その詳細な説明は別の記事の場合です。
パフォーマンスとメモリ使用量
高性能とメモリの最適な使用はもともと主要な目標ではありませんでした-使いやすさが最前線に置かれました。 ほとんどの場合、作業は小さなコレクションで行われるため、パフォーマンスの違いは目立ちません。
それにもかかわらず、私の意見では、この状況でさえ、結果は私にとってかなりのものでした。 SplFixedArrayを使用してコレクションを実装することにより、メモリ使用量が通常の配列と比較してさらに少なくなります。
100,000個の要素のコレクションの例としてのメモリ使用量
$ ./shell.sh // Call use_colada() function to benefit from all shortcuts ;) Interactive shell php > use_colada(); php > vd(memory_get_usage(), memory_get_peak_usage()); int(374736) int(383040) php > $nums = Collections::range(1, 100000); php > vd(memory_get_usage(), memory_get_peak_usage()); int(3575236) int(3581604) php > $nums = range(1, 100000); php > vd(memory_get_usage(), memory_get_peak_usage()); int(8099280) int(8105996)
作業速度に関しては、奇跡はありません-使いやすさを払う必要があります...検索時の要素の拡張比較(コレクション::含む()、マップ:: get()...)、および残りのバンズは額に実装され、当然、組み込みの対応物よりも遅くなります。 しかし、あなたの助けを含めて、すべてがより良く変わる可能性があります;)
しかし、ここにはすでに最適化されたものがあり、使用することを恐れずに覚えておく必要があるものがあります-mapBy()およびacceptBy()/ rejectBy()からの変換チェーンはデフォルトでは怠zyです! これは、関数型言語でプログラミングの経験がある人には非常によく知られており、例で明確に見ることができます。
$emails = $users ->acceptBy(x()->isActive()) ->mapBy(x()->getEmail());
このコードでは、ユーザーコレクションを通過するのは2つではなく1つだけです。 より正確には、上記のコードではまったく存在しません。 パッセージは、新しいコレクションの要素が本当に必要な場合にのみ完了します。
$emails = $users ->acceptBy(x()->isActive()) ->mapBy(x()->getEmail()); foreach ($emails as $email) { echo $email; }
「競合他社」
Scala言語(Scala Collections)とUnderscore.jsライブラリに触発されて、最初からこのようなものがPHPに存在しないとは想像できませんでした。 しかし、見た目が悪かったのか、実際に開発時にPHPで同じ利便性を提供するソリューションはありませんでした。
それにもかかわらず、いくつかの開発があり、誰もが比較を行って適切なツールを選択できるように、ここにそれらを持ち込みたいと思います。
それで、すでにインターネット上にあるもの:
- Doctrine Commonのコレクションは、 コレクションを操作するための補助ラッパーであり、Doctrineプロジェクトで内部使用するために開発されており、それら以外では特に知られていません。 実際には、追加のプロパティ(不変、非スカラーキーなど)を使用せずに、スタートアップ配列に単純なオブジェクト指向のラッパーを提供します。
- Underscore.phpは、PHPのUnderscore.jsの直接の類似物であり、私の意見では、言語の詳細を実質的に考慮せずに作成されました。
- Rmk-Framewrok(Habréの説明付き)-同胞からの注目すべき開発であり、主にデフォルトではPHPに実装されていないさまざまなデータ構造の提供に焦点を当てています。 このライブラリは当初、Coladaとは異なる目的を持っているため、ユーザビリティの主観的な比較では失います。
結論として
便利な(おそらく)リンク:
- github.com/alexeyshockov/colada-ソースコード(プルリクエストは大歓迎です)
- alexeyshockov.github.com/colada-APIドキュメント
PS
一見、これはすべて無意味に思えるかもしれませんし、コードは確かにPHPで書かれているわけではありません。 誰かがまだこれに興味があるなら、私が完全に説明していないことを明らかにできる建設的なコメントを楽しみにしています。