¿Hay alguna diferencia particular entre intval y casting a int - `(int) X`?

219

¿Hay alguna diferencia particular entre intval y (int)?

Ejemplo:

$product_id = intval($_GET['pid']);
$product_id = (int) $_GET['pid'];

¿Hay alguna diferencia particular entre las dos líneas de código anteriores?

Sarfraz
fuente

Respuestas:

192

intval()Se puede pasar una base desde la cual convertir. (int)no puedo.

int intval( mixed $var  [, int $base = 10  ] )
Ámbar
fuente
73
(int) es más rápido que intval (), de acuerdo con wiki.phpbb.com/Best_Practices:PHP
Martin Thoma
Como señalé a continuación hoy, la conversión de base no funciona como se esperaba si el argumento es int o float.
t-dub
1
@moose que los estados de página $i++son incorrectos en rojo. ¡Pero debería ser más lento!
Shiplu Mokaddim
1
Nunca hablé de eso $i++. ¿Qué quieres decir? Cuando dices "¡Pero debería ser más lento!" que comparas
Martin Thoma
66
Hice una evaluación comparativa en ideone: ¡la (int)conversión de texto es más rápida x 2! (int): Ideone.com/QggNGc , intval(): ideone.com/6Y8mPN
jave.web
52

Una cosa a tener en cuenta sobre la diferencia entre (int)y intval(): intval()trata las variables que ya son ints y floats que no necesitan conversión, independientemente del argumento base (al menos a partir de PHP 5.3.5). Este comportamiento no es el más obvio, como se señala en los comentarios en la página de documentación de PHP y se lo reitera descaradamente aquí:

$test_int    = 12;
$test_string = "12";
$test_float  = 12.8;

echo (int) $test_int;         // 12
echo (int) $test_string;      // 12
echo (int) $test_float;       // 12

echo intval($test_int, 8);    // 12 <-- WOAH!
echo intval($test_string, 8); // 10
echo intval($test_float, 8)   // 12 <-- HUH?
t-dub
fuente
13
El documento no dice The base parameter has no effect unless the var parameter is a string.otra parte de la página se actualiza al parecer, hace cuatro días, así que quizás eso es lo que se añadió.
ligereza corre en órbita
66
Destacadamente documentado o no, el comportamiento es un poco sorprendente dado el hecho de que la función teóricamente puede hacer conversión de base. Definitivamente me hizo tropezar antes, pero tal vez solo necesito RTFM un poco más cuidadosamente :)
t-dub
77
Me doy cuenta de que este es un hilo viejo, y si todavía está programando, espero que ahora vea por qué este es realmente el resultado más obvio. Un int no tiene base porque la base solo se usa en representaciones de cadenas. O más simplemente, un int de 12 en la base 10 es lo mismo que un int de 12 en la base 99. Todavía es 12. La expectativa que intval(12,8)daría una respuesta que cuando se convierte en una cadena sin formato se vería como una base 8 El número está mal. ¿Qué esperarías de intval(12,16)porque no puede hacer una int a c?
Robert McKee
1
O de otra manera ... Ha habido 1523994328 ticks desde el 1 de enero de 1970. Preguntar si eso está almacenado como MM / DD / AAAA o DD / MM / AAAA no tiene sentido porque no está almacenado en ninguno de esos formatos. Se almacena como un número, no en ningún formato de fecha en particular. De la misma manera que preguntar cuál es la base de un int. Separar los valores del formato en que se muestran es bastante importante.
Robert McKee
32

Perdón por necroing, solo quería ver si PHP7 tiene un efecto sobre esta pregunta:

$ php -v
PHP 7.0.4-5+deb.sury.org~trusty+1 (cli) ( NTS )

La prueba:

php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = (int) '1'; } var_dump((microtime(true) - $start_ts)*1000 . ' ms');
string(18) "3279.1121006012 ms"
php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = intval('1'); } var_dump((microtime(true) - $start_ts)*1000 . ' ms');
string(18) "5379.3351650238 ms"

Como puede ver, el lanzamiento es definitivamente más rápido, en casi un 100%

Pero tuve que aumentar el conteo de bucles a 100 millones antes de que la diferencia fuera cuestión de segundos, que es aproximadamente cuando realmente comenzaría a preocuparme por el rendimiento, en la mayoría de los casos.

