私はMongoDbのような(http://docs.mongodb.org/manual/applications/read/#find、docs.mongodb.org/manual/reference/operators/)クエリ式オブジェクト評価関数の実装またはクラス。すべての高度な機能を網羅しているわけではなく、拡張可能なアーキテクチャを備えている必要があります。
MongoDBのようなクエリ式オブジェクトは、理解と使用が簡単で、クエリと検索対象のオブジェクトの両方が連想配列であるため、クリーンで自己説明的なコードを記述できます。
基本的に、php配列から情報を抽出するための便利な機能について話します。配列構造(arrayPath)を知っていると、複数のネストされたループを必要とせずに、多次元配列データに対して操作を実行できます。
MongoDbに慣れていない場合は、検索する特定の式オブジェクトと配列を確認してください。
簡単にするためにJSON文字列として記述しました。オブジェクトの内容は意味がなく、MongoDbクエリ構文を示しているだけです。
MongoDbのようなクエリ式オブジェクト
{
"name": "Mongo",
"type": "db",
"arch": {
"$in": [
"x86",
"x64"
]
},
"version": {
"$gte": 22
},
"released": {
"$or": {
"$lt": 2013,
"$gt": 2012
}
}
}
検索する配列
[
{
"name": "Mongo",
"type": "db",
"release": {
"arch": "x86",
"version": 22,
"year": 2012
}
},
{
"name": "Mongo",
"type": "db",
"release": {
"arch": "x64",
"version": 21,
"year": 2012
}
},
{
"name": "Mongo",
"type": "db",
"release": {
"arch": "x86",
"version": 23,
"year": 2013
}
}
]
Mongoのようなクエリ式を使用して検索
したがって、関数の助けを借りて、ターゲット配列に次のクエリを発行できるはずです。
$found=findLikeMongo($array, $queryExpr); //resulting in a $array[0] value;
//@return found array
Mongoのようなクエリ式を使用して配列パスを取得する
$arrayPath=getPathFromMongo($array, $queryExpr);// resulting in array("0")
//@return array path, represented as an array where entries are consecutive keys.
宿題
goingsner.net/articles/JsonPath/が私のニーズをカバーできる可能性があることがわかりました(Xpathのような式を使用しているため、完全に一致するわけではありません)。注意点は、正規表現と文字列の解析に大きく依存しているため、間違いなく遅くなります。配列のみ(JSONのような)の実装と比較してダウンしています。
また、ここで同様の質問を見つけました。@stackoverflowPHPで のMongoDBのようなJSONクエリの評価。結果として得られた答えは、ほとんどの場合回避するために使用されるいくつかのSPL関数を使用することでした。
作者が機能を思いついたのだろうか、彼は開発しようとしていた。可能性のあるarrayPath実装は、thereisamoduleforthat.com / content /dealing-deep-arrays-phpで見つかりました。したがって、この実装がないのは、ポインターに依存していることです。
私はそれがワンライナーの答えで些細な質問ではないことを知っています、それで私は自分のクラスの実際の開発を始める前にそれを尋ねている理由です。
アーキテクチャのヒント、関連または類似のコードに感謝します。これは、php"if..else"式をその場で構築するための良い実践例かもしれません。強調されたテキスト
非SPLバージョンを作成する方法は?
@Babaは、SPLを使用して作成された優れたクラスを提供しました。SPLなしでこのコードを書き直す方法はどうだろうか。
これには2つの理由があります
- クラスを複数回呼び出すと、関数のオーバーヘッドが発生します。これにより、生のPHPでクラスを書き直すことを回避できます。
- SPLが利用できない生のJavascriptに簡単に移植できるため、両方のプラットフォームでのコードのメンテナンスが容易になります。
結果
作成されたArrayQueryクラスはGithubで公開されています。リポジトリをチェックアウトして、更新を確認することを検討してください。
SPL、生のPHPバージョンおよびChequer2FORPプロファイラー出力
簡単に-
- 生のPHPバージョンはSPLバージョンよりも10倍高速に実行され、20%少ないメモリを消費します。
- Chequer2クラスのパフォーマンスはPHPSPLクラスより40%遅く、生のPHPバージョンよりもほぼ20倍遅くなります。
- MongoDbは最速です(生のPHP実装よりも10倍高速で、消費するメモリも5倍少なくなります)。MongoDbとの対話を避けたいことが確実でない限り、これらのクラスを使用しないでください。
MongoDbバージョン
SPLバージョン
生のPHP(最新のArrayQueryクラス)バージョン
Chequer2バージョン
MongoDbリファレンステストプロファイリングコード
$m = new MongoClient(); // connect
$db = $m->testmongo; // select a database
$collection = $db->data;
$loops=100;
for ($i=0; $i<$loops; $i++) {
$d = $collection->find(array("release.year" => 2013));
}
print_r( iterator_to_array($d) );
SPLクラスプロファイリングコードを使用したPHP
include('data.php');
include('phpmongo-spl.php');
$s = new ArrayCollection($array, array("release.year" => 2013),false);
$loops=100;
for ($i=0; $i<$loops; $i++) {
$d = $s->parse();
}
print_r( $d );
SPLクラスの parse ()関数は、実行後に値を返すようにわずかに変更されています。式を受け入れるように変更することもできますが、式は毎回再評価されるため、プロファイリングの目的には必須ではありません。
生のPHP(最新のArrayQueryクラス)プロファイリングコード
include('data.php');
include('phpmongo-raw.php');
$s = new ArrayStandard($array);
$loops=100;
for ($i=0; $i<$loops; $i++) {
$d = $s->find(array("release.year" => 2013));
}
print_r( $d );
chequer2PHPプロファイリングコード
<?php
include('data.php');
include('../chequer2/Chequer.php');
$query=array("release.year" => 2013);
$loops=100;
for ($i=0; $i<$loops; $i++) {
$result=Chequer::shorthand('(.release.year > 2012) ? (.) : NULL')
->walk($array);
}
print_r($result);
?>
使用されたデータ(彼の回答で提供された@babaと同じ)
$json = '[{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x86",
"version":22,
"year":2012
}
},
{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x64",
"version":21,
"year":2012
}
},
{
"name":"Mongo",
"type":"db",
"release":{
"arch":"x86",
"version":23,
"year":2013
}
},
{
"key":"Diffrent",
"value":"cool",
"children":{
"tech":"json",
"lang":"php",
"year":2013
}
}
]';
$array = json_decode($json, true);
forp-uiのわずかに変更されたサンプルUIローダー(?profile = FILE_TO_PROFILEで呼び出されます)
<!doctype html>
<html>
<head>
<style>
body {margin : 0px}
</style>
</head>
<body>
<div class="forp"></div>
<?php
register_shutdown_function(
function() {
// next code can be append to PHP scripts in dev mode
?>
<script src="../forp-ui/js/forp.min.js"></script>
<script>
(function(f) {
f.find(".forp")
.each(
function(el) {
el.css('margin:50px;height:300px;border:1px solid #333');
}
)
.forp({
stack : <?php echo json_encode(forp_dump()); ?>,
//mode : "fixed"
})
})(forp);
</script>
<?php
}
);
// start forp
forp_start();
// our PHP script to profile
include($_GET['profile']);
// stop forp
forp_end();
?>
</body>
</html>