Я искал объект MongoDb-like ( http://docs.mongodb.org/manual/applications/read/#find , docs.mongodb.org/manual/reference/operators/) реализацию функции оценки объекта выражения запроса или класс. Он может охватывать не все расширенные функции и иметь расширяемую архитектуру.
Объекты выражения MongoDB-like легко понимают и используют , обеспечивая возможность писать чистый, самоочевидный код, поскольку как запрос, так и объекты для поиска, являются ассоциативными массивами.
В основном говоря, его удобная функция для извлечения информации из php-массивов. Зная структуру массива (arrayPath), он позволит выполнять операции над данными многомерных массивов без необходимости в нескольких вложенных циклах.
Если вы не знакомы с MongoDb, посмотрите на объект выражения и массив для поиска.
Я написал его как строку JSON для простоты. Содержимое объекта не имеет смысла, просто показано синтаксис запроса 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 } } ]
Таким образом, с помощью функции мы должны иметь возможность выдавать следующий запрос в целевой массив.
$found=findLikeMongo($array, $queryExpr); //resulting in a $array[0] value; //@return found array
$arrayPath=getPathFromMongo($array, $queryExpr);// resulting in array("0") //@return array path, represented as an array where entries are consecutive keys.
Я обнаружил, что goessner.net/articles/JsonPath/ может удовлетворить мои потребности (не будучи точным совпадением, потому что он использует выражения, подобные Xpath), оговорка заключается в том, что она в значительной степени зависит от регулярных выражений и синтаксического анализа строк, что определенно замедляется это по сравнению с реализацией только массива (JSON).
Также я нашел аналогичный вопрос здесь, @stackoverflow. Оценивая запросы JSON , подобные MongoDB, в PHP . В результате ответ был использован некоторые функции SPL, которые я использую, чтобы избежать большую часть времени.
Интересно, создал ли автор функцию, которую он пытался развить.
Возможная реализация arrayPath была найдена на thereisamoduleforthat.com/content/dealing-deep-arrays-php, поэтому отсутствие этой реализации состоит в том, что она опирается на указатели.
Я знаю, что это не тривиальный вопрос с ответом oneliner, вот почему я спрашиваю об этом, прежде чем начинать разработку своего собственного класса.
Я ценю советы по архитектуре, родственный или похожий код, который может быть хорошим примером практики для создания выражений php «if..else» на лету. подчеркнутый текст
@Baba предоставил отличный класс, который написан с использованием SPL. Интересно, как переписать этот код без SPL.
Созданный класс ArrayQuery публикуется в Github, подумайте о том, чтобы проверить репозиторий на наличие обновлений.
Вкратце-
$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) );
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 );
в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 );
в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 );
Функция parse () SPL-класса была слегка изменена, чтобы вернуть значение после выполнения, его также можно было бы изменить, чтобы принять выражение, но это не важно для целей профилирования, поскольку это выражение переоценивается каждый раз.
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 );
в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 );
в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 );
<?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); ?>
в<?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); ?>
$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);
<!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>
@baba дала отличную сырую версию PHP класса, реализующего оценку объекта выражения MongoDB-like, но структура вывода немного отличается, я имею в виду точечную нотацию в выходе вложенного массива ([release.arch] => x86), вместо регулярных массивов ([release] => Массив ([arch] => x86)). Я был бы признателен за ваш совет, как сделать класс полностью совместимым с mongoDB в этом порядке, поскольку он, похоже, строго связан с реализацией PHP-класса.
================================================== =====================
Ответ:
То, что вы хотите, очень просто. Все, что вам нужно, это 2 corrections
в текущем коде ввода и вывода кода, и вы получите новый формат.
Что я имею в виду ?
A. Изменено
foreach ( $array as $part ) { $this->flatten[] = $this->convert($part); }
к
foreach ( $array as $k => $part ) { $this->flatten[$k] = $this->convert($part); }
B. Изменено
foreach ( $this->flatten as $data ) { $this->check($find, $data, $type) and $f[] = $data; }
Для того, чтобы:
foreach ( $this->flatten as $k => $data ) { $this->check($find, $data, $type) and $f[] = $this->array[$k]; }
Новый массив для отдыха
$json = '[ { "name": "Mongo", "release": { "arch": "x86", "version": 22, "year": 2012 }, "type": "db" }, { "name": "Mongo", "release": { "arch": "x64", "version": 21, "year": 2012 }, "type": "db" }, { "name": "Mongo", "release": { "arch": "x86", "version": 23, "year": 2013 }, "type": "db" }, { "name": "MongoBuster", "release": { "arch": [ "x86", "x64" ], "version": 23, "year": 2013 }, "type": "db" }, { "children": { "dance": [ "one", "two", { "three": { "a": "apple", "b": 700000, "c": 8.8 } } ], "lang": "php", "tech": "json", "year": 2013 }, "key": "Diffrent", "value": "cool" } ]'; $array = json_decode($json, true);
Простой тест
$s = new ArrayStandard($array); print_r($s->find(array("release.arch"=>"x86")));
Вывод
Array ( [0] => Array ( [name] => Mongo [type] => db [release] => Array ( [arch] => x86 [version] => 22 [year] => 2012 ) ) [1] => Array ( [name] => Mongo [type] => db [release] => Array ( [arch] => x86 [version] => 23 [year] => 2013 ) ) )
Если вы также хотите сохранить исходную array key position
вы можете
foreach ( $this->flatten as $k => $data ) { $this->check($find, $data, $type) and $f[$k] = $this->array[$k]; }
Просто для забавной части
A. Поддержка regex
Просто для удовольствия я добавил поддержку $regex
с псевдонимом $preg
или $match
что означает, что вы можете
print_r($s->find(array("release.arch" => array('$regex' => "/4$/"))));
Или
print_r($s->find(array("release.arch" => array('$regex' => "/4$/"))));
Вывод
Array ( [1] => Array ( [name] => Mongo [type] => db [release] => Array ( [arch] => x64 [version] => 21 [year] => 2012 ) ) )
B. Используйте простой массив, например, queries
$queryArray = array( "release" => array( "arch" => "x86" ) ); $d = $s->find($s->convert($queryArray));
$s->convert($queryArray)
преобразовал
Array ( [release] => Array ( [arch] => x86 ) )
к
Array ( [release.arch] => x86 )
C. Модуль $mod
print_r($s->find(array( "release.version" => array( '$mod' => array( 23 => 0 ) ) ))); //Checks release.version % 23 == 0 ;
D. Считать элементы с $size
print_r($s->find(array( "release.arch" => array( '$size' => 2 ) ))); // returns count(release.arch) == 2;
E. Проверьте, соответствует ли он всем элементу в массиве $all
print_r($s->find(array( "release.arch" => array( '$all' => array( "x86", "x64" ) ) )));
Вывод
Array ( [3] => Array ( [name] => MongoBuster [release] => Array ( [arch] => Array ( [0] => x86 [1] => x64 ) [version] => 23 [year] => 2013 ) [type] => db ) )
F. Если вы не уверены в имени ключа элемента, то вы используете $has
как у opposite
$in
print_r($s->find(array( "release" => array( '$has' => "x86" ) )));
================================================== =====================
@Baba предоставил отличный класс, который написан с использованием SPL. Интересно, как переписать этот код без SPL. Причина в том, что вызов этого класса несколько раз даст накладные функции, которых можно избежать, переписывая его в необработанном PHP и, возможно, используя инструкцию goto в окончательной версии, чтобы избежать рекурсивных вызовов функций.
================================================== =====================
Поскольку вы не хотите SPL
и функций .. это заняло некоторое время, но я смог придумать альтернативный класс, который также является гибким и простым в использовании
Чтобы избежать загрузки массива несколько раз, вы объявляете его один раз:
$array = json_decode($json, true); $s = new ArrayStandard($array);
A. Найдите, где release.year
– 2013
$d = $s->find(array( "release.year" => "2013" )); print_r($d);
Вывод
Array ( [0] => Array ( [name] => Mongo [type] => db [release.arch] => x86 [release.version] => 23 [release.year] => 2013 ) )
B. В первый раз вы можете запустить сложный $and
или или $or
оператор, например find, где release.arch
= x86
и release.year
= 2012
$d = $s->find(array( "release.arch" => "x86", "release.year" => "2012" ), ArrayStandard::COMPLEX_AND); print_r($d);
Вывод
Array ( [0] => Array ( [name] => Mongo [type] => db [release.arch] => x86 [release.version] => 22 [release.year] => 2012 ) )
C. Представьте себе гораздо более сложный запрос
$d = $s->find(array( "release.year" => array( '$in' => array( "2012", "2013" ) ), "release.version" => array( '$gt' => 22 ), "release.arch" => array( '$func' => function ($a) { return $a == "x86"; } ) ), ArrayStandard::COMPLEX_AND); print_r($d);
Вывод
Array ( [0] => Array ( [name] => Mongo [type] => db [release.arch] => x86 [release.version] => 23 [release.year] => 2013 ) )
Новый класс Modified
class ArrayStandard { const COMPLEX_OR = 1; const COMPLEX_AND = 2; private $array; private $tokens; private $found; function __construct(array $array) { $this->array = $array; foreach ( $array as $k => $item ) { $this->tokens[$k] = $this->tokenize($item); } } public function getTokens() { return $this->tokens; } public function convert($part) { return $this->tokenize($part, null, false); } public function find(array $find, $type = 1) { $f = array(); foreach ( $this->tokens as $k => $data ) { $this->check($find, $data, $type) and $f[$k] = $this->array[$k]; } return $f; } private function check($find, $data, $type) { $o = $r = 0; // Obigation & Requirement foreach ( $data as $key => $value ) { if (isset($find[$key])) { $r ++; $options = $find[$key]; if (is_array($options)) { reset($options); $eK = key($options); $eValue = current($options); if (strpos($eK, '$') === 0) { $this->evaluate($eK, $value, $eValue) and $o ++; } else { throw new InvalidArgumentException('Missing "$" in expession key'); } } else { $this->evaluate('$eq', $value, $options) and $o ++; } } } if ($o === 0) return false; if ($type == self::COMPLEX_AND and $o !== $r) return false; return true; } private function getValue(array $path) { return count($path) > 1 ? $this->getValue(array_slice($path, 1), $this->array[$path[0]]) : $this->array[$path[0]]; } private function tokenize($array, $prefix = '', $addParent = true) { $paths = array(); $px = empty($prefix) ? null : $prefix . "."; foreach ( $array as $key => $items ) { if (is_array($items)) { $addParent && $paths[$px . $key] = json_encode($items); foreach ( $this->tokenize($items, $px . $key) as $k => $path ) { $paths[$k] = $path; } } else { $paths[$px . $key] = $items; } } return $paths; } private function evaluate($func, $a, $b) { $r = false; switch ($func) { case '$eq' : $r = $a == $b; break; case '$not' : $r = $a != $b; break; case '$gte' : case '$gt' : if ($this->checkType($a, $b)) { $r = $a > $b; } break; case '$lte' : case '$lt' : if ($this->checkType($a, $b)) { $r = $a < $b; } break; case '$in' : if (! is_array($b)) throw new InvalidArgumentException('Invalid argument for $in option must be array'); $r = in_array($a, $b); break; case '$has' : if (is_array($b)) throw new InvalidArgumentException('Invalid argument for $has array not supported'); $a = @json_decode($a, true) ? : array(); $r = in_array($b, $a); break; case '$all' : $a = @json_decode($a, true) ? : array(); if (! is_array($b)) throw new InvalidArgumentException('Invalid argument for $all option must be array'); $r = count(array_intersect_key($a, $b)) == count($b); break; case '$regex' : case '$preg' : case '$match' : $r = (boolean) preg_match($b, $a, $match); break; case '$size' : $a = @json_decode($a, true) ? : array(); $r = (int) $b == count($a); break; case '$mod' : if (! is_array($b)) throw new InvalidArgumentException('Invalid argument for $mod option must be array'); list($x, $y) = each($b); $r = $a % $x == 0; break; case '$func' : case '$fn' : case '$f' : if (! is_callable($b)) throw new InvalidArgumentException('Function should be callable'); $r = $b($a); break; default : throw new ErrorException("Condition not valid ... Use \$fn for custom operations"); break; } return $r; } private function checkType($a, $b) { if (is_numeric($a) && is_numeric($b)) { $a = filter_var($a, FILTER_SANITIZE_NUMBER_FLOAT); $b = filter_var($b, FILTER_SANITIZE_NUMBER_FLOAT); } if (gettype($a) != gettype($b)) { return false; } return true; } }
Я думаю, что оценка запросов в JSON от MongoDB в PHP дала всю необходимую вам информацию. все, что вам нужно, это быть творческим с решением, и вы достигаете того, что хотите
Массив
Предположим, что мы имеем следующий 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
ли год 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); } }
с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-like легко понимают и используют, обеспечивая возможность писать чистый, самоочевидный код, поскольку как запрос, так и объекты для поиска, являются ассоциативными массивами.
Почему бы просто не написать массив в MongoDB
данных MongoDB
а не работать с массивами? Это более эффективно, и это сэкономит вам массу проблем
Я также должен упомянуть, что использовать лучший инструмент для лучшей работы … То, что вы хотите, в основном, является функцией базы данных
В основном говоря, его удобная функция для извлечения информации из php-массивов. Зная структуру массива (arrayPath), он позволит выполнять операции над данными многомерных массивов без необходимости в нескольких вложенных циклах.
В этом примере показано, как использовать путь для поиска значения, но вы все еще зависите от загрузки массива в память, а ваш класс выполняет несколько циклов рекурсии и не так эффективен, как база данных.
Я ценю советы по архитектуре, родственный или похожий код, который может быть хорошим примером практики для создания выражений php «if..else» на лету.
Вы действительно хотите, чтобы вы все хотели здесь?