273

Is there any particular difference between intval and (int)?

Example:

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

Is there any particular difference between above two lines of code?

Vladislav Rastrusny
  • 29,378
  • 23
  • 95
  • 156
Sarfraz
  • 377,238
  • 77
  • 533
  • 578

7 Answers7

232

intval() can be passed a base from which to convert. (int) cannot.

int intval( mixed $var  [, int $base = 10  ] )
Amber
  • 507,862
  • 82
  • 626
  • 550
  • 91
    (int) is faster than intval(), according to http://wiki.phpbb.com/Best_Practices:PHP – Martin Thoma Sep 01 '11 at 11:33
  • As I [noted below](http://stackoverflow.com/questions/1912599/php-is-there-any-particular-difference-between-intval-and-int/7825297#7825297) earlier today, the base conversion does not work as expected if the argument is an int or float. – t-dub Oct 20 '11 at 04:23
  • 2
    @moose that page states `$i++` is **incorrect** in red. But it should be slower!! – Shiplu Mokaddim Feb 26 '12 at 01:09
  • 1
    I never spoke of `$i++`. What do you mean? When you say "But it should be slower!!" what do you compare? – Martin Thoma Feb 26 '12 at 16:51
  • 10
    I did benchmarking on ideone - **`(int)` typecast is faster x 2 !** `(int)`:http://ideone.com/QggNGc , `intval()`:http://ideone.com/6Y8mPN – jave.web Aug 12 '14 at 18:32
  • @shiplu.mokadd.im **slower but *same result* ~= incorrect** ... btw be aware of using `++` somewhere else just because of the performance: `++` *before* or *after* `$var` says whether to do the incrementation *before* or *after* evaluation of the command. However in PHP `for()` loop the "loop incrementation"(`for(...$i++/++$i)`) always happens at the end... checkout this test: http://ideone.com/obQjZm – jave.web Aug 12 '14 at 18:37
  • My quick tests show that intval() is averagely 1.5 times slower than (int). But that is not so big deal as it appears 0.5ms vs 0.8ms for 1000 calls. – Anton Mitsev Nov 06 '15 at 13:35
  • @jave.web I've replicated the example on my side - and results practically identical (up to 3 digits after floating point) – Roman S Nov 07 '20 at 17:12
  • @RomanS please be more specific on exact numbers and units :) I'm guessing you're confirming my test? – jave.web Nov 07 '20 at 20:10
  • @jave.web, yes, I sligtly modified your test and cehcked it on MacOS (PHP 7.2 and 7.3) and Ubuntu (PHP 7.2). I was not enough clear in my first comment. I got less than 10% difference between (int) and intval() in average. (int) works bit faster on macos and bit slower on Ubuntu https://ideone.com/ck06aK – Roman S Nov 16 '20 at 20:41
  • @RomanS that's very interesting info considering they're both unix-like, I wonder if the difference is also between linux distros – jave.web Nov 17 '20 at 19:08
  • @jave-web your test was incorrect, performance of both is equal [https://ideone.com/1gZFva](https://ideone.com/1gZFva) – a55 Dec 05 '20 at 11:34
  • Hey, It seems that intval is faster that int casting: Intval: https://3v4l.org/1lO0R#v7.4.28 Takes ~8ms (Complexity: 5) Int: https://3v4l.org/4HVK5#v7.4.28 Takes ~10ms (Complexity: 14) It's important to perform benchmarks with PHP. – Juan Lago Mar 23 '22 at 12:32
  • For PHP 8.1, (int) type casting can generate the following notice while an integer is expected but float is provided. `Deprecated: Implicit conversion from float (float_number) to int loses precision in Standard input code` but intval will not generate this notice . – Azhar Dec 02 '22 at 13:34
62

One thing to note about the difference between (int) and intval(): intval() treats variables which are already ints and floats as needing no conversion, regardless of the base argument (as of PHP 5.3.5 at least). This behavior isn't the most obvious, as noted in the comments on the PHP doc page and shamelessly reiterated here:

$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
  • 812
  • 6
  • 6
  • 19
    The doc _does_ say `The base parameter has no effect unless the var parameter is a string.` Then again the page was apparently updated four days ago, so perhaps that's what was added. – Lightness Races in Orbit Feb 07 '12 at 11:38
  • 3
    Hmm, nope. [This has been prominently documented for almost 11 years](https://bugs.php.net/bug.php?id=7878). – Lightness Races in Orbit Feb 07 '12 at 11:40
  • 8
    Prominently documented or not, the behavior is a little surprising given the fact that the function theoretically can do base conversion. It definitely tripped me up before, but perhaps I just need to RTFM a bit more carefully :) – t-dub Feb 10 '12 at 17:07
  • 15
    I realize this is an old thread, and if you are still programming, then I hope you now see why this is actually the most obvious result. An int has no base because base is only used in string representations. Or more simply, an int of 12 in base 10 is the same as an int of 12 in base 99. It is still 12. The expectation that `intval(12,8)` would give an answer that when converted to a string with no formatting would look like a base 8 number is just wrong. What would you expect from `intval(12,16)` because it can't make an int a `c`? – Robert McKee Dec 22 '16 at 17:54
  • It may be helpful to people puzzled by this to consider what the output should be if `test_int` is instead assigned a value from the list `99 - 87`, `014`, `0xC`, and `0b1100`. In all cases, it is stored as the bits 1100, and the formatting of the constant is not saved. Converting this integer bit-string to an integer using any base should result in the same integer, with bits of 1100. It should not give some different integer. – Dewi Morgan Mar 19 '18 at 16:30
  • @RobertMcKee, I don't think it's right to say an int has no base.... Would you agree that it would be more accurate to say that ints by default display in base 10? I would guess the computer actually uses base 2 to store the value. My understanding is that base is simply the number of digits in your number representation system. –  Apr 17 '18 at 16:04
  • 3
    @Addison int has no base because an int isn't stored in a string form, and base is only relevant when looking at a number in string form. Thinking of it another way, if you use rocks to count, and you take a bunch and put them into a pile, asking the question what base is the pile of rocks makes no sense because the rocks don't have a "base". It's only when you want to write down the number of rocks that base matters. – Robert McKee Apr 17 '18 at 19:18
  • 1
    Or another way... There have been 1523994328 ticks since January 1, 1970. Asking if that is stored as MM/DD/YYYY or DD/MM/YYYY doesn't make sense because it's not stored in either of those formats. It's stored as a number, not in any particular date format. The same way as asking what the base of an int is. Separating values from the format they are displayed in is pretty important. – Robert McKee Apr 17 '18 at 19:50
  • Say there have been 1523994328 ticks... No one is storing 1523994328 little rocks in the computer to keep count. They are using a base 2 representation to store it. Doesn't that mean the int is base 2? That said, I see your point if you mean that a number is independent of its string representation, but in a physical computer it is represented concretely in some base. But perhaps the PHP spec doesn't specify a representation, so a physical int's base can't be determined from documentation. –  Apr 18 '18 at 21:20
50

Sorry for necroing, I just wanted to see if/how PHP7 has an effect on this question:

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

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

As you can see, casting is definitely faster, by almost 100%

But I had to increase the loop count to 100 million before the difference was a matter of seconds, which is about when I would actually start caring about performance, in most cases.

So I'll stick with using the intval function, because casting is a bit of language magic that's happening. Even if intval uses casting behind the scenes, if there were to be a bug found with casting, and for some reason it could not be fixed (backwards compatibility?), then they could at least fix intval to perform it's duty.

Update (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"

Looks like 7.1 optimized intval, and '1' + 0 is now the winner of this speed contest :) I'd still keep using intval anyway

Populus
  • 7,470
  • 3
  • 38
  • 54
  • 1
    the only benchmark left is to `+0` the var... not sure if the implicit cast here is faster than the explicit one. – SparK Dec 02 '16 at 17:07
  • 2
    LOL @ `+0` winning... that's a very dirty hack – SparK Dec 05 '16 at 22:52
  • @SparK your idea :) I wouldn't trust it though, PHP's type casting rules are not exactly the best – Populus Dec 05 '16 at 23:58
  • For `v5.5.34` my results were `9191.0059452057 ms`, `23307.397127151 ms`, and `11483.719110489 ms` respectively. So before PHP 7, casting is the fastest. – Katrina Dec 28 '16 at 16:02
  • Although its far less understandable I like `$a = '1' + 0;` and I bet most never thought of doing it like that – mic Jul 04 '18 at 06:51
  • Another method is to prefix a "+" to a value, such as `$a = +'1';`. However, this operator could result in a float. Instead you could use `$a = '1.5' | 0;` and still get the minor perf boost. `value | 0` is a commonly used trick in asm.js to enable optimizations. – Chinoto Vokro Dec 22 '19 at 20:08
  • I wouldn't worry about a necro - PHP is still in use and the new versions do act differently than the old ones. Great info! – Jeff Clayton Nov 15 '20 at 20:47
  • 2
    @chinoto-vokro both `+0` and `|0` will make a **warning** while casting non-numeric or empty string, also `+0` will make a **fatal error** while casting an empty array – a55 Dec 05 '20 at 12:00
  • @a55 I didn't realize we were considering anything besides strings, but to your former point... well crud... – Chinoto Vokro Dec 08 '20 at 03:44
  • In php 7.3.33 there is no longer a difference in performance ```php php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = intval('1'); } var_dump((microtime(true) - $start_ts)*1000 . ' ms'); string(18) "2087.4350070953 ms" php > $start_ts = microtime(true); for($i = 0; $i < 100000000; $i++) { $a = (int) '1'; } var_dump((microtime(true) - $start_ts)*1000 . ' ms'); string(18) "2085.4749679565 ms" ``` – Jose Palazuelos Jul 13 '22 at 05:59
