如何销毁一个对象?

137
据我所知(了解很少),有以下两种方法:
$var = new object()

那么:

// Method 1: Set to null
$var = null;
// Method 2: Unset 
unset($var); 

还有更好的方法吗?我在这里太纠结了吗?

6个回答

171

你需要使用unset()

但要注意,你不能显式销毁对象

对象将继续存在,但如果你使用 unset() 函数并且你的脚本将 PHP 推到内存限制,那么未被使用的对象将被垃圾回收。我建议使用 unset()(而非将其设置为 null),因为这似乎具有更好的性能(虽然未经测试,但在PHP官方手册的一条评论中有记录)。

话虽如此,请记住PHP总是在页面提供服务时立即销毁对象。因此,这只在真正长的循环和/或大量运行的页面上需要。


1
所以,Frankie,我来自C++,在那里当我们使用new一次时,就必须使用delete一次。这在PHP中不是真的吗?当对象不再需要时,有自动垃圾回收吗? - gsamaras
3
@gsamaras说得没错。但是即使如此,你也可能会出现内存泄漏的情况,如果你正在处理守护进程或类似任务,建议你多了解一下PHP垃圾回收机制。在大多数网站中,请求的生命周期非常短,因此这并不重要。http://php.net/manual/en/features.gc.refcounting-basics.php - Frankie
1
unset()函数是否会删除对对象的引用? - Yousha Aleayoub
这个答案在2021年仍然适用吗?这是UnitTesting所需的,这个概念在2012年并不是很普及。 - clockw0rk
1
@Rodrigo 我建议你在循环内部使用 memory_get_usage() 进行检查,因为这取决于你在循环中做了什么额外的操作以及你实际需要多少内存。你无法真正控制 PHP 何时调用 freemallocs。理论上,重复使用变量意味着不需要重新分配内存空间,符号表条目也不需要重新创建和相应的管理对象。但这并不总是成立。 - undefined
显示剩余2条评论

9

一篇有用的文章,解释了几个关于此的误解:

不要显式调用析构函数

这篇文章涵盖了关于析构函数如何工作的几个误解。根据PHP5文档,显式调用析构函数实际上不会销毁您的变量:

PHP 5引入了类似于其他面向对象语言(如C ++)的析构函数概念。当没有其他引用特定对象时,析构函数将立即被调用,或者在关闭序列期间以任何顺序调用。

上面的文章确实表明,在一些情况下,将变量设置为null可以起作用,只要没有其他东西指向已分配的内存即可。


5

简短回答:两者都需要。

我觉得给出了正确的答案,但是很简略。通常情况下,unset() 是最好的选择,因为它更快,但是如果你想立即回收内存(以 CPU 为代价),应该使用 null。

就像其他人提到的,将其设置为 null 并不意味着所有东西都被回收,你可能会有共享内存(未克隆)对象,这将防止对象的销毁。此外,正如其他人所说,你无法明确地“销毁”对象,因此也不应该尝试这样做。

你需要找出哪个更适合你。此外,你可以为一个对象使用 __destruct(),它将在 unset 或 null 上调用,但应小心使用,并且绝不能直接调用!

参见:

http://www.stoimen.com/blog/2011/11/14/php-dont-call-the-destructor-explicitly/

赋值NULL和unset有什么区别?


1

可能会遇到创建一个新的mysqli对象的情况。

$MyConnection = new mysqli($hn, $un, $pw, $db);

但即使你关闭了这个对象

$MyConnection->close();

如果你使用print_r()检查$MyConnection的内容,你将会得到以下错误:

Error:
mysqli Object

Warning: print_r(): Property access is not allowed yet in /path/to/program on line ..
( [affected_rows] => [client_info] => [client_version] =>.................)

在这种情况下,您不能使用 unlink(),因为 unlink() 需要一个路径名字符串,但在这种情况下,$MyConnection 是一个对象。
所以你有另一种选择,将其值设置为 null: $MyConnection = null; 现在事情顺利进行,就像您所预期的那样。您没有任何内容在变量 $MyConnection 中,而且您已经清理了 mysqli 对象。
在将变量的值设置为 null 之前关闭对象是一个推荐的实践。

0
在PHP中,你不是销毁一个对象,而是销毁指向该对象的指针。这是一个很大的区别。
在其他语言中,你可以销毁一个对象,所有其他指针都会给你异常或垃圾,但在PHP中不是这种情况。
这是一个简单的证明,你不能销毁一个对象,只能销毁指向它的链接。
$var = (object)['a'=>1];
$var2 = $var;
$var2->a = 2;
unset($var2);
echo $var->a;

返回

2

在这里查看它的运行效果:https://eval.in/1054130


3
没错,你已经销毁了$var2这个指向$var的引用。现在你也销毁了$var,假设没有其他引用指向这个对象,那么你就完成了任务。 - i336_
7
您所摧毁的并非对象,而是指针(pointer)指向该对象的位置。这两者之间有很大的区别。 - Yevgeniy Afanasyev
1
在其他语言中,您可以销毁一个对象,所有其他指针将给您异常或垃圾,但这不是 PHP 的情况。 - Yevgeniy Afanasyev
1
你不能销毁一个对象。当没有引用持有该对象时,该对象会被垃圾回收器回收。你也不能强制运行垃圾回收器。 - Daniel

-9
我会选择使用unset,因为它可能会给垃圾回收器一个更好的提示,以便内存可以更快地再次可用。请注意,对象指向的任何东西都必须有其他引用或先被取消设置,否则您真的必须等待垃圾回收器,因为它们将没有句柄。

17
除非你真的有支持你回答的来源,否则最好不要发布你认为“可能”会发生的事情。这样做没有帮助,反而会导致这种错误信息被误认为是真相并被重复传播。 - user229044
1
@meagar,这正是我链接到官方手册页面的确切原因,在那里的评论中,有一个比较unset()和null的示例测试。 - Frankie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接