Czy jest jakaś szczególna różnica między intvalem a rzutowaniem na int - `(int) X`?

219

Czy jest jakaś szczególna różnica między intval a (int)?

Przykład:

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

Czy jest jakaś szczególna różnica między powyższymi dwoma wierszami kodu?

Sarfraz
źródło

Odpowiedzi:

192

intval()można przekazać bazę, z której można dokonać konwersji. (int)Nie mogę.

int intval( mixed $var  [, int $base = 10  ] )
Bursztyn
źródło
73
(int) jest szybszy niż intval (), zgodnie z wiki.phpbb.com/Best_Practices:PHP
Martin Thoma
Jak zauważyłem dzisiaj wcześniej, konwersja podstawowa nie działa zgodnie z oczekiwaniami, jeśli argument jest liczbą całkowitą lub zmiennoprzecinkową.
t-dub
1
@moose twierdzi, że strona $i++ma niepoprawny czerwony kolor. Ale powinno być wolniejsze !!
Shiplu Mokaddim
1
Nigdy o tym nie mówiłem $i++. Co masz na myśli? Kiedy mówisz „Ale powinno być wolniej !!” co porównujesz
Martin Thoma,
6
Przeprowadziłem testy porównawcze na ideone - (int)typecast jest szybszy x 2! (int): Ideone.com/QggNGc , intval(): ideone.com/6Y8mPN
jave.web
52

Jedną rzeczą, aby pamiętać o różnicy między (int)i intval(): intval()traktuje zmienne, które są już intS i floatS, która nie wymaga konwersji, niezależnie od argumentu podstawowego (od PHP 5.3.5 przynajmniej). To zachowanie nie jest najbardziej oczywiste, jak zauważono w komentarzach na stronie dokumentu PHP i bezwstydnie powtórzono tutaj:

$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
źródło
13
Doc nie powiedzieć The base parameter has no effect unless the var parameter is a string.Potem znowu strona została zaktualizowana widocznie cztery dni temu, więc być może to właśnie został dodany.
Wyścigi lekkości na orbicie
3
Hmm, nie. Zostało to wyraźnie udokumentowane przez prawie 11 lat .
Wyścigi lekkości na orbicie
6
Wyraźnie udokumentowane lub nie, zachowanie jest nieco zaskakujące, biorąc pod uwagę fakt, że funkcja teoretycznie może dokonać konwersji bazy. Zdecydowanie wcześniej mnie to potknęło, ale być może muszę trochę bardziej ostrożnie RTFM :)
t-dub
7
Zdaję sobie sprawę, że to stary wątek, a jeśli nadal programujesz, mam nadzieję, że teraz rozumiesz, dlaczego jest to w rzeczywistości najbardziej oczywisty wynik. Int nie ma podstawy, ponieważ podstawa jest używana tylko w reprezentacjach łańcuchowych. Lub prościej, liczba całkowita 12 w bazie 10 jest taka sama jak liczba całkowita 12 w bazie 99. To wciąż 12. Oczekiwanie, intval(12,8)które dałoby odpowiedź, że po przekształceniu w ciąg bez formatowania wyglądałoby jak podstawa 8 numer jest po prostu zły. Czego można oczekiwać, intval(12,16)ponieważ nie może zrobić int c?
Robert McKee,
1
Lub inny sposób ... Od 1 stycznia 1970 r. Zarejestrowano 1523994328 tyknięć. Pytanie, czy jest ono przechowywane jako MM / DD / RRRR lub DD / MM / RRRR, nie ma sensu, ponieważ nie jest przechowywane w żadnym z tych formatów. Jest przechowywany jako liczba, a nie w określonym formacie daty. Ten sam sposób, w jaki pyta się, jaka jest podstawa int. Oddzielenie wartości od formatu, w jakim są wyświetlane, jest bardzo ważne.
Robert McKee,
32

Przepraszam za nekrozę, chciałem tylko sprawdzić, czy / jak PHP7 ma wpływ na to pytanie:

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

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"

Jak widać casting jest zdecydowanie szybszy, o prawie 100%

Ale musiałem zwiększyć liczbę pętli do 100 milionów, zanim różnica była kwestią sekund, czyli w większości przypadków zacząłem dbać o wydajność.

