PHP: Casting vs. intval()

Doing a cast like (int) $var instead of the intval($var) function is about 300% to 650% faster. I did some tests out of curiousity in #13317 and those are the results:

Running the Tests

Speed comparison (int)$val vs. intval($val) [System #1]

#   INPUT                     (INT)$val        INTVAL($val)       RATIO
----------------------------------------------------------------------------
#0  42                      : 0.068180       / 0.448819             658%
#1  -42                     : 0.067972       / 0.448907             660%
#2  4.2                     : 0.072348       / 0.450288             622%
#3  '42'                    : 0.087305       / 0.469350             537%
#4  '+42'                   : 0.087590       / 0.471153             537%
#5  '-42'                   : 0.089154       / 0.469826             526%
#6  34                      : 0.068234       / 0.451035             661%
#7  '042'                   : 0.089344       / 0.470391             526%
#8  0x1A                    : 0.072989       / 0.451909             619%
#9  '1e10'                  : 0.088196       / 0.469347             532%
#10 26                      : 0.068378       / 0.449884             657%
#11 42000000                : 0.068770       / 0.449416             653%
#12 2147483647              : 0.068927       / 0.448028             650%
#13 2147483648              : 0.072599       / 0.450618             620%
#14 4.2E+20                 : 0.086305       / 0.467347             541%
#15 '420000000000000000000' : 0.102120       / 0.484245             474%
#16 array()                 : 0.092310       / 0.472185             511%
#17 array('foo', 'bar')     : 0.112644       / 0.494482             438%

Speed comparison (int)$val vs. intval($val) [System #2]

#   INPUT                     (INT)$val        INTVAL($val)       RATIO
----------------------------------------------------------------------------
#0  42                      : 0.045576       / 0.194759             427%
#1  -42                     : 0.042457       / 0.194273             457%
#2  4.2                     : 0.047853       / 0.196049             409%
#3  '42'                    : 0.055792       / 0.209531             375%
#4  '+42'                   : 0.055158       / 0.208236             377%
#5  '-42'                   : 0.056604       / 0.209486             370%
#6  34                      : 0.042580       / 0.194606             457%
#7  '042'                   : 0.056834       / 0.209276             368%
#8  0x1A                    : 0.045320       / 0.196626             433%
#9  '1e10'                  : 0.054923       / 0.209295             381%
#10 26                      : 0.042582       / 0.195295             458%
#11 42000000                : 0.042673       / 0.194469             455%
#12 2147483647              : 0.042560       / 0.194363             456%
#13 2147483648              : 0.045553       / 0.197149             432%
#14 4.2E+20                 : 0.054069       / 0.206131             381%
#15 '420000000000000000000' : 0.066170       / 0.218996             330%
#16 array()                 : 0.057587       / 0.210010             364%
#17 array('foo', 'bar')     : 0.071908       / 0.224338             311%

This has been done with 100 000 iterations each. Both systems were running windows. The first one was with PHP 5.2.8 and weaker as the other with PHP 5.2.9 and more CPU, memory and hd-speed.

Comparison of results intval() and casting to integer

To proof that intval() and casting to integer reveal the exact same values, I did run another test as well:

#   INPUT                     EXPECTED      INTVAL()      CAST        RESULT
----------------------------------------------------------------------------
#0  42                      : 42          / 42          / 42           pass.
#1  -42                     : -42         / -42         / -42          pass.
#2  4.2                     : 4           / 4           / 4            pass.
#3  '42'                    : 42          / 42          / 42           pass.
#4  '+42'                   : 42          / 42          / 42           pass.
#5  '-42'                   : -42         / -42         / -42          pass.
#6  34                      : 34          / 34          / 34           pass.
#7  '042'                   : 42          / 42          / 42           pass.
#8  0x1A                    : 1410065408  / 1410065408  / 1410065408   pass.
#9  '1e10'                  : 1           / 1           / 1            pass.
#10 26                      : 26          / 26          / 26           pass.
#11 42000000                : 42000000    / 42000000    / 42000000     pass.
#12 2147483647              : 2147483647  / 2147483647  / 2147483647   pass.
#13 2147483648              : -2147483648 / -2147483648 / -2147483648  pass.
#14 4.2E+20                 : 0           / 0           / 0            pass.
#15 '420000000000000000000' : 2147483647  / 2147483647  / 2147483647   pass.
#16 array()                 : 0           / 0           / 0            pass.
#17 array('foo', 'bar')     : 1           / 1           / 1            pass.

Speed comparison settype() vs. intval() [System #1]

For comparison reasons I did run a test between settype() and intval() as well. The differences are not that big, but I’m not sure that the test actually is valid because it is not easy to test both functions directly against each other. Since I did run it I thought this is worth so share next to the data above:

#   INPUT                     SETTYPE()         INTVAL($val)       RATIO
----------------------------------------------------------------------------
#0  42                      : 0.533901       / 0.477519              89%
#1  -42                     : 0.533729       / 0.478345              89%
#2  4.2                     : 0.536932       / 0.480030              89%
#3  '42'                    : 0.547209       / 0.503447              92%
#4  '+42'                   : 0.553214       / 0.501764              90%
#5  '-42'                   : 0.551974       / 0.503403              91%
#6  34                      : 0.532637       / 0.478039              89%
#7  '042'                   : 0.552709       / 0.505796              91%
#8  0x1A                    : 0.536864       / 0.481672              89%
#9  '1e10'                  : 0.550352       / 0.506748              92%
#10 26                      : 0.537672       / 0.478947              89%
#11 42000000                : 0.536360       / 0.478373              89%
#12 2147483647              : 0.541348       / 0.490556              90%
#13 2147483648              : 0.539018       / 0.486669              90%
#14 4.2E+20                 : 0.554357       / 0.499877              90%
#15 '420000000000000000000' : 0.566189       / 0.522929              92%
#16 array()                 : 0.549919       / 0.505488              91%
#17 array('foo', 'bar')     : 0.578893       / 0.527864              91%

Update:

I did run some tests for 0 + $var as well because it’s some way to get a number as well. It’s not that type-safe but for comparison reasons I thought it’s worth to list as well while I’m at it:

Comparison of results intval() and 0 + $var

#   INPUT                     EXPECTED      INTVAL()      0+$VAR      RESULT
----------------------------------------------------------------------------
#0  42                      : 42          / 42          / 42           pass.
#1  -42                     : -42         / -42         / -42          pass.
#2  4.2                     : 4           / 4           / 4.2          different.
#3  '42'                    : 42          / 42          / 42           pass.
#4  '+42'                   : 42          / 42          / 42           pass.
#5  '-42'                   : -42         / -42         / -42          pass.
#6  042                     : 34          / 34          / 34           pass.
#7  '042'                   : 42          / 42          / 42           pass.
#8  1e10                    : 1410065408  / 1410065408  / 10000000000  different.
#9  '1e10'                  : 1           / 1           / 10000000000  different.
#10 0x1A                    : 26          / 26          / 26           pass.
#11 42000000                : 42000000    / 42000000    / 42000000     pass.
#12 2147483647              : 2147483647  / 2147483647  / 2147483647   pass.
#13 2147483648              : -2147483648 / -2147483648 / 2147483648   different.
#14 420000000000000000000   : 0           / 0           / 4.2E+20      different.
#15 '420000000000000000000' : 2147483647  / 2147483647  / 4.2E+20      different.
#16 array()                 : 0           / 0           / error.       skipped.
#17 array('foo', 'bar')     : 1           / 1           / error.       skipped.

Speed comparison (int)$val vs. 0 + $val [System #1]

And for the speed comparison. I only did run it on one test-system, I think it’s enough to show the picture:

#   INPUT                     (INT)$val        0+$val             RATIO
----------------------------------------------------------------------------
#0  42                      : 0.068794       / 0.069249             100%
#1  -42                     : 0.074688       / 0.069155              92%
#2  4.2                     : 0.073207       / 0.069257              94%   Note: different.
#3  '42'                    : 0.086568       / 0.076261              88%
#4  '+42'                   : 0.087230       / 0.080867              92%
#5  '-42'                   : 0.090189       / 0.075923              84%
#6  042                     : 0.069072       / 0.069243             100%
#7  '042'                   : 0.088535       / 0.082137              92%
#8  1e10                    : 0.072930       / 0.069512              95%   Note: different.
#9  '1e10'                  : 0.086942       / 0.082032              94%
#10 0x1A                    : 0.068921       / 0.069365             100%
#11 42000000                : 0.069203       / 0.069415             100%
#12 2147483647              : 0.069109       / 0.069386             100%
#13 2147483648              : 0.073053       / 0.069277              94%   Note: different.
#14 420000000000000000000   : 0.092318       / 0.069463              75%   Note: different.
#15 '420000000000000000000' : 0.105735       / 0.211617             200%   Note: different.
#16 array()                 : skipped.
#17 array('foo', 'bar')     : skipped.

Those one with the Note: different at the end are those where both functions do not return the same value (see previous test).

Conclusions

Cast. It’s handy and it’s not doing bad things. In fact it does exactly the same results as the intval() function while being faster. Both even do the same warning if I had seen that right.

Read On:

This entry was posted in Hacking The Core, Pressed, The Know Your Language Department and tagged , , , , , , , , . Bookmark the permalink.

18 Responses to PHP: Casting vs. intval()

  1. Joseph Scott says:

    I’d expect intval() to be slower than a direct cast. A simple test script run through VLD shows one less operation. And the ops that are run are slightly different:

    intval
    ———
    0 ASSIGN
    1 SEND_VAR
    2 DO_FCALL
    3 ASSIGN
    4 RETURN
    5* ZEND_HANDLE_EXCEPTION

    cast
    ——-
    0 ASSIGN
    1 CAST
    2 ASSIGN
    3 RETURN
    4* ZEND_HANDLE_EXCEPTION

    I suspect that doing a single CAST is quite a bit faster than the combined SEND_VAR, DO_FCALL ops.

    • hakre says:

      Nice listing. Can you try for 0 + $var and maybe a settype() call as well? I’ll update the article, because I did some measurements for 0 + $var. I got that one from the question / answer from stackoverflow.

      • Joseph Scott says:

        settype() increases the opcount to 7

        0 ASSIGN
        1 SEND_REF
        2 SEND_VAL
        3 DO_FCALL
        4 ASSIGN
        5 RETURN
        6* ZEND_HANDLE_EXCEPTION

        The 0 + $var is 5 ops

        0 ASSIGN
        1 ADD
        2 ASSIGN
        3 RETURN
        4* ZEND_HANDLE_EXCEPTION

        • hakre says:

          Great! I always had the feeling that cast is something nice to ensure a certain type and do things straight. Looks like it’s the same performance wise. So a nice win-win.

  2. Pingback: 網站製作學習誌 » [Web] 連結分享

  3. Pingback: PHP: Compare vs. Calculating | hakre on wordpress

  4. samwho says:

    Really really awesome post🙂 I wonder where all of that speed is going with intval()… It must do something funky behind the scenes.

    Any chance you could post up a link to the code you used to run these benchmarks?

    Thanks!
    Sam

    • hakre says:

      Well, I do not know if this is really awesome but I had some fun doing so. Where the speed is going is pretty well shown in Jospeh Scott’s comment.

      For the tests sourcecode, this is what I discovered on my harddisk:

      <pre>
      <?php 
      /*
       * intval and casting integers tests
       * 
       * Last Updated: 13. May 2010
       *  
       * @author hakre <https://hakre.wordpress.com/>
       */
      
      $values = array(
      	array('value' => 42                     , 'intval' => 42),
      	array('value' => -42                    , 'intval' => -42),
      	array('value' => 4.2                    , 'intval' => 4  ),
      	array('value' => '42'                   , 'intval' => 42 ),
      	array('value' => '+42'                  , 'intval' => 42 ),
      	array('value' => '-42'                  , 'intval' => -42),
      	array('value' => 042                    , 'intval' => 34        , 'notation' => '042' ), # 34
      	array('value' => '042'                  , 'intval' => 42 ),
      	array('value' => 1e10                   , 'intval' => 1410065408, 'notation' => '1e10'), # 10000000000
      	array('value' => '1e10'                 , 'intval' => 1  ),
      	array('value' => 0x1A                   , 'intval' => 26        , 'notation' => '0x1A'), # 26
      	array('value' => 42000000               , 'intval' => 42000000),
      	array('value' => 2147483647             , 'intval' => 2147483647),
      	array('value' => 2147483648             , 'intval' => -2147483648),
      	array('value' => 420000000000000000000  , 'intval' => 0         , 'notation' => '420000000000000000000'), # 4.2E+20
      	array('value' => '420000000000000000000', 'intval' => 2147483647),
      	array('value' => array()                , 'intval' => 0  ),
      	array('value' => array('foo', 'bar')    , 'intval' => 1  ),
      );
      
      $tests  = array_keys($values);
      $labels = array(0 => 'pass.', 1 => 'failed.', 2 => 'different.', 3 => 'error.' , 4 => 'skipped.');
      
      printf ("PHP %s %s/%s - %s\n\n", PHP_VERSION, PHP_OS, PHP_SAPI, str_replace(' +0000', ' UTC ', gmdate('r')));
      
      print "\n* TEST #1: Comparison of results intval() and casting to integer:\n\n";
      print "#   INPUT                     EXPECTED      INTVAL()      CAST        RESULT\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	$expected = $value['intval'];
      	$intval   = intval($input);
      	$castval  = (int) $input;
      	$result   = 1 - (int) ($expected == $intval && $intval === $castval);
      	$label    = $labels[$result];
      	printf('#%-2s %-23s : %-11s / %-11s / %-11s  %s', $test, $notation, $expected, $intval, $castval, $label);
      	
      	print "\n";
      }
      print "\n";
      flush();
      
      print "\n* TEST #2: Comparison of results intval() and 0 + \$var:\n\n";
      print "#   INPUT                     EXPECTED      INTVAL()      0+\$VAR      RESULT\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	$expected = $value['intval'];
      	$intval   = intval($input);
      	if (is_array($input)) {
      		$castval  = $labels[3];
      		$label    = $labels[4];	
      	} else {	
      		$castval  = 0 + $input;
      		$result   = 1 - (int) ($expected == $intval && $intval === $castval);
      		$label    = $labels[$result * 2];
      	}
      	printf('#%-2s %-23s : %-11s / %-11s / %-11s  %s', $test, $notation, $expected, $intval, $castval, $label);
      	
      	print "\n";
      }
      print "\n";
      flush();
      
      print "\n* TEST #3: abs((int)\$val) vs. (int) abs(\$val) \n\n";
      print "#   INPUT                     ABS((INT)\$val)   (INT)ABS(\$val)      RESULT\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];	
      	$notation = test_varnotation($value);
      	$absint   = abs((int) $input);
      	$intabs   = (int) abs($input);
      	$result   = 1 - (int) ($absint === $intabs);
      	$label    = $labels[$result * 2];
      	printf('#%-2s %-23s : %-14s / %-11s        %s', $test, $notation, $absint, $intabs, $label);	
      	print "\n";
      }
      print "\n";
      flush();
      
      print "\n* TEST #4: abs((int)\$val) vs. absint(\$val) \n\n";
      print "#   INPUT                     ABS((INT)\$val)   ABSINT(\$val)       RESULT\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	$absint   = abs((int) $input);
      	$intabs   = absint($input);
      	$result   = 1 - (int) ($absint === $intabs);
      	$label    = $labels[$result * 2];
      	printf('#%-2s %-23s : %-14s / %-10s         %s', $test, $notation, $absint, $intabs, $label);	
      	print "\n";
      }
      print "\n";
      flush();
      
      ini_set("max_execution_time", "300");
      $iterations = 100000;
      
      print "\n* TEST #5: Speed comparison (int)\$val  vs. intval(\$val) \n\n";
      print "#   INPUT                     (INT)\$val        INTVAL(\$val)       RATIO\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = (int) $input;
      	}
      	$stop = microtime(true);
      	$timea = $stop - $start;
      
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = intval($input);
      	}
      	$stop = microtime(true);
      	$timeb = $stop - $start;
      	
      	
      	$ratio = ($timeb / $timea) * 100;
      	printf('#%-2s %-23s : %-12f   / %-12f         %3d%%', $test, $notation, $timea, $timeb, $ratio);	
      	print "\n";
      }
      printf("(%s iterations each)\n\n", number_format($iterations));
      flush();
      
      print "\n* TEST #6: Speed comparison settype() vs. intval() \n\n";
      print "#   INPUT                     SETTYPE()         INTVAL(\$val)       RATIO\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = $input;
      		$r    = settype( $calc, 'int' );
      	}
      	$stop = microtime(true);
      	$timea = $stop - $start;
      
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = $input;
      		$calc = intval($input);
      	}
      	$stop = microtime(true);
      	$timeb = $stop - $start;
      	
      	
      	$ratio = ($timeb / $timea) * 100;
      	printf('#%-2s %-23s : %-12f   / %-12f         %3d%%', $test, $notation, $timea, $timeb, $ratio);	
      	print "\n";
      }
      printf("(%s iterations each)\n\n", number_format($iterations));
      flush();
      
      print "\n* TEST #7: Speed comparison abs((int)\$val) vs. absint(\$val) \n\n";
      print "#   INPUT                     ABS((INT)\$val)   ABSINT(\$val)       RATIO\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = abs((int) $input);
      	}
      	$stop = microtime(true);
      	$timea = $stop - $start;
      
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = absint($input);
      	}
      	$stop = microtime(true);
      	$timeb = $stop - $start;
      	
      	
      	$ratio = ($timeb / $timea) * 100;
      	printf('#%-2s %-23s : %-12f   / %-12f         %3d%%', $test, $notation, $timea, $timeb, $ratio);	
      	print "\n";
      }
      printf("(%s iterations each)\n\n", number_format($iterations));
      flush(); 
      
      print "\n* TEST #8: Speed comparison (int)\$val vs. 0 + \$val \n\n";
      print "#   INPUT                     (INT)\$val        0+\$val             RATIO\n";
      print "----------------------------------------------------------------------------\n";
      foreach ($tests as $test) {
      	flush();
      	$value    = $values[$test];	
      	$input    = $value['value'];
      	$notation = test_varnotation($value);
      	
      	if (is_array($input)) {
      		printf('#%-2s %-23s : %s', $test, $notation, $labels[4]);
      		print "\n";
      		continue;
      	}
      	
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = (int) $input;
      	}
      	$stop = microtime(true);
      	$timea = $stop - $start;
      
      	$start = microtime(true);
      	for ($i = 0; $i < $iterations; $i++) {
      		$calc = 0 + $input;
      	}
      	$stop = microtime(true);
      	$timeb = $stop - $start;	
      	
      	$ratio = ($timeb / $timea) * 100;
      	printf('#%-2s %-23s : %-12f   / %-12f         %3d%%', $test, $notation, $timea, $timeb, $ratio);	
      	print "\n";
      }
      printf("(%s iterations each)\n\n", number_format($iterations));
      flush(); 
      
      print "</pre>\n";
      return;
      
      function test_varnotation(array $test) {
      	if (isset($test['notation'])) {
      		return $test['notation'];
      	}
      	$input = $test['value'];
      	
      	$notation = preg_replace('(\n|\s+)', ' ' , var_export($input, true));
      	$notation = str_replace(array('array ( ',' 0 => ','  1 => ',', )'), array('array(', '',' ',')'), $notation);
      	return $notation;
      }
      
      function absint( $maybeint ) {
      	return abs( intval( $maybeint ) );
      }
      
      #EOF;
      
  5. Geo says:

    Excellent benchmark! No doubt I’ll be using casting from now on.

    The “0+” is lame. And not consistent. What if you need to cast string, you’d use a “”+”? And array? “$array+”??? Lol. And it’s still slower after all.

    One thing to be careful about though is precision. Check this out:

    <?php
    echo (int) ( (0.1+0.7) * 10 ); // echoes 7!
    ?>

    • hakre says:

      Yes, that’s by nature of computers as machines are limited about numbers compared to what we as humans can imagine and calculate upon. From Warning: Floating point precision:

      floor((0.1+0.7)*10) will usually return 7 instead of the expected 8, since the internal representation will be something like 7.9999999999999991118….

      So never trust floating number results to the last digit, and never compare floating point numbers for equality. If higher precision is necessary, the arbitrary precision math functions and gmp functions are available.

  6. I would like to change string to number with decimal such as “0.001”. Which function I should use? (cannot use intval() because it returns “integer”, not “decimal”)

  7. briedis says:

    Intval() probably is slower because it’s a function call, and we know that function calls cost time…

  8. Pingback: Zajímavé články o WordPressu (v angličtině) « Fórum podpory WordPressu

  9. Cody says:

    Thanks for this. Exactly what i needed to prove a hunch. Complete and in depth. I really enjoyed knowing that after viewing this it was no longer a shot in the dark.

  10. Pingback: PHP: Casten vs intval() | xi-intersection

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s