Existe-t-il une différence particulière entre intval et transtypage en int - `(int) X`?

219

Y a-t-il une différence particulière entre intval et (int)?

Exemple:

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

Y a-t-il une différence particulière entre les deux lignes de code ci-dessus?

Sarfraz
la source

Réponses:

192

intval()peut être passé une base à partir de laquelle convertir. (int)ne peux pas.

int intval( mixed $var  [, int $base = 10  ] )
ambre
la source
73
(int) est plus rapide que intval (), selon wiki.phpbb.com/Best_Practices:PHP
Martin Thoma
Comme je l'ai noté ci-dessous plus tôt aujourd'hui, la conversion de base ne fonctionne pas comme prévu si l'argument est un entier ou un flottant.
t-dub
1
@moose que l'état de la page $i++est incorrect en rouge. Mais ça devrait être plus lent !!
Shiplu Mokaddim
1
Je n'en ai jamais parlé $i++. Que voulez-vous dire? Quand vous dites "Mais ça devrait être plus lent !!" que comparez-vous?
Martin Thoma
6
J'ai fait une analyse comparative sur ideone - le transtypage (int)est plus rapide x 2! (int): Ideone.com/QggNGc , intval(): ideone.com/6Y8mPN
jave.web
52

Une chose à noter sur la différence entre (int)et intval(): intval()traite les variables qui sont déjà ints et floats comme ne nécessitant aucune conversion, quel que soit l'argument de base (à partir de PHP 5.3.5 au moins). Ce comportement n'est pas le plus évident, comme indiqué dans les commentaires sur la page de documentation PHP et répété sans vergogne ici:

$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
la source
13
Le doc ne dit The base parameter has no effect unless the var parameter is a string.ensuite à nouveau la page a été apparemment mis à jour il y a quatre jours, alors peut - être que ce qui a été ajouté.
Courses de légèreté en orbite le
3
Hmm, non. Cela a été largement documenté pendant près de 11 ans .
Courses de légèreté en orbite le
6
Bien documenté ou non, le comportement est un peu surprenant étant donné que la fonction peut théoriquement faire une conversion de base. Cela m'a définitivement fait trébucher avant, mais j'ai peut-être juste besoin de RTFM un peu plus attentivement :)
t-dub
7
Je me rends compte que c'est un vieux fil, et si vous êtes toujours en train de programmer, alors j'espère que vous voyez maintenant pourquoi c'est le résultat le plus évident. Un int n'a pas de base car la base n'est utilisée que dans les représentations sous forme de chaîne. Ou plus simplement, un entier de 12 dans la base 10 est identique à un entier de 12 dans la base 99. C'est toujours 12. L'attente qui intval(12,8)donnerait une réponse qui, une fois convertie en chaîne sans formatage, ressemblerait à une base 8 le numéro est tout simplement faux. Qu'attendriez-vous de intval(12,16)parce qu'il ne peut pas faire un int a c?
Robert McKee
1
Ou d'une autre manière ... Il y a eu 1523994328 ticks depuis le 1er janvier 1970. Demander si cela est stocké sous MM / DD / YYYY ou DD / MM / YYYY n'a aucun sens car il n'est stocké dans aucun de ces formats. Il est stocké sous forme de nombre, pas dans un format de date particulier. De la même manière que de demander quelle est la base d'un int. Il est très important de séparer les valeurs du format dans lequel elles sont affichées.
Robert McKee
32

Désolé pour le necroing, je voulais juste voir si / comment PHP7 a un effet sur cette question:

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

Le test:

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"

Comme vous pouvez le voir, le casting est nettement plus rapide, de près de 100%

Mais j'ai dû augmenter le nombre de boucles à 100 millions avant que la différence ne soit une question de secondes, c'est-à-dire quand je commencerais à me soucier des performances, dans la plupart des cas.

