PHP, como la mayoría de nosotros sabemos, tiene una escritura débil . Para aquellos que no, PHP.net dice:
PHP no requiere (o admite) la definición de tipo explícito en la declaración de variable; El tipo de una variable está determinado por el contexto en el que se utiliza la variable.
Me encanta o lo odio, PHP vuelve a emitir variables sobre la marcha. Entonces, el siguiente código es válido:
$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)
PHP también le permite emitir explícitamente una variable, así:
$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"
Eso es genial ... pero, por mi vida, no puedo concebir una razón práctica para hacer esto.
No tengo ningún problema con la escritura fuerte en idiomas que lo admiten, como Java. Eso está bien, y lo entiendo completamente. Además, soy consciente de, y entiendo completamente la utilidad de, las sugerencias de tipo en los parámetros de la función.
El problema que tengo con la conversión de tipos se explica en la cita anterior. Si PHP puede intercambiar tipos a voluntad , puede hacerlo incluso después de forzar la conversión de un tipo; y puede hacerlo sobre la marcha cuando necesite un determinado tipo en una operación. Eso hace que lo siguiente sea válido:
$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"
¿Entonces cuál es el punto?
Tome este ejemplo teórico de un mundo donde la conversión de tipos definida por el usuario tiene sentido en PHP :
- Fuerza la variable de lanzamiento
$foo
comoint
→(int)$foo
. - Intenta almacenar un valor de cadena en la variable
$foo
. - PHP lanza una excepción !! ← Eso tendría sentido. De repente, existe la razón para la conversión de tipos definida por el usuario.
El hecho de que PHP cambie las cosas según sea necesario hace que el punto de conversión de tipo definido por el usuario sea vago. Por ejemplo, los siguientes dos ejemplos de código son equivalentes:
// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
Un año después de hacer esta pregunta originalmente, ¿adivina quién se encontró usando la conversión de texto en un entorno práctico? Atentamente.
El requisito era mostrar valores monetarios en un sitio web para un menú de restaurante. El diseño del sitio requería que se recortaran los ceros finales, de modo que la pantalla se viera como la siguiente:
Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3
La mejor manera que encontré para hacerlo fue lanzar la variable como flotante:
$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;
PHP recorta los ceros finales del flotador y luego vuelve a refundir el flotador como una cadena para la concatenación.
fuente
(string)
moldes por todas partes ?$intval.'bar'
lanza una excepción, todavía estoy en desacuerdo. Eso no arroja una excepción en ningún idioma. (Todos los idiomas que conozco realizan una transmisión automática o una.toString()
). Si está diciendo$intval = $stringval
arroja una excepción, entonces está hablando de un lenguaje fuertemente tipado. No quise sonar grosero, así que lo siento si lo hice. Simplemente creo que va en contra de lo que todos los desarrolladores están acostumbrados, y es mucho, mucho menos conveniente.Respuestas:
En un lenguaje de tipo débil, la conversión de tipos existe para eliminar la ambigüedad en las operaciones de tipo, cuando de lo contrario el compilador / intérprete usaría el orden u otras reglas para suponer qué operación usar.
Normalmente diría que PHP sigue este patrón, pero de los casos que he verificado, PHP se ha comportado de manera contra intuitiva en cada uno.
Estos son esos casos, usando JavaScript como lenguaje de comparación.
Concatenación de cadenas
Obviamente, esto no es un problema en PHP porque hay operadores de concatenación de cadenas (
JavaScript.
) y suma (+
) separados .Comparación de cadenas
A menudo, en los sistemas informáticos, "5" es mayor que "10" porque no lo interpreta como un número. No es así en PHP, que, incluso si ambas son cadenas, se da cuenta de que son números y elimina la necesidad de un reparto):
JavaScript PHPMecanografía de firma de función
PHP implementa una verificación de tipos básica en las firmas de funciones, pero desafortunadamente es tan defectuosa que probablemente rara vez se pueda usar.
Pensé que podría estar haciendo algo mal, pero un comentario en los documentos confirma que los tipos integrados distintos de la matriz no se pueden usar en las firmas de funciones de PHP, aunque el mensaje de error es engañoso.
PHPY a diferencia de cualquier otro idioma que conozco, incluso si usa un tipo que entiende, nulo ya no se puede pasar a ese argumento (
must be an instance of array, null given
). Que estúpido.Interpretación booleana
[ Editar ]: Este es nuevo. Pensé en otro caso, y nuevamente la lógica se invierte de JavaScript.
JavaScript PHPEn conclusión, el único caso útil que se me ocurre es ... (redoble de batería)
Tipo de truncamiento
En otras palabras, cuando tiene un valor de un tipo (digamos cadena) y quiere interpretarlo como otro tipo (int) y quiere forzarlo a convertirse en uno de los conjuntos de valores válidos en ese tipo:
No puedo ver qué upcasting (para un tipo que abarca más valores) realmente te ganaría.
Entonces, aunque no estoy de acuerdo con su uso propuesto de mecanografía (esencialmente está proponiendo mecanografía estática , pero con la ambigüedad de que solo si se forzara en un tipo arrojaría un error, lo que causaría confusión), creo que es un buen pregunta, porque aparentemente el casting tiene muy poco propósito en PHP.
fuente
E_NOTICE
entonces? :)E_NOTICE
podría estar bien, pero para mí el estado ambiguo es preocupante: ¿cómo podría saber mirando un bit de código si la variable estaba en ese estado (después de haber sido emitida en otro lugar)? Además, encontré otra condición y la agregué a mi respuesta.echo "010" == 010
yecho "0x10" == 0x10
;-)Estás mezclando los conceptos de tipo débil / fuerte y dinámico / estático.
PHP es débil y dinámico, pero su problema es con el concepto de tipo dinámico. Eso significa que las variables no tienen un tipo, los valores sí.
Una 'conversión de tipo' es una expresión que produce un nuevo valor de un tipo diferente del original; no hace nada a la variable (si hay una involucrada).
La única situación en la que escribo regularmente valores de conversión es en parámetros numéricos de SQL. Se supone que debe desinfectar / escapar cualquier valor de entrada que inserte en las instrucciones SQL, o (mucho mejor) usar consultas parametrizadas. Pero, si desea un valor que DEBE ser un número entero, es mucho más fácil simplemente lanzarlo.
Considerar:
Si omitiera la primera línea,
$id
sería un vector fácil para la inyección de SQL. El elenco se asegura de que sea un entero inofensivo; cualquier intento de insertar algo de SQL simplemente resultaría en una consulta paraid=0
fuente
mysql_real_escape_string($id);
ya no lo hace?mysql_real_escape_string()
tiene la vulnerabilidad de no hacer nada a cadenas como '0x01ABCDEF' (es decir, representación hexadecimal de un entero). En algunas codificaciones multibyte (no unicode por suerte), una cadena como esta se puede utilizar para romper la consulta (porque MySQL la evalúa como algo que contiene una cita). Es por eso que nimysql_real_escape_string()
tampocois_int()
es la mejor opción para tratar con valores enteros. La conversión de texto es.Un uso para la conversión de tipos en PHP que he encontrado:
estoy desarrollando una aplicación de Android que realiza solicitudes http a scripts PHP en un servidor para recuperar datos de una base de datos. El script almacena datos en forma de un objeto PHP (o matriz asociativa) y se devuelve como un objeto JSON a la aplicación. Sin el tipo de casting, recibiría algo como esto:
Pero, al usar la conversión de tipo PHP
(int)
en la identificación del usuario al almacenarlo en el objeto PHP, en su lugar obtengo esto devuelto a la aplicación:Luego, cuando el objeto JSON se analiza en la aplicación, me ahorra tener que analizar la identificación a un número entero.
Mira, muy útil.
fuente
Un ejemplo es objetos con un método __toString:
$str = $obj->__toString();
vs$str = (string) $obj;
. Hay mucho menos tipeo en el segundo, y el material adicional es la puntuación, que lleva más tiempo escribir. También creo que es más legible, aunque otros pueden estar en desacuerdo.Otra es hacer una matriz de un solo elemento:
array($item);
vs(array) $item;
. Esto colocará cualquier tipo escalar (entero, recurso, etc.) dentro de una matriz.Alternativamente, si
$item
es un objeto, sus propiedades se convertirán en claves para sus valores. Sin embargo, creo que la conversión de objeto-> matriz es un poco extraña: las propiedades privadas y protegidas son parte de la matriz y se renombraron. Para citar la documentación de PHP : las variables privadas tienen el nombre de la clase antepuesto al nombre de la variable; Las variables protegidas tienen un '*' antepuesto al nombre de la variable.Otro uso es convertir datos GET / POST en tipos apropiados para una base de datos. MySQL puede manejar esto por sí mismo, pero creo que los servidores más compatibles con ANSI podrían rechazar los datos. La razón por la que solo menciono las bases de datos es que en la mayoría de los otros casos, los datos tendrán una operación realizada de acuerdo con su tipo en algún momento (es decir, int / floats generalmente tendrán cálculos realizados en ellos, etc.).
fuente
int
ofloat
se producirá al generar la consulta).(array) $item
es ordenado pero útil?Este guión:
funcionará bien
script.php?tags[]=one
pero fallaráscript.php?tags=one
porque_GET['tags']
devuelve una matriz en el primer caso pero no en el segundo. Dado que el script está escrito para esperar una matriz (y usted tiene menos control sobre la cadena de consulta enviada al script), el problema se puede resolver al emitir adecuadamente el resultado de_GET
:fuente
También se puede usar como un método rápido y sucio para garantizar que los datos no confiables no rompan algo, por ejemplo, si se utiliza un servicio remoto que tiene validación de basura y solo debe aceptar números.
Obviamente, esto es defectuoso y también lo maneja implícitamente el operador de comparación en la instrucción if, pero es útil para garantizar que sepa exactamente lo que está haciendo su código.
fuente
$_POST['amount']
contuviera una cadena de basura, php evaluaría que no fuera mayor que cero. Si contuviera una cadena que representara un número positivo, evaluaría verdadero.Un "uso" de PHP que vuelve a emitir variables sobre la marcha que veo en uso a menudo es cuando se recuperan datos de fuentes externas (entrada del usuario o base de datos). Permite a los codificadores (tenga en cuenta que no dije desarrolladores) ignorar (o incluso no aprender) los diferentes tipos de datos disponibles de diferentes fuentes.
Un codificador (tenga en cuenta que no dije desarrollador) cuyo código heredé y aún mantengo no parece saber que existe una diferencia entre la cadena
"20"
que se devuelve en la$_GET
súper variable, entre la operación entera20 + 20
cuando la agrega a El valor en la base de datos. Ella solo tiene suerte de que PHP use.
para la concatenación de cadenas y no+
como cualquier otro lenguaje, porque he visto su código "agregar" dos cadenas (unavarcahr
de MySQL y un valor de$_GET
) y obtener un int.¿Es este un ejemplo práctico? Solo en el sentido de que permite a los codificadores escapar sin saber con qué tipos de datos están trabajando. Yo personalmente lo odio.
fuente