Dlatego pozostanę przy użyciu tej intvalfunkcji, ponieważ casting to trochę magii języka, która się dzieje. Nawet jeśli intvalużywa rzutowania za kulisami, jeśli miałby zostać wykryty błąd podczas rzutowania i z jakiegoś powodu nie można go naprawić (kompatybilność wsteczna?), To mogliby przynajmniej naprawić, intvalaby wykonać swój obowiązek.

Aktualizacja (PHP 7.1 + dodatkowa skrzynka):

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

Wygląda 7.1 zoptymalizowany intvali „1” + 0 jest zwycięzcą tego konkursu prędkości :) ja nadal zachować stosując intvalw każdym razie

Populus
źródło
1
jedynym testem, który pozostał, jest +0var ... nie jestem pewien, czy ukryta obsada jest szybsza niż jawna.
SparK,
2
LOL @ +0wygrywa ... to bardzo brudny hack
SparK
@SparK twój pomysł :) Nie ufałbym jednak, reguły rzutowania PHP nie są najlepsze
Populus
Na v5.5.34moje wyniki były 9191.0059452057 ms, 23307.397127151 msi 11483.719110489 msodpowiednio. Tak więc przed PHP 7 casting jest najszybszy.
GreeKatrina
Chociaż podoba mi się to znacznie mniej zrozumiałe $a = '1' + 0;i założę się, że większość nigdy nie myślała o zrobieniu tego w ten sposób
mic
26

Wydaje mi się, że istnieje co najmniej jedna różnica: za pomocą parametru intval można określić, która podstawa powinna być użyta jako drugi parametr (domyślnie podstawa 10):

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

dostanie cię:

int 123
int 123
int 83
Pascal MARTIN
źródło
11
Uważam za niezwykle zabawne, że można przekonwertować podstawową liczbę 17 „g” na dziesiętną:intval("2g", 17) = 50 = 2*17 + 16
JSchaefer
1
@JSchaefer poszedłem jeszcze dalej i odkryłem, że maksimum, które mogę przekazać jako podstawa 36, takie jak w intval("g", 36) //16. Każda wartość większa niż 36 zwraca 0. To sugeruje, że możemy użyć wszystkich znaków 0-9 plus az dla naszej niestandardowej bazy, np intval("z",36) //35. Należy również zauważyć, że w pierwszym parametrze nie jest rozróżniana wielkość liter .
Jay Dadhania,
17

Jedną użyteczną właściwością intvaljest to, że - ponieważ jest to funkcja, a nie konstrukcja języka - może być przekazana jako argument funkcji, która oczekuje funkcji. Nie możesz tego zrobić (int).

Na przykład użyłem go do oczyszczenia liczb całkowitych w celu włączenia do IN()klauzuli SQL , przekazując ją do array_map. Oto przykład:

$ids = implode(",", array_map('intval', $_POST['array_of_integers']));
$sql = "SELECT * FROM table WHERE ids IN ($ids)";
Kodos Johnson
źródło
funkcja anonimowa jako oddzwanianie:array_map(function($n){return (int)$n;}, $_POST['array_of_integers'])
Daniel Omine
@DanielOmine Miałem na myśli, że możesz z niego korzystać bez konieczności definiowania funkcji zwrotnej.
Kodos Johnson,
15

Bursztyn ma rację i jeśli mogę dodać przydatne rzutowanie typu informacji (dodanie „(int)” przed wyrażeniem) jest od 300 do 600% szybsze niż intval. Więc jeśli twoim celem nie jest zajmowanie się innymi bazami niż dziesiętne, polecam użycie: (int) $something

użytkownik900469
źródło
2
Coś, co może Cię zainteresować: programmers.stackexchange.com/questions/99445/...
Gerry
8

Rzeczą, która intvalpowoduje, że zwykły rzut nie jest, jest konwersja bazy:

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

Jeśli baza ma 10, to intvalpowinna być taka sama jak obsada (chyba że będziesz podejrzany i wspominasz, że jedno wywołuje funkcję, a drugie nie). Jak wspomniano na stronie podręcznika :

Obowiązują wspólne zasady rzutowania liczb całkowitych.

deceze
źródło