2010-06-05 91 views
12

同时优化在PHP函数,我改变为什么PHP中的投射和比较比is_ *更快?

if(is_array($obj)) foreach($obj as $key=>$value { [snip] } 
else if(is_object($obj)) foreach($obj as $key=>$value { [snip] }

if($obj == (array) $obj) foreach($obj as $key=>$value { [snip] } 
else if($obj == (obj) $obj) foreach($obj as $key=>$value { [snip] }

了解===后,我改变了对

if($obj === (array) $obj) foreach($obj as $key=>$value { [snip] } 
else if($obj === (obj) $obj) foreach($obj as $key=>$value { [snip] }

改变从芸,*铸造每个测试导致重大加速(> 30%)。

据我所知,=====快,因为没有强制要做,但为什么要比调用任何is _ * - 函数更快速地创建变量?

编辑: 既然大家问的正确性,我写了这个小测试:

$foo=(object) array('bar'=>'foo'); 
$bar=array('bar'=>'foo'); 

if($foo===(array) $foo) echo '$foo is an array?'; 
if($bar===(object) $bar) echo '$bar is an object?'; 

它不打印任何错误,这两个变量不得到改变,所以我觉得它的工作,但我已经准备好了,否则就说服了。

另一个编辑: Artefacto的节目给了我下面的数字:

PHP 5.3.2-1ubuntu4.2 (64bit) on a Core i5-750 with Xdebug 
Elapsed (1): 0.46174287796021/0.28902506828308 
Elapsed (2): 0.52625703811646/0.3072669506073 
Elapsed (3): 0.57169318199158/0.12708187103271 
Elapsed (4): 0.51496887207031/0.30524897575378 
Speculation: Casting and comparing can be about 1.7-4 times faster.
PHP 5.3.2-1ubuntu4.2 (64bit) on a Core i5-750 without Xdebug 
Elapsed (1): 0.15818405151367/0.214271068573 
Elapsed (2): 0.1531388759613/0.25853085517883 
Elapsed (3): 0.16164898872375/0.074632883071899 
Elapsed (4): 0.14408397674561/0.25812387466431 
Without Xdebug, the extra function call didn't matter anymore, so every test (except 3) ran faster.
PHP 5.3.2-1ubuntu4.2 on a Pentium M 1.6GHz 
Elapsed (1): 0.97393798828125/0.9062979221344 
Elapsed (2): 0.39448714256287/0.86932587623596 
Elapsed (3): 0.44513893127441/0.23662400245667 
Elapsed (4): 0.38685202598572/0.82854390144348 
Speculation: Casting an array is slower, casting an object can be faster, but might not be slower.
PHP 5.2.6-1+lenny8 on a Xeon 5110 
Elapsed (1): 0.273758888245/0.530702114105 
Elapsed (2): 0.276469945908/0.605964899063 
Elapsed (3): 0.332523107529/0.137730836868 
Elapsed (4): 0.267735004425/0.556323766708 
Speculation: These results are similar to Artefacto's results, I think it's PHP 5.2. 

解决办法: 我使用的分析器(Xdebug的)由函数调用大约慢了3倍(即使不进行分析),但没有影响铸造和比较没有所以铸造和比较似乎更快,即使它不受调试器/分析器的影响。

+4

如果我猜的话,它会是因为避免函数调用的开销。 – Amber 2010-06-05 20:36:42

+2

您的替换不会导致相应的程序。例如,如果'$ obj'是一个对象,'is_array($ obj)'返回'false',但是可能'($ obj ==(array)$ obj)'计算为'true'。 – Artefacto 2010-06-05 20:45:14

+0

@Artefacto是的,这完全是真的。这也是我写的,请看看我的回答,并给我一些反馈 – streetparade 2010-06-05 20:49:14

回答

4

我真的不能重现。事实上,你的策略给了我,但在所有情况下,一个更长的时间:

<?php 

class A { 
    private $a = 4; 
    private $b = 4; 
    private $f = 7; 
} 

$arr = array("a" => 4, "b" => 4, "f" => 7); 

$obj = new A(); 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_array($obj) and die("err"); 
} 

echo "Elapsed (1.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($obj === (array) $obj) and die("err"); 
} 

echo "Elapsed (1.2): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_object($arr) and die("err"); 
} 

echo "Elapsed (2.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($arr === (object) $arr) and die("err"); 
} 

echo "Elapsed (2.2): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_object($obj) or die("err"); 
} 

echo "Elapsed (3.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($obj === (object) $obj) or die("err"); 
} 

