Есть ли какая-то особая разница между intval и приведением к int - `(int) X`?

219

Есть ли какая-то особая разница между intval и (int)?

Пример:

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

Есть ли какая-то особая разница между двумя строками кода?

Sarfraz
источник

Ответы:

192

intval()может быть передана база для конвертации. (int)не может.

int intval( mixed $var  [, int $base = 10  ] )
янтарный
источник
73
(int) быстрее, чем intval (), согласно wiki.phpbb.com/Best_Practices:PHP
Мартин Тома,
Как я отмечал ниже сегодня, базовое преобразование не работает должным образом, если аргумент является int или float.
t-dub
1
@moose что страница состояния $i++является неправильным в красном цвете. Но это должно быть медленнее!
Шиплу Мокаддим
1
Я никогда не говорил о $i++. Что вы имеете в виду? Когда вы говорите "Но это должно быть медленнее!" что ты сравниваешь?
Мартин Тома
6
Я сделал бенчмаркинг на ideone - typecast (int)быстрее x 2! (int): Ideone.com/QggNGc , intval(): ideone.com/6Y8mPN
jave.web
52

Следует отметить одну вещь, касающуюся разницы между (int)and intval(): intval()обрабатывает переменные, которые уже ints и floats, как не требующие преобразования, независимо от базового аргумента (по крайней мере, в PHP 5.3.5). Это поведение не является наиболее очевидным, как отмечено в комментариях на странице документации по PHP и бесстыдно повторено здесь:

$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?
т-даб
источник
13
Документ говорит : « The base parameter has no effect unless the var parameter is a string.Опять же, страница была обновлена ​​четыре дня назад, так что, возможно, это было добавлено».
Гонки легкости на орбите
6
Очевидно, задокументировано или нет, поведение немного удивительно, учитывая тот факт, что функция теоретически может выполнять базовое преобразование. Это определенно споткнуло меня раньше, но, возможно, мне просто нужно более осторожно RTFM :)
t-dub
7
Я понимаю, что это старая тема, и если вы все еще программируете, то, надеюсь, вы теперь понимаете, почему это на самом деле самый очевидный результат. У int нет базы, потому что base используется только в строковых представлениях. Или, проще говоря, целое число 12 в базе 10 такое же, как целое число 12 в базе 99. Это все еще 12. Ожидание, intval(12,8)которое даст ответ, что при преобразовании в строку без форматирования будет выглядеть как основание 8 номер просто неправильный Чего бы вы ожидали, intval(12,16)потому что он не может сделать int c?
Роберт Макки
1
Или иным способом ... С 1 января 1970 года было зарегистрировано 1523994328 тиков. Запрашивать, хранится ли это как ММ / ДД / ГГГГ или ДД / ММ / ГГГГ, не имеет смысла, поскольку он не сохраняется ни в одном из этих форматов. Он хранится в виде числа, а не в каком-либо конкретном формате даты. Точно так же, как вопрос о том, что является основой int. Отделение значений от формата, в котором они отображаются, очень важно.
Роберт Макки
32

Извините за некроз, я просто хотел посмотреть, повлияет ли / как PHP7 на этот вопрос:

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

Тест:

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"

Как видите, кастинг определенно быстрее, почти на 100%

Но мне пришлось увеличить количество циклов до 100 миллионов, прежде чем разница составила считанные секунды, а в большинстве случаев я начинал заботиться о производительности.

Поэтому я остановлюсь на использовании этой intvalфункции, потому что кастинг - это немного языковой магии, которая происходит. Даже если intvalиспользование кастинга происходит за кулисами, если при кастинге была обнаружена ошибка, и по какой-то причине ее нельзя было исправить (обратная совместимость?), Тогда они могли бы, по крайней мере, исправить ее intvalдля выполнения своих обязанностей.

Обновление (PHP 7.1 + Extra case):

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

Выглядит как 7.1 оптимизирован intval, и «1» + 0 теперь победитель этого конкурса скорости :) я бы до сих пор продолжают использовать в intvalлюбом случае

Populus
источник
1
единственный оставшийся тест - +0это var ... не уверен, что неявное приведение здесь быстрее, чем явное.
SparK
2
LOL @ +0победы ... это очень грязный хак
SparK
@ SparK твоя идея :) Я бы не стал верить этому, хотя правила приведения типов в PHP не совсем лучшие
Populus
Для v5.5.34моих результатов были 9191.0059452057 ms, 23307.397127151 msи 11483.719110489 msсоответственно. Так что до PHP 7 кастинг был самым быстрым.
GreeKatrina
Хотя это гораздо менее понятно, мне нравится, $a = '1' + 0;и я уверен, что большинство из них никогда не думали так делать
mic
26

Я думаю, что есть как минимум одно отличие: с помощью intval вы можете указать, какая база должна использоваться в качестве второго параметра (по умолчанию база 10):

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

получит вас:

int 123
int 123
int 83
Паскаль МАРТИН
источник
11
Я нахожу невероятно забавным, что можно преобразовать базовое число 17 «g» в десятичное:intval("2g", 17) = 50 = 2*17 + 16
JSchaefer
1
@JSchaefer Я взял это еще дальше, и обнаружил, что максимум, который я мог бы передать в качестве базы 36, например, в intval("g", 36) //16. Любое значение больше 36 возвращает 0. Это говорит о том, что мы можем использовать все 0-9 плюс символы z для нашей пользовательской базы, например intval("z",36) //35. Также следует отметить, что первый параметр не учитывает регистр .
Джей Дадхания
17

Одним из полезных свойств intvalявляется то, что - поскольку это функция, а не языковая конструкция - ее можно передать в качестве аргумента функции, которая ожидает функцию. Вы не можете сделать это с (int).

Например, я использовал его для очистки целых чисел для включения в предложение SQL IN(), передав его array_map. Вот пример:

$ids = implode(",", array_map('intval', $_POST['array_of_integers']));
$sql = "SELECT * FROM table WHERE ids IN ($ids)";
Кодос Джонсон
источник
анонимная функция в качестве обратного вызова:array_map(function($n){return (int)$n;}, $_POST['array_of_integers'])
Даниэль Омин
@DanielOmine Я имел в виду, что вы можете использовать его без определения функции обратного вызова.
Кодос Джонсон
15

Янтарь прав, и если я могу добавить полезную информацию, приведение типов (добавление "(int)" перед вашим выражением) будет на 300-600% быстрее, чем intval. Поэтому, если ваша цель не в том, чтобы иметь дело с другими основаниями, кроме десятичной, я рекомендую использовать: (int) $something

user900469
источник
2
Что-то, что вы могли бы найти интересным: programmers.stackexchange.com/questions/99445/…
Джерри
8

То, что intvalделает то , чего не делает простое приведение, - это базовое преобразование:

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

Если основание равно 10, то оно intvalдолжно совпадать с приведением (если только вы не будете придирчивы и упомяните, что один выполняет вызов функции, а другой нет). Как отмечено на странице руководства :

Применяются общие правила целочисленного приведения.

децезе
источник