Je vais donc continuer à utiliser la intvalfonction, car le casting est un peu la magie du langage qui se produit. Même si le intvalcasting est utilisé dans les coulisses, s'il devait y avoir un bug trouvé avec le casting, et pour une raison quelconque, il ne pouvait pas être corrigé (compatibilité descendante?), Alors ils pourraient au moins le corriger intvalpour accomplir son devoir.

Mise à jour (PHP 7.1 + cas supplémentaire):

$ 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"

On dirait que 7.1 optimisé intval, et '1' + 0 est maintenant le gagnant de ce concours de vitesse :) Je continuerais à utiliser intvalquand même

Populus
la source
1
la seule référence restante est pour +0la var ... je ne sais pas si la conversion implicite ici est plus rapide que la conversion explicite.
SparK
2
LOL @ +0gagnant ... c'est un hack très sale
SparK
@SparK votre idée :) Je ne lui ferais pas confiance cependant, les règles de casting de type PHP ne sont pas exactement les meilleures
Populus
Pour v5.5.34mes résultats ont été 9191.0059452057 ms, 23307.397127151 mset 11483.719110489 msrespectivement. Donc, avant PHP 7, le casting est le plus rapide.
GreeKatrina
Bien que ce soit beaucoup moins compréhensible, j'aime bien $a = '1' + 0;et je parie que la plupart n'ont jamais pensé à le faire comme ça
micro
26

Je pense qu'il y a au moins une différence: avec intval , vous pouvez spécifier quelle base doit être utilisée comme deuxième paramètre (base 10 par défaut):

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

vous obtiendrez:

int 123
int 123
int 83
Pascal MARTIN
la source
11
Je trouve incroyablement amusant que l'on puisse convertir le nombre de base "g" en décimal:intval("2g", 17) = 50 = 2*17 + 16
JSchaefer
1
@JSchaefer Je suis allé encore plus loin et j'ai constaté que le maximum que je pouvais passer comme base était 36, comme dans intval("g", 36) //16. Toute valeur supérieure à 36 renvoie 0. Cela suggère que nous pouvons utiliser tous les caractères 0-9 plus az pour notre base personnalisée, tels que intval("z",36) //35. Il convient également de noter que le premier paramètre est insensible à la casse .
Jay Dadhania du
17

Une propriété utile de intvalest que - puisqu'il s'agit d'une fonction et non d'une construction de langage - il peut être passé comme argument à une fonction qui attend une fonction. Vous ne pouvez pas faire ça avec (int).

Par exemple, je l'ai utilisé pour filtrer les entiers à inclure dans une IN()clause SQL en la passant à array_map. Voici un exemple:

$ids = implode(",", array_map('intval', $_POST['array_of_integers']));
$sql = "SELECT * FROM table WHERE ids IN ($ids)";
Kodos Johnson
la source
fonction anonyme en tant que rappel:array_map(function($n){return (int)$n;}, $_POST['array_of_integers'])
Daniel Omine
@DanielOmine Je voulais dire que vous pouvez l'utiliser sans avoir à définir la fonction de rappel.
Kodos Johnson
15

Amber a raison et si je peux ajouter un casting de type d'information utile (ajouter un "(int)" avant votre expression) est 300 à 600% plus rapide qu'intval. Donc, si votre but n'est pas de traiter avec d'autres bases que décimales, je recommande d'utiliser: (int) $something

user900469
la source
2
Quelque chose que vous pourriez trouver intéressant: programmers.stackexchange.com/questions/99445/…
Gerry
8

Ce qui intvalne fait pas une conversion simple, c'est la conversion de base:

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

Si la base est 10 cependant, cela intvaldevrait être la même chose qu'un casting (sauf si vous allez être un peu nerveux et mentionner que l'un fait un appel de fonction tandis que l'autre ne le fait pas). Comme indiqué sur la page de manuel :

Les règles communes de la conversion d'entiers s'appliquent.

décomposer
la source