echo "Elapsed (3.2): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    is_array($arr) or die("err"); 
} 

echo "Elapsed (4.1): " . (microtime(true) - $t); 
echo "\n"; 

$t = microtime(true); 

for ($i = 0; $i < 500000; $i++) { 
    ($arr === (array) $arr) or die("err"); 
} 

echo "Elapsed (4.2): " . (microtime(true) - $t); 

输出:

 
Elapsed (1.1): 0.366055965424 
Elapsed (1.2): 0.550662994385 
Elapsed (2.1): 0.337422132492 
Elapsed (2.2): 0.579686880112 
Elapsed (3.1): 0.402997970581 
Elapsed (3.2): 0.190818071365 
Elapsed (4.1): 0.332742214203 
Elapsed (4.2): 0.549873113632 

演员和比较只有更快检查,如果事情是一个对象。推测如下:可能是因为对象标识检查只需要确定处理程序表和对象句柄是否相同,而在检查数组标识时需要在最坏的情况下比较所有值。

+0

Xdebug歪曲了我的数字,当我将i5与Xeon比较时,发现问题。我接受了你的答案,但你可能想添加一个关于影响基准的PHP版本和插件(调试器,操作码缓存等)的注释。 – tstenner 2010-06-06 09:27:17

+0

@tstenner Windows 7 64位,Athlon 64 3500+,使用VC6编译的PHP 5.3.2的发布版本。没有调试器或操作码缓存(不是操作码缓存会有所作为;在脚本编译后计算统计信息的时间)。 – Artefacto 2010-06-06 16:40:14

3
  1. 这可能是在某些PHP版本中,函数调用会比转换花费更长的时间。
  2. 调试器/分析器将显着改变这些关系,因为它们会覆盖函数调用处理程序等,因此它们会更改调用函数所需的时间。
  3. 如果你正在优化这些东西,你看错了地方。如果你的PHP应用程序做了一些不平凡的事情,它的性能几乎永远不会从你尝试智能引擎所获得的微秒优势中得到提高,即使这样做可能会消失,下一个PHP版本将会改变引擎实现的一些细节。例如,5。2和5.3引擎在内部有所不同,下一版本会有更多差异。这些差异通常不会影响代码,但它们会使所有的微观优化无关紧要。
  4. 将不是对象/数组的东西转换为对象/数组可能会比通常检查更慢,因为它必须创建新的对象/数组。
+0

一微秒可能看起来不多,但是这个测试占用了该函数执行时间的四分之一以上。 – tstenner 2010-06-06 10:06:53

+0

4.让我感到惊讶,这就是为什么问这个问题;) 无论如何,很好的答案。 +1 – tstenner 2010-06-06 10:07:55

3

我只是想补充说,对于小数组/对象,强制比较只会更快。

for ($i = 0; $i < 10000; $i ++) { 
    $arr[] = $i; 
} 

$t = microtime(true); 
for ($i = 0; $i < 5000; $i ++) { 
    is_array($arr); 
} 
echo "Elapsed: " . (microtime(true) - $t) . "\n"; 

$t = microtime(true); 
for ($i = 0; $i < 5000; $i ++) { 
    ($arr === (array)$arr); 
} 
echo "Elapsed: " . (microtime(true) - $t) . "\n"; 

输出:

Elapsed: 0.0487940311432 
Elapsed: 9.20055603981 
+0

优秀的例子! – CoR 2015-05-03 11:15:22