Para mejor o peor, suelta-escribir es "The Way PHP". Muchos de los integradores, y la mayoría de los constructos de lenguaje, operarán en los tipos que les proporciones: silenciosamente (y con frecuencia peligrosamente) lanzándolos detrás de las escenas para hacer que las cosas (más o menos) encajen juntas.
Procedente de un fondo Java/C/C++, el modelo de mecanografía de PHP siempre ha sido una fuente de frustración para mí. Pero a través de los años he descubierto que, si tengo que escribir PHP, puedo hacer un mejor trabajo (es decir, un código más limpio, más seguro y más comprobable) adoptando la "soltura" de PHP, en lugar de luchar contra ella; y termino siendo un mono más feliz por eso.
Casting realmente es fundamental para mi técnica, y (en mi humilde opinión) es la única forma de construir consistentemente un código PHP limpio y legible que maneje argumentos mixtos de una manera bien entendida, comprobable y determinista.
El punto principal (que usted también comprende claramente) es que, en PHP, no puede simplemente asumir que un argumento es del tipo que espera que sea. Si lo hace, puede tener consecuencias graves que probablemente no detectará hasta después de que su aplicación haya comenzado a producirse.
Para ilustrar este punto:
<?php
function displayRoomCount($numBoys, $numGirls) {
// we'll assume both args are int
// check boundary conditions
if(($numBoys < 0) || ($numGirls < 0)) throw new Exception('argument out of range');
// perform the specified logic
$total = $numBoys + $numGirls;
print("{$total} people: {$numBoys} boys, and {$numGirls} girls \n");
}
displayRoomCount(0, 0); // (ok) prints: "0 people: 0 boys, and 0 girls"
displayRoomCount(-10, 20); // (ok) throws an exception
displayRoomCount("asdf", 10); // (wrong!) prints: "10 people: asdf boys, and 10 girls"
Un enfoque para la solución de este es para restringir los tipos que la función puede aceptar, lanzar una excepción cuando se detecta un tipo no válido. Otros ya han mencionado este enfoque. Apela bien a mi estética Java/C/C++, y seguí este enfoque en PHP durante años y años. En resumen, no hay nada de malo en ello, pero va en contra de "The PHP Way", y después de un tiempo, eso comienza a parecerse a la corriente ascendente.
Como alternativa, la fundición proporciona una manera simple y limpia de garantizar que la función se comporte de manera determinista para todas las entradas posibles, sin tener que escribir una lógica específica para manejar cada tipo diferente.
El uso de fundición, nuestro ejemplo ahora se convierte en:
<?php
function displayRoomCount($numBoys, $numGirls) {
// we cast to ensure that we have the types we expect
$numBoys = (int)$numBoys;
$numGirls = (int)$numGirls;
// check boundary conditions
if(($numBoys < 0) || ($numGirls < 0)) throw new Exception('argument out of range');
// perform the specified logic
$total = $numBoys + $numGirls;
print("{$total} people: {$numBoys} boys, and {$numGirls} girls \n");
}
displayRoomCount("asdf", 10); // (ok now!) prints: "10 people: 0 boys, and 10 girls"
La función se comporta ahora como se esperaba. De hecho, es fácil mostrar que el comportamiento de la función ahora está bien definido para todas las entradas posibles. Esto se debe a que la operación de lanzamiento está bien definida para todas las entradas posibles; los lanzamientos aseguran que siempre estamos trabajando con enteros; y el resto de la función está escrita para estar bien definida para todos los enteros posibles.
Rules for type-casting in PHP are documented here, (consulte los enlaces específicos del tipo en la mitad de la página, p. Ej .: "Convertir a entero").
Este enfoque tiene la ventaja añadida de que la función ahora se comportará de manera coherente con otras construcciones de lenguaje PHP incorporadas. Por ejemplo:
// assume $db_row read from a database of some sort
displayRoomCount($db_row['boys'], $db_row['girls']);
funcionará bien, a pesar del hecho de que $db_row['boys']
y $db_row['girls']
son en realidad las cadenas que contienen valores numéricos. Esto es consistente con la forma en que el desarrollador promedio de PHP (que no conoce C, C++ o Java) esperará que funcione.
En cuanto a la fundición valores de retorno: hay muy poco sentido hacerlo, a menos que usted sabe que tiene una variable potencialmente de tipo mixto, y que desea asegurarse siempre de que el valor de retorno es un tipo específico. Este es más frecuentemente el caso en puntos intermedios en el código, en lugar de en el punto en el que regresas de una función.
Un ejemplo práctico:
<?php
function getParam($name, $idx=0) {
$name = (string)$name;
$idx = (int)$idx;
if($name==='') return null;
if($idx<0) $idx=0;
// $_REQUEST[$name] could be null, or string, or array
// this depends on the web request that came in. Our use of
// the array cast here, lets us write generic logic to deal with them all
//
$param = (array)$_REQUEST[$name];
if(count($param) <= $idx) return null;
return $param[$idx];
}
// here, the cast is used to ensure that we always get a string
// even if "fullName" was missing from the request, the cast will convert
// the returned NULL value into an empty string.
$full_name = (string)getParam("fullName");
se entiende la idea.
Hay un par de pifias a tener en cuenta el mecanismo de fundición
de PHP no es lo suficientemente inteligente como para optimizar la "no-op" fundido. Entonces, fundir siempre provoca que se realice una copia de la variable. En la mayoría de los casos, esto no es un problema, pero si usa este enfoque regularmente, debe tenerlo en cuenta. Debido a esto, la conversión puede causar problemas inesperados con referencias y arreglos grandes. Ver PHP Bug Report #50894 para más detalles.
En php, un número entero que es demasiado grande (o demasiado pequeño) para representarlo como un tipo entero, se representará automáticamente como un flotante (o un doble, si es necesario). Esto significa que el resultado de ($big_int + $big_int)
puede ser realmente un flotador, y si lo lanzas a un int, el número resultante será un galimatías. Por lo tanto, si está creando funciones que necesitan operar en números enteros grandes, debe tener esto en cuenta, y probablemente considere otro enfoque.
Lo siento por el largo post, pero es un tema que he considerado en profundidad, ya través de los años, he acumulado un poco de conocimiento (y de opinión) sobre él. Al publicarlo aquí, espero que alguien lo encuentre útil.
Puede pensar que la tipificación débil (como en PHP, javascript, Smalltalk, c, C++, etc.) es un defecto, pero es parte del diseño de PHP, y por lo tanto es poco probable que cambie. También es una de las características que hace que PHP sea un lenguaje de tipo c. – GZipp
@GZopp: C y C++ no son idiomas débilmente tipados. –
En realidad, puede requerir que los argumentos sean de cierto tipo, pero solo funciona con clases y matrices, no con otros tipos incorporados. http://www.php.net/manual/en/functions.arguments.php#98425 – mwhite