Сопоставьте формулу (SQL'ish) с массивом PHP, чтобы вернуть true или false

Это сложно объяснить. У меня есть ассоциативный массив, для которого я хочу запустить набор правил, чтобы вернуть true или false.

Мне было интересно, есть ли где-нибудь библиотека, позволяющая мне сравнивать правило (или набор) с массивом. Почти как SQL, за исключением того, что у меня есть запись, мне просто нужно посмотреть, вернет ли SQL ее или нет.

Например:

$subject = array('name' => 'John Smith', 'age' => '44');
$formula = "name LIKE 'John%' AND (age = 44 OR age = 45)";
if(match($formula, $subject))
return true;
else 
return false;

Массив тем НЕ из базы данных, а на самом деле из сообщения формы, иначе я бы просто запустил SQL, и если бы он вернул правильную запись, это было бы правдой. Кроме того, это то, что я хотел бы часто использовать с разными ассоциативными массивами, поэтому добавление в таблицу, а затем выполнение запроса для получения той же записи будет невозможно. В принципе, я не могу использовать базу данных.


person user1094128    schedule 13.12.2011    source источник
comment
Трудность здесь будет заключаться в разборе $formula — откуда берется эта строка? Не могли бы вы изменить формат или (в идеале) использовать массив?   -  person DaveRandom    schedule 13.12.2011
comment
Это был просто пример. На данный момент я использую следующий массив: array('field'=›'name','operator'=›'==','value'=›'Jonh Smith'), но он должен быть очень сложным.   -  person user1094128    schedule 13.12.2011
comment
Кроме того, в настоящее время я объединяю их вместе для сопоставления более чем одного поля или значения. Это нормально, но я не могу иметь вложенные правила, как в SQL.   -  person user1094128    schedule 13.12.2011


Ответы (3)


Может быть, вы могли бы сделать что-то вроде этого?

function match ($subject, $formula) {
  extract($subject);
  foreach ($formula as $rule) {
    if (!eval("return $rule;")) return FALSE;
  }
  return TRUE;
}

$formula = array(
  'substr($name,0,4) == "John"',
  '$age == 44 OR $age == 45'
);
$subject1 = array('name' => 'John Smith', 'age' => '44');
$subject2 = array('name' => 'Bob Jones', 'age' => '42');

var_dump(match($subject1, $formula)); // bool (TRUE)
var_dump(match($subject2, $formula)); // bool (FALSE)

Такой подход означает, что ваши правила могут быть настолько сложными, насколько вам нравится; например, приведенное выше $formula можно сжать в это одно правило:

$formula = array(
  'substr($name,0,4) == "John" AND ($age == 44 OR $age == 45)'
);

Из-за того, как это работает, несколько правил фактически имеют отношение И — как только одно правило не работает, функция возвращает false.

Вы можете написать что угодно, используя любую функцию PHP, если это допустимое выражение сравнения.

person DaveRandom    schedule 13.12.2011

Если вы хотите, чтобы выражение анализировалось так, как если бы оно было SQL, используйте анализатор SQL....

$subject = array('name' => 'John Smith', 'age' => '44'); 
$formula = "'name' LIKE 'John%' AND ('age' = '44' OR 'age' = '45')";
$result=try_expression($subject, $formula);

function try_db_expression($subject, $formula) 
{
$keys=array_keys($subject);
$vals=array_values($subject);

foreach ($keys as $k=>$v) {
   $keys[$k]='/\b' . mysql_real_escape_string($v) . '\b/i';
}
foreach ($vals as $k=>$v) {
   $vals[$k]=mysql_real_escape_string($v);
}
$test=preg_replace($keys, $vals, $subject);
$res=mysql_query("SELECT ($test) AS evald");
if ($r=mysql_fetch_assoc($res)) return $r['evald'];
return false;
}

В основном я не могу использовать базу данных

Затем вам придется создать свой собственный синтаксический анализатор (не совсем - вы можете использовать eval PHP - но вам нужно будет сопоставить оператор LIKE с функцией PHP).

person symcbean    schedule 13.12.2011

Таких реализаций немного. Вы в основном ищете «LINQ в PHP» и тот, который работает с наборами данных массива. PHPLinq

Большинство из них используют метод запроса, более похожий на ORM, а не анализатор SQL. (Который вы можете получить на http://www.phpinsider.com/php/code/SafeSQL/ или http://pear.php.net/package/SQL_Parser)

Вы можете имитировать выражения SQL с помощью рекурсивного регулярного выражения. Но вы не можете так просто разобрать и обработать их с помощью preg_match или _replace_callback. Я бы не беспокоился, если бы у вас действительно не было только таких простых примеров.

person mario    schedule 13.12.2011