Ken*_*ins 22 php performance reference isset array-key-exists
我发现如果在数组引用中设置了一个键,则array_key_exists比isset检查时慢1000倍.是否有人了解PHP的实现方式解释了为什么这是真的?
编辑:我添加了另一个案例,似乎指出在使用引用调用函数时需要开销.
基准示例
function isset_( $key, array $array )
{
return isset( $array[$key] );
}
$my_array = array();
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
array_key_exists( $i, $my_array );
$my_array[$i] = 0;
}
$stop = microtime( TRUE );
print "array_key_exists( \$my_array ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
$my_array = array();
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
isset( $my_array[$i] );
$my_array[$i] = 0;
}
$stop = microtime( TRUE );
print "isset( \$my_array ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
$my_array = array();
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
isset_( $i, $my_array );
$my_array[$i] = 0;
}
$stop = microtime( TRUE );
print "isset_( \$my_array ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
$my_array = array();
$my_array_ref = &$my_array;
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
array_key_exists( $i, $my_array_ref );
$my_array_ref[$i] = 0;
}
$stop = microtime( TRUE );
print "array_key_exists( \$my_array_ref ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
$my_array = array();
$my_array_ref = &$my_array;
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
isset( $my_array_ref[$i] );
$my_array_ref[$i] = 0;
}
$stop = microtime( TRUE );
print "isset( \$my_array_ref ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
$my_array = array();
$my_array_ref = &$my_array;
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
isset_( $i, $my_array_ref );
$my_array_ref[$i] = 0;
}
$stop = microtime( TRUE );
print "isset_( \$my_array_ref ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
Run Code Online (Sandbox Code Playgroud)
产量
array_key_exists( $my_array ) 0.0056459903717
isset( $my_array ) 0.00234198570251
isset_( $my_array ) 0.00539588928223
array_key_exists( $my_array_ref ) 3.64232587814 // <~ what on earth?
isset( $my_array_ref ) 0.00222992897034
isset_( $my_array_ref ) 4.12856411934 // <~ what on earth?
Run Code Online (Sandbox Code Playgroud)
我在PHP 5.3.6上.
键盘示例.
在工作中,我有一个PHP的VM实例,其中包含一个名为VLD的PECL扩展.这使您可以从命令行执行PHP代码而不是执行它,而是返回生成的操作码.
在回答这样的问题时非常出色.
http://pecl.php.net/package/vld
如果你走这条路(如果你一般都很好奇PHP如何在内部工作,我想你应该)你应该把它安装在虚拟机上(也就是说,我不会把它安装在机器上我'我试图开发或部署到).这是你用来唱歌的命令:
php -d vld.execute=0 -d vld.active=1 -f foo.php
Run Code Online (Sandbox Code Playgroud)
查看操作码将告诉你一个更完整的故事,但是,我有一个猜测......大多数PHP的内置函数都会复制一个数组/对象并对该副本起作用(而不是写入时复制)或者,立即复制).最广为人知的例子是foreach().当您将数组传递给foreach()时,PHP实际上正在制作该数组的副本并在副本上进行迭代.这就是为什么你会通过将数组作为参考传递给foreach来看到显着的性能优势,如下所示:
foreach($ someReallyBigArray为$ k =>&$ v)
但是这种行为 - 传递一个像这样的显式引用 - 对foreach()来说是唯一的.如果它更快地检查array_key_exists(),我会非常惊讶.
好的,回到我得到的......
大多数内置函数都会获取数组的副本并对该副本执行操作.我将冒险尝试完全无条件的猜测,即isset()已经过高度优化,其中一个优化可能是在传入时不立即复制数组.
我会尝试回答你可能遇到的任何其他问题,但你可能会阅读很多google的"zval_struct"(这是PHP内部存储每个变量的数据结构.它是一个C结构(想想......)关联数组)具有"value","type","refcount"等键.
不是 array_key_exists,而是删除引用 (= NULL) 导致此情况。我从你的脚本中注释掉了它,这就是结果:
array_key_exists( $my_array ) 0.0059430599212646
isset( $my_array ) 0.0027170181274414
array_key_exists( $my_array_ref ) 0.0038740634918213
isset( $my_array_ref ) 0.0025200843811035
Run Code Online (Sandbox Code Playgroud)
只去掉了取消设置的array_key_exists( $my_array_ref )部分,这是修改后的部分供参考:
$my_array = array();
$my_array_ref = &$my_array;
$start = microtime( TRUE );
for( $i = 1; $i < 10000; $i++ ) {
array_key_exists( $i, $my_array_ref );
// $my_array_ref[$i] = NULL;
}
$stop = microtime( TRUE );
print "array_key_exists( \$my_array_ref ) ".($stop-$start).PHP_EOL;
unset( $my_array, $my_array_ref, $start, $stop, $i );
Run Code Online (Sandbox Code Playgroud)