Операторы динамического сравнения в PHP - PullRequest
11 голосов
/ 27 мая 2010

Можно ли каким-либо образом передать операторы сравнения в качестве переменных в функцию? Я смотрю на производство некоторых вспомогательных функций, например (и я знаю, что это не будет работать):

function isAnd($var, $value, $operator = '==')
{
    if(isset($var) && $var $operator $value)
        return true;
}

if(isAnd(1, 1, '===')) echo 'worked';

Заранее спасибо.

Ответы [ 10 ]

29 голосов
/ 12 июля 2010

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

17 голосов
/ 07 апреля 2011

Как насчет этого?

function num_cond ($var1, $op, $var2) {

    switch ($op) {
        case "=":  return $var1 == $var2;
        case "!=": return $var1 != $var2;
        case ">=": return $var1 >= $var2;
        case "<=": return $var1 <= $var2;
        case ">":  return $var1 >  $var2;
        case "<":  return $var1 <  $var2;
    default:       return true;
    }   
}

Тест:

$ops = array( "=", "!=", ">=", "<=", ">", "<" );
$v1 = 1; $v2 = 5;

foreach ($ops as $op) {
    if (num_cond($v1, $op, $v2)) echo "True  ($v1 $op $v2)\n"; else echo "False ($v1 $op $v2)\n";
}
10 голосов
/ 27 мая 2010

Как насчет небольшого класса:

class compare
{
  function is($op1,$op2,$c)
  {
     $meth = array('===' => 'type_equal', '<' => 'less_than');
     if($method = $meth[$c]) {
        return $this->$method($op1,$op2);
     }
     return null; // or throw excp.
  }
  function type_equal($op1,$op2)
  {
      return $op1 === $op2;
  }
  function less_than($op1,$op2)
  {
      return $op1 < $op2;
  }
}
3 голосов
/ 27 мая 2010

Большая проблема в том, что эта функция довольно бессмысленна. Давайте заменим это реальным (гипотетически работающим) примером:

function isAnd($var, $value, $operator = '==') {
    return isset($var) && $var $operator $value;
}

isAnd($foo, 1, '===');

В этом примере $foo не установлено. Вы получите ошибку, потому что пытаетесь передать несуществующую переменную ($foo) в функцию (isAnd). Итак, вам нужно будет проверить $foo для isset до того, как позвонит isAnd:

isset($foo) && isAnd($foo, 1, '===');

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

Что может сбить с толку, так это то, что isset() и empty() не имеют этого ограничения, т. Е. Вы можете передать им несуществующую переменную без ошибок. Дело в том, что это не обычные функции, а специальные языковые конструкции (которые выглядят как функции; обвиняют PHP). К сожалению, вы не можете создавать такие конструкции, параметры для ваших функций всегда должны существовать.

Вы должны просто привыкнуть к написанию isset($foo) && $foo === 1. С правильно структурированным кодом вы можете уменьшить его до минимума, всегда объявляя все переменные, которые вы собираетесь использовать, что в любом случае является хорошей практикой.

Для динамического оператора ... вам понадобится какая-то форма if ... else где-нибудь, чтобы решить, какой оператор все равно использовать. Вместо того, чтобы устанавливать переменную оператора и затем оценивать ее, не проще ли выполнить оценку прямо здесь?

2 голосов
/ 17 марта 2016

Верхний ответ рекомендует небольшой класс, но мне нравится эта черта.

trait DynamicComparisons{

private $operatorToMethodTranslation = [
    '=='  => 'equal',
    '===' => 'totallyEqual',
    '!='  => 'notEqual',
    '>'   => 'greaterThan',
    '<'   => 'lessThan',
];

protected function is($value_a, $operation, $value_b){

    if($method = $this->operatorToMethodTranslation[$operation]){
        return $this->$method($value_a, $value_b);
    }

    throw new \Exception('Unknown Dynamic Operator.');
}

private function equal($value_a, $value_b){
    return $value_a == $value_b;
}

private function totallyEqual($value_a, $value_b){
    return $value_a === $value_b;
}

private function notEqual($value_a, $value_b){
    return $value_a != $value_b;
}

private function greaterThan($value_a, $value_b){
    return $value_a > $value_b;
}

private function lessThan($value_a, $value_b){
    return $value_a < $value_b;
}

private function greaterThanOrEqual($value_a, $value_b){
    return $value_a >= $value_b;
}

private function lessThanOrEqual($value_a, $value_b){
    return $value_a <= $value_b;
}

}
2 голосов
/ 27 мая 2010

Если вы абсолютно настаиваете, вы можете использовать eval.

if(isset($var) && eval("return \$var $operator \$value"))
    return true;

Но я бы не советовал.

1 голос
/ 24 апреля 2019

Вот простое решение, которое должно работать почти для всех операторов

Например.

$b = 10;
$c = '+';
$p = $a . $c. $b; // Forming a String equation
$p = eval('return '.$p.';'); // Evaluating the Equation
echo $p;

Выход:

15

Другой пример с оператором сравнения:

$b = 10;
$c = '==';
$p = $a . $c. $b;
$p = eval('return '.$p.';');
echo $p;

Выход:

false

Надеюсь, это поможет.

1 голос
/ 27 мая 2010

Как предлагает Майкл Крелин, вы можете использовать eval, но это потенциально может привести к множеству атак внедрения кода.

Вы не можете заменить переменную для оператора - но вы можете заменить переменную для функции:

function is_equal($a, $b) {
  return $a==$b;
} 
function is_same($a, $b) {
  return $a===$b;
}
function is_greater_than($a, $b)
....

$compare='is_equal';
if ($compare($a, $b)) {
   ....

С

0 голосов
/ 27 мая 2010

Насколько я знаю, это невозможно, и поскольку в документации PHP нет упоминаний об обратном вызове операторов, http://www.php.net/manual/en/language.operators.php

вместо использования eval, я бы переопределил каждый оператор в глобальных функциях и использовал бы обратные вызовы php Как реализовать обратный вызов в PHP?

0 голосов
/ 27 мая 2010

Нет, это невозможно. Вместо этого вы можете использовать условные операторы, но будет намного, намного лучше , если вы перепроектируете свое приложение, чтобы сделать такое динамическое сравнение ненужным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...