Existe alguma diferença particular entre intval e casting para int - `(int) X`?

219

Existe alguma diferença em particular entre intval e (int)?

Exemplo:

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

Existe alguma diferença específica entre as duas linhas de código acima?

Sarfraz
fonte

Respostas:

192

intval()pode ser passada uma base a partir da qual converter. (int)não podes.

int intval( mixed $var  [, int $base = 10  ] )
Âmbar
fonte
73
(int) é mais rápido que intval (), de acordo com wiki.phpbb.com/Best_Practices:PHP
Martin Thoma
Como observei abaixo hoje, a conversão base não funcionará conforme o esperado se o argumento for int ou float.
t-dub
1
@moose que os estados da página $i++estão incorretos em vermelho. Mas deve ser mais lento !!
Shiplu Mokaddim
1
Eu nunca falei disso $i++. O que você quer dizer? Quando você diz "Mas deve ser mais lento !!" o que você compara?
Martin Thoma
6
Fiz benchmarking em ideone - (int)typecast é mais rápido x 2! (int): Ideone.com/QggNGc , intval(): ideone.com/6Y8mPN
jave.web
52

Uma coisa a ser observada sobre a diferença entre (int)e intval(): intval()trata as variáveis ​​que já são intes e floatnão precisam de conversão, independentemente do argumento base (pelo menos no PHP 5.3.5). Esse comportamento não é o mais óbvio, conforme observado nos comentários na página de documentos PHP e reiteradamente descaradamente reiterado aqui:

$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
fonte
13
O doc não dizer The base parameter has no effect unless the var parameter is a string.Então, novamente a página foi aparentemente atualizados há quatro dias, então talvez isso é o que foi adicionado.
Lightness Races em órbita
3
Hmm, não. Isso foi documentado de maneira proeminente por quase 11 anos .
Lightness Races em órbita
6
De forma proeminente documentada ou não, o comportamento é um pouco surpreendente, dado que a função teoricamente pode fazer a conversão básica. Ele definitivamente me tropeçar antes, mas talvez eu só preciso RTFM um pouco mais de cuidado :)
t-dub
7
Sei que esse é um encadeamento antigo e, se você ainda está programando, espero que agora veja por que esse é realmente o resultado mais óbvio. Um int não tem base porque base é usada apenas em representações de string. Ou, mais simplesmente, um int de 12 na base 10 é o mesmo que um int de 12 na base 99. Ainda é 12. A expectativa que intval(12,8)daria uma resposta que, quando convertida em uma string sem formatação, pareceria uma base 8 número está errado. O que você esperaria, intval(12,16)porque não pode fazer um int a c?
Robert McKee
1
Ou de outra maneira ... Existem 1523994328 ticks desde 1º de janeiro de 1970. Perguntar se isso está armazenado como MM / DD / AAAA ou DD / MM / AAAA não faz sentido porque não está armazenado em nenhum desses formatos. Ele é armazenado como um número, não em nenhum formato de data específico. Da mesma maneira que perguntar qual é a base de um int. Separar valores do formato em que são exibidos é muito importante.
Robert McKee
32

Desculpe por necroing, eu só queria ver se / como o PHP7 afeta esta questão:

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

O teste:

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 você pode ver, a transmissão é definitivamente mais rápida, em quase 100%

Mas tive que aumentar a contagem de loop para 100 milhões antes que a diferença fosse uma questão de segundos, que é quando eu realmente começaria a me preocupar com o desempenho, na maioria dos casos.

Então, continuarei usando a intvalfunção, porque a transmissão é um pouco de mágica da linguagem que está acontecendo. Mesmo que intvaluse vazamento nos bastidores, se houvesse um erro encontrado no vazamento e, por algum motivo, ele não pudesse ser corrigido (compatibilidade com versões anteriores?), Eles poderiam pelo menos consertar intvalpara executar seu dever.

Atualização (caso PHP 7.1 + Extra):

$ 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 otimizado intval, e '1' + 0 agora é o vencedor deste concurso de velocidade :) Eu continuaria usando intvalmesmo assim

Populus
fonte
1
a única referência que resta é +0a var ... não tenho certeza se o elenco implícito aqui é mais rápido que o explícito.
SparK 02/12/19
2
LOL @ +0ganhar ... isso é um truque muito sujo
SparK
@SparK sua ideia :) Eu não confiaria ele, porém, tipo do PHP lançando regras não são exatamente o melhor
Populus
Para v5.5.34os meus resultados foram 9191.0059452057 ms, 23307.397127151 mse 11483.719110489 msrespectivamente. Portanto, antes do PHP 7, a transmissão é a mais rápida.
GreeKatrina
Embora seja muito menos compreensível, eu gosto $a = '1' + 0;e aposto que a maioria nunca pensou em fazê-lo dessa maneira
Mic
26

Eu acho que há pelo menos uma diferença: com intval , você pode especificar qual base deve ser usada como um segundo parâmetro (base 10 por padrão):

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

você receberá:

int 123
int 123
int 83
Pascal MARTIN
fonte
11
Acho incrivelmente divertido que se possa converter o número base 17 "g" em decimal:intval("2g", 17) = 50 = 2*17 + 16
JSchaefer
1
@JSchaefer Eu levei ainda mais longe e descobri que o máximo que eu poderia passar como base é 36, como em intval("g", 36) //16. Qualquer valor maior que 36 retorna 0. Isso sugere que podemos usar todos os caracteres 0-9 mais az para nossa base personalizada, como intval("z",36) //35. Além disso, deve-se notar que o primeiro parâmetro não diferencia maiúsculas de minúsculas .
Jay Dadhania 03/12/19
17

Uma propriedade útil de intvalé que - como é uma função e não uma construção de linguagem - pode ser passada como argumento para uma função que espera uma função. Você não pode fazer isso com (int).

Por exemplo, eu o usei para higienizar números inteiros para inclusão em uma IN()cláusula SQL passando-a para array_map. Aqui está um exemplo:

$ids = implode(",", array_map('intval', $_POST['array_of_integers']));
$sql = "SELECT * FROM table WHERE ids IN ($ids)";
Kodos Johnson
fonte
função anônima como retorno de chamada:array_map(function($n){return (int)$n;}, $_POST['array_of_integers'])
Daniel Omine 5/10
@DanielOmine, quis dizer que você pode usá-lo sem ter que definir a função de retorno de chamada.
Kodo Johnson
15

Âmbar está certo e, se eu puder adicionar uma conversão de tipo de informação útil (adicionar um "(int)" antes da sua expressão) é 300 a 600% mais rápida que intval. Portanto, se seu objetivo não é lidar com outras bases que não sejam decimais, recomendo usar: (int) $something

user900469
fonte
2
Algo que você pode achar interessante: programmers.stackexchange.com/questions/99445/…
Gerry
8

O intvalque uma simples conversão não faz é a conversão básica:

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

Se a base for 10, no entanto, intvaldeve ser a mesma que o elenco (a menos que você seja exigente e mencione que um faz uma chamada de função enquanto o outro não). Conforme observado na página do manual :

As regras comuns de conversão de números inteiros se aplicam.

deceze
fonte