Así que me quedaré con el uso de la intvalfunción, porque el casting es un poco de magia de lenguaje que está sucediendo. Incluso si intvalusa el casting detrás de escena, si se encontrara un error con el casting, y por alguna razón no se puede solucionar (¿compatibilidad hacia atrás?), Entonces al menos podrían solucionarlo intvalpara cumplir con su deber.

Actualización (PHP 7.1 + caso adicional):

$ php -v
PHP 7.1.0RC6 (cli) (built: Nov  9 2016 04:45:59) ( NTS )
$ php -a
php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = (int) '1'; } var_dump((microtime(true) - $start_ts)*1000 . ' ms');
string(18) "3583.9052200317 ms"
php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = intval('1'); } var_dump((microtime(true) - $start_ts)*1000 . ' ms');
string(18) "3569.0960884094 ms"
php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = '1' + 0; } var_dump((microtime(true) - $start_ts)*1000 . ' ms');
string(18) "1641.7920589447 ms"

Parece 7.1 optimizado intval, y '1' + 0 ahora es el ganador de este concurso de velocidad :) Todavía seguiría usando de intvaltodos modos

Populus
fuente
1
el único punto de referencia que queda es +0el var ... no estoy seguro si el lanzamiento implícito aquí es más rápido que el explícito.
SparK
2
LOL @ +0ganador ... ese es un truco muy sucio
SparK
@SparK su idea :) Sin embargo, no confiaría en él, las reglas de conversión de tipo de PHP no son exactamente las mejores
Populus
Para v5.5.34mis resultados fueron 9191.0059452057 ms, 23307.397127151 msy 11483.719110489 msrespectivamente. Entonces, antes de PHP 7, el casting es el más rápido.
GreeKatrina
Aunque es mucho menos comprensible, me gusta $a = '1' + 0;y apuesto a que nunca pensé en hacerlo así
micrófono
26

Creo que hay al menos una diferencia: con intval , puede especificar qué base debe usarse como segundo parámetro (base 10 por defecto):

var_dump((int)"0123", intval("0123"), intval("0123", 8));

te conseguirá:

int 123
int 123
int 83
Pascal MARTIN
fuente
11
Me parece increíblemente divertido que uno pueda convertir el número 17 de base "g" en decimal:intval("2g", 17) = 50 = 2*17 + 16
JSchaefer
1
@JSchaefer Lo llevé aún más lejos, y descubrí que lo máximo que podía pasar como base es 36, como en intval("g", 36) //16. Cualquier valor mayor que 36 devuelve 0. Eso sugiere que podemos usar todos los caracteres 0-9 más az para nuestra base personalizada, como intval("z",36) //35. Además, debe tenerse en cuenta que el primer parámetro no distingue entre mayúsculas y minúsculas .
Jay Dadhania
17

Una propiedad útil de intvales que, dado que es una función y no una construcción de lenguaje, se puede pasar como argumento a una función que espera una función. No puedes hacer esto con (int).

Por ejemplo, lo he usado para desinfectar enteros para su inclusión en una IN()cláusula SQL pasándolo a array_map. Aquí hay un ejemplo:

$ids = implode(",", array_map('intval', $_POST['array_of_integers']));
$sql = "SELECT * FROM table WHERE ids IN ($ids)";
Kodos Johnson
fuente
función anónima como devolución de llamada:array_map(function($n){return (int)$n;}, $_POST['array_of_integers'])
Daniel Omine
@DanielOmine Quise decir que puede usarlo sin tener que definir la función de devolución de llamada.
Kodos Johnson
15

Amber tiene razón y si puedo agregar un tipo de información útil (agregar un "(int)" antes de su expresión) es 300 a 600% más rápido que intval. Entonces, si su propósito no es tratar con otras bases que no sean decimales, le recomiendo usar: (int) $something

usuario900469
fuente
2
Algo que puede encontrar interesante: programmers.stackexchange.com/questions/99445/…
Gerry
8

Lo que intvalhace que un elenco simple no lo haga es la conversión de base:

int intval ( mixed $var [, int $base = 10 ] )

Sin embargo, si la base es 10, intvaldebería ser lo mismo que un elenco (a menos que seas quisquilloso y mencione que uno realiza una llamada a la función mientras que el otro no). Como se señala en la página del manual :

Se aplican las reglas comunes de conversión de enteros.

difunto
fuente