在一般我们执行循环操作的时候,都会采用自增变量(++)或自减变量(--)的方式来进行。
i的不同之处,在我们初学程序的时候都会理解。
在PHP的手册中,可以看到一段这样的话:
通过这张图片不难看出,i前者是先返回,再加一,而后者是先加一,再返回。
但是如果我们使用如下的代码:
<?php
echo '$i++'."\n";
for($i=0;$i<10;$i++){
echo $i."\n";
}
echo '++$i'."\n";
for($i=0;$i<10;++$i){
echo $i."\n";
}
最终得到的结果却是一样的。
$i++
0
1
2
3
4
5
6
7
8
9
++$i
0
1
2
3
4
5
6
7
8
9
究其原因,无论是++i还是i++,都是在本次循环结束后再进行取值的。
我们举个例子:
<?php
$i=0;
++$i;
echo $i."\n";
$i=0;
$i++;
echo $i."\n";
die;
最终得到的结果是:
$ /program/bin/php/php7/bin/php pp.php
1
1
因此无论是i,对于循环体中的代码块调用的都是同样的内容。
那么,i的方式,究竟有多大的区别呢?
我们通过gdb来输出一下$i++的流程可以看出,其执行的顺序是这样的:
ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:39440
ZEND_POST_INC_SPEC_CV_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:34576
ZEND_FREE_SPEC_TMPVAR_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:51415
ZEND_RETURN_SPEC_CONST_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:2858
这个方法会生成一个临时变量,来存储当前++后的值。
而++$i的执行过程是这样的:
ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:39440
ZEND_PRE_INC_SPEC_CV_RETVAL_UNUSED_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:34420
ZEND_RETURN_SPEC_CONST_HANDLER () at /program/php-7.1.0/Zend/zend_vm_execute.h:2858
这个过程是直接赋值,然后返回的。
理论上,++i++的方式更节省时间,我们来测试一下:
$ cat pp.php
<?php
$time=microtime_float();
echo '开始时间为:'.$time."\n";
for($i=0;$i<10000000;$i++){}
$timepp=microtime_float();
echo '$i++的执行时间: ',$timepp-$time,"\n";
for($i=0;$i<10000000;++$i){}
$pptime=microtime_float();
echo '++$i的执行时间: ', $pptime-$timepp,"\n";
echo '二者之间的差值: ',($timepp-$time)-($pptime-$timepp),"\n";
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
看一下执行结果:
$ /program/bin/php/php7/bin/php pp.php
开始时间为:1583119859.6322
$i++的执行时间: 0.22519993782043
++$i的执行时间: 0.17001795768738
二者之间的差值: 0.055181980133057
由此可见,执行1千万次++i++操作后,二者之间的差值仅为0.05秒,差距并不是很大。
为了养成好习惯,循环中建议使用++$i这种形式
但节省的这点时间,倒不如检查一下循环体中的内容,是否有可优化之处。
网友评论