Search code examples
phpmysqlperformancetype-conversionperformance-testing

Converting MySQL tinyint booleans (0/1) to PHP booleans (true/false)


I need to repeatedly convert the MySQL tinyint(1) 'boolean' datatype into a PHP boolean value, and I've been trying to test the fastest way to do this. My data mapping is as follows:

  • NULL = FALSE
  • 0 = FALSE
  • 1 = TRUE

After looking around for a few hours, I can't seem to find any performance explanations/critiques on this, so I went and tried to make one myself of the possible solutions I have found. My code is as follows:

echo 'Current PHP Version: ' . phpversion() . '<br /><br />';
$start1 = 1;
$start0 = 0;

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 8500000; $i++ )
{
    $answer = !empty($start1);
    $answer = !empty($start2);  
}
$time_end = microtime(TRUE);
echo 'Did NOT EMPTY in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 8500000; $i++ )
{
    $answer = (bool)$start1;
    $answer = (bool)$start2;    
}
$time_end = microtime(TRUE);
echo 'Did TYPECAST BOOL in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 8500000; $i++ )
{
    $answer = $start1 == TRUE;
    $answer = $start2 == TRUE;  
}
$time_end = microtime(TRUE);
echo 'Did EQUALS TRUE in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 8500000; $i++ )
{
    $answer = !!$start1;
    $answer = !!$start2;    
}
$time_end = microtime(TRUE);
echo 'Did NOT NOT in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 8500000; $i++ )
{
    $answer = is_null($start1);
    $answer = is_null($start2);     
}
$time_end = microtime(TRUE);
echo 'Did IS NULL in ' . ($time_end - $time_start) . " seconds<br>";

My results are as follows:

Current PHP Version: 5.4.16

Did NOT EMPTY in 1.00608086586 seconds
Did TYPECAST BOOL in 2.5599420070648 seconds
Did EQUALS TRUE in 2.7039749622345 seconds
Did NOT NOT in 2.7622299194336 seconds
Did IS NULL in 4.1728219985962 seconds

I picked 8.5 million iterations as I generally like to bring the fastest test as close to 1 second as possible to see scaling at a glance. From this test it seems like the best choice is !empty($value) by an impressively wide margin.

I'm posting this to share my findings and see if anyone else knows of a different way to get the same results which may be faster, or if this will radically change in future PHP versions. We're currently in a 5.4 environment, hoping to port to 5.6 in the next year, with hopes of seeing php7 eventually.

Does one of these methods win out differently in newer versions of PHP, or is there even a completely different way to go about this that I'm missing? Thanks for your insight!

EDIT:

As was pointed out, the above test is incorrect. A correct test, with an additional option, is below:

echo 'Current PHP Version: ' . phpversion() . '<br /><br />';

$start1 = 1;
$start0 = 0;

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 14000000; $i++ )
{
    $answer = $start1 == 1;
    $answer = $start0 == 1;     
}
$time_end = microtime(TRUE);
echo 'Did EQUALS 1 in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 14000000; $i++ )
{
    $answer = (bool)$start1;
    $answer = (bool)$start0;    
}
$time_end = microtime(TRUE);
echo 'Did TYPECAST BOOL in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 14000000; $i++ )
{
    $answer = $start1 == TRUE;
    $answer = $start0 == TRUE;  
}
$time_end = microtime(TRUE);
echo 'Did EQUALS TRUE in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 14000000; $i++ )
{
    $answer = !!$start1;
    $answer = !!$start0;    
}
$time_end = microtime(TRUE);
echo 'Did NOT NOT in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 14000000; $i++ )
{
    $answer = !empty($start1);
    $answer = !empty($start0);  
}
$time_end = microtime(TRUE);
echo 'Did NOT EMPTY in ' . ($time_end - $time_start) . " seconds<br>";

$time_start = microtime(TRUE);
for( $i = 0 ; $i < 14000000; $i++ )
{
    $answer = !is_null($start1);
    $answer = !is_null($start0);    
}
$time_end = microtime(TRUE);
echo 'Did NOT IS NULL in ' . ($time_end - $time_start) . " seconds<br>";

This test gives me:

Current PHP Version: 5.4.16

Did EQUALS 1 in 1.0449228286743 seconds
Did TYPECAST BOOL in 1.0921199321747 seconds
Did EQUALS TRUE in 1.3697588443756 seconds
Did NOT NOT in 1.3729720115662 seconds
Did NOT EMPTY in 1.4694240093231 seconds
Did NOT IS NULL in 3.2058408260345 seconds

After seeing the possibly significant performance changes in newer version of PHP, I'm interested in how it fares moving forward, as the race is pretty close now!


Solution

  • First you should fix your test as you assign values to $start0 and $start1 but then you check $start1 and $start2 where the latter is not defined.

    Once fixed the fastest test is the simple comparison (you did not try it):

    $answer = $start0 == 1

    Here is my code (I ran it from the terminal)

    <?php
    echo 'Current PHP Version: ' . phpversion() . "\n\n";
    $start1 = 1;
    $start0 = 0;
    
    $time_start = microtime(TRUE);
    for( $i = 0 ; $i < 8500000; $i++ )
    {
        $answer = $start0 == 1;
        $answer = $start1 == 1;  
    }
    $time_end = microtime(TRUE);
    echo 'Did COMPARISON in ' . ($time_end - $time_start) . " seconds\n";
    
    $time_start = microtime(TRUE);
    for( $i = 0 ; $i < 8500000; $i++ )
    {
        $answer = !empty($start0);
        $answer = !empty($start1);  
    }
    $time_end = microtime(TRUE);
    echo 'Did NOT EMPTY in ' . ($time_end - $time_start) . " seconds\n";
    
    /* 
       .
       .
       .
    */
    

    Here is the result

    Current PHP Version: 5.4.45
    
    Did COMPARISON in 0.60736107826233 seconds
    Did NOT EMPTY in 0.75234413146973 seconds
    Did TYPECAST BOOL in 0.67925190925598 seconds
    Did EQUALS TRUE in 0.80053496360779 seconds
    Did NOT NOT in 0.95479583740234 seconds
    Did IS NULL in 2.1385459899902 seconds
    

    You can run the test on different versions of PHP here

    https://3v4l.org/t4K5j