Я искал MongoDb-like (http://docs.mongodb.org/manual/applications/read/#find, docs.mongodb.org/manual/reference/operator/) функция оценки объекта выражения запроса или класс. Он может охватывать не все расширенные функции и иметь расширяемую архитектуру.
Объекты выражения MongoDB-like легко понять и использовать, обеспечивая возможность писать чистый, самоочевидный код, поскольку как запрос, так и объекты для поиска в, являются ассоциативными массивами.
В основном говорить о своей удобной функции для извлечения информации из 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-like
Итак, с помощью функции мы должны иметь возможность выдать следующий запрос в целевой массив.
$found=findLikeMongo($array, $queryExpr); //resulting in a $array[0] value;
//@return found array
Получить массив с использованием выражений выражений Mongo-like
$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-like выражения), оговорка состоит в том, что она в значительной степени зависит от регулярных выражения и синтаксический анализ строк, что определенно замедлит его по сравнению с реализацией только массива (как JSON).
-
Также я нашел аналогичный вопрос, @stackoverflow Оценка запросов JSON, подобных MongoDB, в PHP. В результате получилось использовать некоторые функции SPL, которые я использую чтобы избежать большей части времени.
Интересно, если автор придумал функцию, он пытался развиваться. -
Возможная реализация arrayPath была найдена на thereisamoduleforthat.com/content/dealing-deep-arrays-php, таким образом, отсутствие этой реализации состоит в том, что она опирается на указатели.
Я знаю, что это не тривиальный вопрос с ответом oneliner, поэтому я спрашиваю его перед тем, как начать фактическое развитие моего собственного класса.
Я ценю советы по архитектуре, родственный или похожий код, который может быть примером хорошей практики для создания выражений php "if..else" на лету. Символьный текст
Как написать версию, отличную от SPL?
@Baba предоставил отличный класс, который написан с использованием SPL. Интересно, как переписать этот код без SPL.
Для этого есть две причины:
- вызов класса несколько раз даст накладные расходы функции, чего можно избежать перезаписи в необработанном PHP.
- он был бы легко переносимым к необработанному Javascript, где SPL недоступен, что упростит обслуживание кода на обеих платформах.
Результаты
Созданный класс ArrayQuery опубликован в Github, подумайте о том, чтобы проверить репозиторий на наличие обновлений.
SPL, исходная версия PHP и Chequer2 FORP profiler output
Вкратце -
- необработанная версия PHP работает в 10 раз быстрее, чем SPL, потребляя На 20% меньше памяти.
- Класс Chequer2 выполняет на 40% медленнее, чем класс PHP SPL, и почти 20x медленнее, чем исходная версия PHP.
- MongoDb является самым быстрым (в 10 раз быстрее, чем необработанная реализация PHP и потребляет 5 раз меньше памяти), do не используйте эти классы, если вы не уверены, что хотите избежать взаимодействие с MongoDb.
версия MongoDb
версия SPL
версия Raw 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) );
PHP с кодом профилирования класса SPL
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 class parse() была слегка изменена, чтобы вернуть значение после выполнения, его также можно было бы изменить, чтобы принять выражение, но это не является существенным для целей профилирования, поскольку выражение переоценивается каждый раз.
raw 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 );
chequer2 PHP-код профилирования
<?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 скриптs 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 скрипт to profile
include($_GET['profile']);
// stop forp
forp_end();
?>
</body>
</html>