2010-05-27 31 views
10

¿Es posible, de alguna manera, pasar operadores de comparación como variables a una función? Estoy buscando producir algunas funciones de conveniencia, por ejemplo (y sé que esto no funcionará):Operadores de comparación dinámica en PHP

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

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

Gracias de antemano.

+2

¿Cuál es el objetivo de tal función? La llamada a la función es mucho más larga que la operación en sí y no puedo pensar en algo útil que hacer con eso. – soulmerge

+1

Puede hacerlo si usa Scheme. Puede ser un patrón muy poderoso. – Skilldrick

Respuesta

9

¿Qué tal una pequeña clase:

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; 
    } 
} 
+0

¿Ni siquiera pensé en utilizar una clase, quizás temprano en la mañana? Gracias. – BenTheDesigner

+7

¿Por qué necesita ser una clase? – symcbean

+0

Antes de 5.3 esta es la mejor opción, con espacios de nombres y devoluciones de llamada reales son posibles otras buenas soluciones. Pero una clase es probablemente la más simple. – giftnuss

-2

No, es imposible. Puede usar operadores condicionales en su lugar, pero será mucho, mucho mejor si rediseña su aplicación para hacer una comparación dinámica tan innecesaria.

2

Si insistes en que puedas usar eval.

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

Pero no lo recomendaría.

+8

+1 - pero alguna explicación de por qué no la recomienda puede ser de valor para los lectores – symcbean

2

El problema más grande es que esta función es bastante inútil. Vamos a sustituir que con un ejemplo real (hipotéticamente de trabajo):

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

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

En este ejemplo $foo no está establecida. Obtendrá un error porque está intentando pasar una variable inexistente ($foo) a una función (isAnd). Por lo tanto, tendrá que poner a prueba $foo para isset antes de llamar isAnd:

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

Por lo tanto, cualquier variable que nunca entra en la función isAnd se establece definitivamente. No necesita probarlo dentro de la función. Entonces todo el ejercicio es bastante inútil.

Lo que puede ser confuso es que isset() y empty() no tienen esta limitación, es decir que puede pasar una variable inexistente a ellos sin error. El asunto es sin embargo, estas no son funciones normales, son construcciones de lenguaje especiales (que parecen funciones, culpan a PHP). Desafortunadamente usted no puede hacer este tipo de construcciones, los parámetros para sus funciones siempre deben existir.

Simplemente debe acostumbrarse a escribir isset($foo) && $foo === 1. Con el código adecuadamente estructurado, puede reducir esto al mínimo declarando siempre todas las variables que va a utilizar, lo que es una buena práctica de todos modos.

Para el operador dinámico ... necesitará algún tipo de if ... else en algún lugar para decidir qué operador usar de todos modos. En lugar de establecer la variable de operador y luego evaluarla, ¿no es más fácil hacer la evaluación allí mismo?

+0

Ver también http://stackoverflow.com/questions/1960509/isset-and-empty-make-code-ugly/1960588#1960588 – deceze

1

Como Michael Krelin sugiere que podría usar eval, pero eso potencialmente permite una gran cantidad de ataques de inyección de código.

No se puede sustituir una variable para un operador - pero se puede sustituir una variable de una función:

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)) { 
    .... 

C.

22

También puede utilizar version_compare() función, como se puede pasar operador que se usará para comparar como tercer argumento.

+1

genio relacionado. +1 esta es una solución bastante creativa y funciona muy bien para las comparaciones numéricas. –

+0

Aquí está el ejemplo, 'if (version_compare (5.9, 6, '<=')) echo TRUE; // devuelve 1 ' –

+0

Estaba creando una función de comparación de versiones porque no sabía que PHP tenía esta función, ¡increíble! –

11

¿Qué tal este?

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; 
    } 
} 

prueba:

$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"; 
} 
+0

debe incluir entrada/salida en su prueba. –

+0

esto es muy buena idea, utilicé este en mi código. Gracias –

2

La respuesta más común recomienda una pequeña clase, pero me gusta un rasgo.

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; 
} 

} 
Cuestiones relacionadas