はじめに
PHPでMongoDBのようなJSONクエリを評価することで、必要なすべての情報が得られたと思います。必要なのは、ソリューションを創造的にすることであり、あなたはあなたが望むものを達成します
アレイ
次のjson
があると仮定しましょう 配列に変換
$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);
例1
key
かどうかを確認します -Different
echo new ArrayCollection($array, array("key" => "Diffrent"));
出力
{"3":{"key":"Diffrent","value":"cool","children":{"tech":"json","lang":"php","year":2013}}}
例2 release year
かどうかを確認します 2013
です
echo new ArrayCollection($array, array("release.year" => 2013));
出力
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
例3
Year
の場所を数える 2012
です
$c = new ArrayCollection($array, array("release.year" => 2012));
echo count($c); // output 2
例4
version
を確認したい例から見てみましょう grater than 22
$c = new ArrayCollection($array, array("release.version" => array('$gt'=>22)));
echo $c;
出力
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
例5
release.arch
かどうかを確認します 値はIN
です [x86,x100]
などのセット (例)
$c = new ArrayCollection($array, array("release.arch" => array('$in'=>array("x86","x100"))));
foreach($c as $var)
{
print_r($var);
}
出力
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 22
[year] => 2012
)
)
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 23
[year] => 2013
)
)
例6
Callableの使用
$year = 2013;
$expression = array("release.year" => array('$func' => function ($value) use($year) {
return $value === 2013;
}));
$c = new ArrayCollection($array, $expression);
foreach ( $c as $var ) {
print_r($var);
}
出力
Array
(
[name] => Mongo
[type] => db
[release] => Array
(
[arch] => x86
[version] => 23
[year] => 2013
)
)
例7
独自の式名を登録する
$c = new ArrayCollection($array, array("release.year" => array('$baba' => 3)), false);
$c->register('$baba', function ($a, $b) {
return substr($a, - 1) == $b;
});
$c->parse();
echo $c;
出力
{"2":{"name":"Mongo","type":"db","release":{"arch":"x86","version":23,"year":2013}}}
使用クラス
class ArrayCollection implements IteratorAggregate, Countable, JsonSerializable {
private $array;
private $found = array();
private $log;
private $expression;
private $register;
function __construct(array $array, array $expression, $parse = true) {
$this->array = $array;
$this->expression = $expression;
$this->registerDefault();
$parse === true and $this->parse();
}
public function __toString() {
return $this->jsonSerialize();
}
public function jsonSerialize() {
return json_encode($this->found);
}
public function getIterator() {
return new ArrayIterator($this->found);
}
public function count() {
return count($this->found);
}
public function getLog() {
return $this->log;
}
public function register($offset, $value) {
if (strpos($offset, '$') !== 0)
throw new InvalidArgumentException('Expresiion name must always start with "$" sign');
if (isset($this->register[$offset]))
throw new InvalidArgumentException(sprintf('Expression %s already registred .. Please unregister It first'));
if (! is_callable($value)) {
throw new InvalidArgumentException(sprintf('Only callable value can be registred'));
}
$this->register[$offset] = $value;
}
public function unRegister($offset) {
unset($this->register[$offset]);
}
public function parse() {
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($this->array));
foreach ( $it as $k => $items ) {
if ($this->evaluate($this->getPath($it), $items)) {
$this->found[$it->getSubIterator(0)->key()] = $this->array[$it->getSubIterator(0)->key()];
}
}
}
private function registerDefault() {
$this->register['$eq'] = array($this,"evaluateEqal");
$this->register['$not'] = array($this,"evaluateNotEqual");
$this->register['$gte'] = array($this,"evaluateGreater");
$this->register['$gt'] = array($this,"evaluateGreater");
$this->register['$lte'] = array($this,"evaluateLess");
$this->register['$lt'] = array($this,"evaluateLess");
$this->register['$in'] = array($this,"evalueateInset");
$this->register['$func'] = array($this,"evalueateFunction");
$this->register['$fn'] = array($this,"evalueateFunction");
$this->register['$f'] = array($this,"evalueateFunction");
}
private function log($log) {
$this->log[] = $log;
}
private function getPath(RecursiveIteratorIterator $it) {
$keyPath = array();
foreach ( range(1, $it->getDepth()) as $depth ) {
$keyPath[] = $it->getSubIterator($depth)->key();
}
return implode(".", $keyPath);
}
private function checkType($a, $b) {
if (gettype($a) != gettype($b)) {
$this->log(sprintf("%s - %s is not same type of %s - %s", json_encode($a), gettype($a), json_encode($b), gettype($b)));
return false;
}
return true;
}
private function evaluate($key, $value) {
$o = $r = 0; // Obigation & Requirement
foreach ( $this->expression as $k => $options ) {
if ($k !== $key)
continue;
if (is_array($options)) {
foreach ( $options as $eK => $eValue ) {
if (strpos($eK, '$') === 0) {
$r ++;
$callable = $this->register[$eK];
$callable($value, $eValue) and $o ++;
} else {
throw new InvalidArgumentException('Missing "$" in expession key');
}
}
} else {
$r ++;
$this->evaluateEqal($value, $options) and $o ++;
}
}
return $r > 0 && $o === $r;
}
private function evaluateEqal($a, $b) {
return $a == $b;
}
private function evaluateNotEqual($a, $b) {
return $a != $b;
}
private function evaluateLess($a, $b) {
return $this->checkType($a, $b) and $a < $b;
}
private function evaluateGreater($a, $b) {
return $this->checkType($a, $b) and $a > $b;
}
private function evalueateInset($a, array $b) {
return in_array($a, $b);
}
private function evalueateFunction($a, callable $b) {
return $b($a);
}
}
概要
すべての高度な機能を網羅しているわけではなく、拡張可能なアーキテクチャを備えている必要があります
上記のクラスは、必要なものの典型的な例を示しています。簡単にdecouple
できます。 それは、$and
のような複合式をサポートするように拡張します および$or
MongoDBのようなクエリ式オブジェクトは、理解と使用が簡単で、クエリと検索対象のオブジェクトの両方が連想配列であるため、クリーンで自己説明的なコードを記述できます。
配列をMongoDB
に書き込んでみませんか 配列ではなくデータベース??それはより効率的であり、それはあなたに多くのトラブルを救うでしょう
また、最高の仕事に最高のツールを使用することにも言及する必要があります...必要なのは基本的にデータベースの機能です
基本的に、php配列から情報を抽出するための便利な機能について話します。配列構造(arrayPath)を知っているので、複数のネストされたループを必要とせずに、多次元配列データに対して操作を実行できます。
この例は、パスを使用して値を検索する方法を示していますが、配列をメモリにロードし、クラスがデータベースほど効率的ではない複数の再帰ansループを実行することに依存しています。
アーキテクチャのヒント、関連または類似のコードに感謝します。これは、phpの「if..else」式をその場で構築するための良い実践例かもしれません。
本当にここにあるものすべてが欲しいという意味ですか???