【问题标题】:Converting MySQL tinyint booleans (0/1) to PHP booleans (true/false)将 MySQL tinyint 布尔值 (0/1) 转换为 PHP 布尔值 (true/false)
【发布时间】:2015-12-30 21:43:41
【问题描述】:

我需要反复将 MySQL tinyint(1) 'boolean' 数据类型转换为 PHP 布尔值,并且我一直在尝试测试最快的方法来做到这一点。我的数据映射如下:

  • NULL = FALSE
  • 0 = 错误
  • 1 = 真

环顾了几个小时后,我似乎找不到任何关于此的性能解释/批评,所以我去尝试自己制作我找到的可能解决方案。我的代码如下:

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

我的结果如下:

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

我选择了 850 万次迭代,因为我通常希望使最快的测试尽可能接近 1 秒,以便一目了然地看到缩放。从这个测试来看,最好的选择似乎是 !empty($value) 的差距非常大。

我发布这篇文章是为了分享我的发现,看看其他人是否知道获得相同结果的不同方法可能更快,或者这是否会在未来的 PHP 版本中彻底改变。我们目前是5.4的环境,希望明年能移植到5.6,希望最终能看到php7。

这些方法中的一种在较新版本的 PHP 中是否会以不同的方式胜出,或者是否有完全不同的方法来解决这个问题?感谢您的洞察力!

编辑:

正如所指出的,上述测试是不正确的。下面是一个带有附加选项的正确测试:

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

这个测试给了我:

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

在看到较新版本的 PHP 可能出现的显着性能变化后,我对它的进展很感兴趣,因为现在比赛已经接近尾声了!

【问题讨论】:

  • NULL 转换为false 可能有一天会给您带来严重的麻烦。 “未设置”与“设置为不正确”完全不同。
  • 我同意,但客户和团队同意此映射。这是一个超过十年的老系统,其中用户群对数据输入很懒惰,所以他们希望他们看到不经常出现的错误数据 (<.01>耸耸肩
  • $start2 未定义
  • @Paolo,感谢您了解这一点,这可能会改变一些事情。让我重新运行并编辑...

标签: php mysql performance type-conversion performance-testing


【解决方案1】:

这似乎在后来的 PHP 版本中得到了优化:

Current PHP Version: 5.6.16-2+deb.sury.org~wily+1

Did NOT EMPTY in 0.43913006782532 seconds
Did TYPECAST BOOL in 0.40566301345825 seconds
Did EQUALS TRUE in 0.42750406265259 seconds
Did NOT NOT in 0.43936395645142 seconds
Did IS NULL in 1.3173689842224 seconds

PHP 7 更令人印象深刻:

Current PHP Version: 7.0.1-1+deb.sury.org~wily+2

Did NOT EMPTY in 0.21985292434692 seconds
Did TYPECAST BOOL in 0.18928909301758 seconds
Did EQUALS TRUE in 0.17465591430664 seconds
Did NOT NOT in 0.20792722702026 seconds
Did IS NULL in 0.15517687797546 seconds

在性能和可读性方面,类型转换似乎是最佳解决方案((bool) $someVar 之类的结构比!!$someVar 或其他晦涩的结构更能向其他开发人员传达您的意图)。

【讨论】:

  • 哇,这些都是一些非常显着的改进,也有显着的差异! Not empty 从最前面到最后一个死,反之亦然 IS NULL(虽然我意识到应该是 !(is_null() 现在我看着它)。
【解决方案2】:

PHP的默认活动对你来说还不够吗?

从手册中无耻地撕下

转换为布尔值

要将值显式转换为布尔值,请使用 (bool) 或 (boolean) 强制转换。但是,在大多数情况下,强制转换是不必要的,因为如果运算符、函数或控制结构需要布尔参数,则会自动转换值。

另见Type Juggling

当转换为布尔值时,以下值被视为 FALSE:

the boolean FALSE itself
the integer 0 (zero)
the float 0.0 (zero)
the empty string, and the string "0"
an array with zero elements
an object with zero member variables (PHP 4 only)
the special type NULL (including unset variables)
SimpleXML objects created from empty tags

所有其他值都被视为 TRUE(包括任何资源)。

【讨论】:

  • 完全同意。 PHP 确实对真实性采取了“足够接近”的方法,因此实际上没有必要显式转换。
  • 对客户来说不够好,不。我正在与其他团队一起在面向对象的环境中工作,我的特定对象应该从数据库中提取,然后将数据存储并传递为真假。所以是的,我的要求确实需要我上面列出的内容。此外,将其类型转换为 bool 需要 !empty() 的 250% 时间,所以我不确定为什么我会选择这样做,除了轻微的可读性问题。在较新版本的 PHP 中是否更快?
  • @Ripptor 如果你想对这件事如此正式,这不一定是一件坏事,为什么不使用一个可以为你处理这个问题的 ORM 呢?使用低级数据库调用四处乱窜会让你接触到所有这些丑陋的东西。
【解决方案3】:

首先,您应该在为 $start0$start1 分配值时修复您的测试,然后检查 $start1$start2,其中后者未定义。

一旦固定,最快的测试就是简单的比较(你没有尝试过):

$answer = $start0 == 1

这是我的代码(我从终端运行)

<?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";

/* 
   .
   .
   .
*/

这是结果

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

您可以在此处对不同版本的 PHP 运行测试

https://3v4l.org/t4K5j

【讨论】:

  • 感谢您提供的附加选项,我没有考虑过那个!我在上面修复了我的测试并添加了您的选项,我的结果几乎相同。但是我们都在运行 5.4,所以我仍然想知道新版本的 PHP 是否有不同的结果?
  • 作为警告,在 PHP5.6.15 中运行 Paolo 代码,当我从 5.4.45 得到非常相似的数字时,得到了一个相当奇怪的结果 Did IS NULL in 56.041206121445 seconds 所以如果你正在考虑升级,也许你应该检查这个
  • 哇,这个网站是一个很棒的发现!然而,它在几乎所有服务器上中途退出了测试......
猜你喜欢
  • 2021-12-29
  • 1970-01-01
  • 2016-02-01
  • 1970-01-01
  • 2022-08-05
  • 1970-01-01
  • 2020-12-10
  • 2012-09-12
  • 2011-04-27
相关资源
最近更新 更多