30

I think there is at least one difference : with intval, you can specify which base should be used as a second parameter (base 10 by default) :

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

will get you :

int 123
int 123
int 83
Dominic Rodger
  • 97,747
  • 36
  • 197
  • 212
Pascal MARTIN
  • 395,085
  • 80
  • 655
  • 663
  • 11
    I find it incredibly amusing that one can convert the base 17 number "g" into decimal: `intval("2g", 17) = 50 = 2*17 + 16` – JSchaefer Oct 06 '11 at 19:10
  • 1
    @JSchaefer I took it even further, and found that the maximum I could pass as base is `36`, such as in `intval("g", 36) //16`. Any value larger than 36 returns 0. That suggests that we can use all 0-9 plus a-z characters for our custom base, such as `intval("z",36) //35`. Also, it should be noted that the first parameter is **case-insensitive**. – Jay Dadhania Dec 03 '19 at 15:49
22

One useful property of intval is that - since it is a function and not a language construct - it can be passed as an argument to a function that expects a function. You can't do this with (int).

For example, I have used it to sanitize integers for inclusion into a SQL IN() clause by passing it to array_map. Here is an example:

$ids = implode(",", array_map('intval', $_POST['array_of_integers']));
$sql = "SELECT * FROM table WHERE ids IN ($ids)";
Cave Johnson
  • 6,499
  • 5
  • 38
  • 57
16

Amber is right and if I may add a useful information type casting (adding a "(int)" before your expression ) is 300 to 600% faster than intval. So if your purpose is not to dealing with other bases than decimal, I recommend using: (int) $something

user900469
  • 161
  • 1
  • 2
  • 2
    Something you might find interesting: http://programmers.stackexchange.com/questions/99445/is-micro-optimisation-important-when-coding – Gerry Aug 18 '11 at 16:17
10

The thing that intval does that a simple cast doesn't is base conversion:

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

If the base is 10 though, intval should be the same as a cast (unless you're going to be nitpicky and mention that one makes a function call while the other doesn't). As noted on the man page:

The common rules of integer casting apply.

deceze
  • 510,633
  • 85
  • 743
  • 889