2010-11-04 9 views
7

Escribo código para una tabla ordenable, donde al hacer clic en los enlaces del encabezado cambia el ORDEN BY ejecutado al generar un conjunto de resultados de búsqueda (el caso donde no hay orden válido por causas la consulta no debe ejecutarse con el pedido y solo devuelve los resultados en el orden en que la base de datos retorna. Esto es como se diseñó). El código se está escribiendo dentro de un marco provisto por mi empleador.Comportamiento extraño en una declaración de interruptor

Para validar la parte ORDER BY de la consulta, ejecuto la entrada a través de la siguiente función de validación.

<?php 
function sortMode ($name) 
{ 
    $mode = ''; 
    switch ($name) 
    { 
     case 'resnum' : $mode = 'b_resnum';   break; 
     case 'state' : $mode = 'st_id';    break; 
     case 'name'  : $mode = 'lastname, firstname'; break; 
     case 'phone' : $mode = 'phone';    break; 
     case 'email' : $mode = 'email';    break; 
     case 'opened' : $mode = 'cs_created';   break; 
     default   : $mode = '';     break; 
    } 
    return ($mode); 
} 
?> 

En las pruebas, descubrí que si no se proporcionaba ningún parámetro, el orden de clasificación sería resnum. Después de un poco de experimentación, descubrí que el filtrado integrado en el marco provocaría una solicitud de una variable no inicializada, como un parámetro GET no establecido para devolver el entero 0. Si el código anterior se alimentaba con un entero 0 como su entrada, siempre seguiría al primero camino de ejecución disponible para él.

Como experimento Intenté cambiar el orden de los casos en la sentencia switch, y encontré lo que estaba en la parte superior sería lo que se ejecutará si esta función se aprobó un 0.

La solución al problema era usando switch (strval($name)) por lo que el problema particular está resuelto, pero ahora tengo curiosidad en cuanto al comportamiento general de las instrucciones de conmutación de PHP. ¿Es el comportamiento que presencié el comportamiento correcto para PHP? ¿Hay algún error en PHP que está causando esto o he cometido un error en mi código del cual no estoy al tanto?

Respuesta

12

Es por la forma en que php aplica cadenas a las tintas. Cuando pasa en 0, le está pidiendo que haga una comparación entera, por lo que convertirá todas sus claves de caso en enteros. Cuando php lanza un string a un int, busca un número real al comienzo de la cadena y engulle el número hasta que llegue a un número no. Desde la cadena "resnum" no tiene números, se devuelve 0. Ver aquí:

php > echo (int)"100"; 
100 
php > echo (int)"300 dogs"; 
300 
php > echo (int)"resnum"; 
0 
php > echo (int)"resnum 100"; 
0 

Puesto que todas esas cadenas emitidos a 0, el primer caso evaluaría a true desde 0 == 0.

Recursos:
String conversion to numbers
Type comparison tables


tiempo nitpick. Cuando está haciendo declaraciones de casos simples que asignan una cadena a una cadena, use una matriz. Es mucho más claro y realmente más rápido:

function sortMode ($name) 
{ 
    $modeMap = array(
     'resnum' => 'b_resnum', 
     'state' => 'st_id', 
     'name'  => 'lastname, firstname', 
     'phone' => 'phone', 
     'email' => 'email', 
     'opened' => 'cs_created' 
    ); 

    return isset($modeMap[$name]) ? $modeMap[$name] : ''; 
} 

Si el $name se encuentra en el mapa, volvemos el valor que se asigna a la tecla. De lo contrario, devolvemos una cadena vacía, que toma el lugar del caso default.

Como una ventaja, usted habría notado el error antes si hubiera hecho el método anterior, porque estaría tratando de acceder al $modeMap[0] y habría devuelto su caso predeterminado en su lugar.

+4

+1 dang! Este es un comportamiento peligroso. –

+1

PHP puede ser pura maldad. Esta conversión int automática ha causado más frustración que el tiempo "guardado". – GWW

+1

Al menos en un si se puede usar === y evitar esto, pero lamentablemente el interruptor/caso es un == – UnkwnTech

0

El punto clave es que una instrucción switch() realiza comparaciones entre el parámetro y las etiquetas. Eso significa que tiene que lidiar con la comparación de PHP y escribir reglas de conversión.Sólo hay que ver algunos ejemplos:

<?php 

var_dump(''==0); // bool(true) 
var_dump('foo'==0); // bool(true) 
var_dump('0'==0); // bool(true) 
var_dump('0m'==0); // bool(true) 
var_dump('01'==0); // bool(false) 

La referencia se puede encontrar en:

inicializar un parámetro GET desarmar a 0 es un bonito decisión de diseño extraño. Debe tratar ese caso en particular de forma separada para dejar en claro que se trata de una situación especial:

if($name===0){ 
    return ''; 
} 
switch($name){ 
    // ... 
}