我意识到第二种方法避免了函数调用的开销(更新,实际上是一种语言构造),但知道其中一种方法是否比另一种更好会很有趣。我的大部分代码都使用unset(),但最近我在网上找到了一些使用$var = null的体面类。

是否有一个首选的,理由是什么?


当前回答

在2009年的unset手册页面中提到:

unset() does just what its name says - unset a variable. It does not force immediate memory freeing. PHP's garbage collector will do it when it see fits - by intention as soon, as those CPU cycles aren't needed anyway, or as late as before the script would run out of memory, whatever occurs first. If you are doing $whatever = null; then you are rewriting variable's data. You might get memory freed / shrunk faster, but it may steal CPU cycles from the code that truly needs them sooner, resulting in a longer overall execution time.

(自2013年起,未设置的手册页不再包括该部分)

注意,在php5.3之前,如果循环引用中有两个对象,例如在父子关系中,在父对象上调用unset()将不会释放用于子对象中父引用的内存。当父对象被垃圾回收时,内存也不会被释放。


问题“unset和= null之间的差异”详细说明了一些差异:


Unset ($a)也从符号表中删除$a;例如:

$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);

输出:

Notice: Undefined variable: a in xxx
NULL

但是当使用$a = null时:

$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);

输出:

NULL

$a = null似乎比它的unset()对手快一点:更新符号表项似乎比删除它快。


当您尝试使用不存在(未设置)变量时,将触发一个错误,变量表达式的值将为null。(因为,PHP还应该做什么?每个表达式都需要产生某个值。) 一个赋值为null的变量仍然是一个完全正常的变量。

其他回答

Unset实际上不是一个函数,而是一种语言结构。与其说它是一个函数调用,不如说它是一个return或include。

除了性能问题,使用unset可以使代码的意图更加清晰。

对于通过引用复制的变量,它的工作方式不同:

$a = 5;
$b = &$a;
unset($b); // just say $b should not point to any variable
print $a; // 5

$a = 5;
$b = &$a;
$b = null; // rewrites value of $b (and $a)
print $a; // nothing, because $a = null

通过对变量执行unset()操作,您实际上已经将变量标记为“垃圾收集”(PHP实际上并没有这样的功能,但为了举例说明),因此内存不能立即可用。该变量不再存储数据,但堆栈仍然保持较大的大小。执行null方法几乎会立即丢弃数据并缩小堆栈内存。

这是我个人的经验,也是别人的经验。在这里查看unset()函数的注释。

我个人在循环的迭代之间使用unset(),这样我就不必在大小上有堆栈的延迟。数据消失了,但足迹还在。在下一次迭代时,内存已经被php占用,因此可以更快地初始化下一个变量。

我为unset和=null创建了一个新的性能测试,因为正如在评论中提到的,这里写的有一个错误(重新创建元素)。 我用的是数组,你们看,现在无所谓了。

<?php
$arr1 = array();
$arr2 = array();
for ($i = 0; $i < 10000000; $i++) {
    $arr1[$i] = 'a';
    $arr2[$i] = 'a';
}

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $arr1[$i] = null;
}
$elapsed = microtime(true) - $start;

echo 'took '. $elapsed .'seconds<br>';

$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    unset($arr2[$i]);
}
$elapsed = microtime(true) - $start;

echo 'took '. $elapsed .'seconds<br>';

但是我只能在PHP 5.5.9服务器上测试它,结果如下: -耗时4.4571571350098秒 -耗时4.4425978660583秒

出于可读性考虑,我更喜欢不设置。

<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    $a = NULL;
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\r\n";



$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
    $a = 'a';
    unset($a);
}
$elapsed = microtime(true) - $start;

echo "took $elapsed seconds\r\n";
?>

根据这一点,“= null”似乎更快。

PHP 5.4结果:

花了0.88389301300049秒 耗时2.1757180690765秒

PHP 5.3结果:

耗时1.7235369682312秒 用时2.9490959644318秒

PHP 5.2结果:

花了3.0069220066071秒 耗时4.7002630233765秒

PHP 5.1结果:

花了2.6272349357605秒 耗时5.0403649806976秒

在PHP 5.0和4.4中,情况开始有所不同。

5.0:

花了10.038941144943秒 耗时7.0874409675598秒

4.4:

耗时7.5352551937103秒 花了6.6245851516724秒

请记住,microtime(true)在PHP 4.4中不起作用,因此我必须使用php.net/microtime /示例#1中给出的microtime_float示例。