我有一个 PHP 类,可以动态创建 PNG 图像并将其发送到浏览器。PHP 手册说我需要确保 图像销毁 最后调用函数来释放内存。现在,如果我不使用类,我会有这样的代码:

function shutdown_func() 
{
    global $img;
    if ($img)
        imagedestroy($img);
}
register_shutdown_function("shutdown_func");

但是,我认为适合我的课程的地方是拨打电话 图像销毁 在类的析构函数中。

我没能弄清楚析构函数是否以与关闭函数相同的方式被调用?例如,如果当用户按下浏览器中的“停止”按钮时执行停止。

笔记:无论您在答案中写什么,请指出支持它的一些文章或手册页 (URL)。

有帮助吗?

解决方案

我刚刚使用 Apache 进行了测试,PHP 被用作 Apache 模块。我创建了一个这样的无限循环:

<?php
class X
{
    function __destruct()
    {
        $fp = fopen("/var/www/htdocs/dtor.txt", "w+");
        fputs($fp, "Destroyed\n");
        fclose($fp);
    }
};

$obj = new X();
while (true) {
    // do nothing
}
?>

这是我发现的:

  • 在 Firefox 中按“停止”按钮不会停止此脚本
  • 如果我关闭 Apache,析构函数不会被调用
  • 当达到 PHP max_execution_time 并且析构函数不会被调用时它会停止

但是,这样做:

<?php
function shutdown_func() {
    $fp = fopen("/var/www/htdocs/dtor.txt", "w+");
    fputs($fp, "Destroyed2\n");
    fclose($fp);
}
register_shutdown_function("shutdown_func");

while (true) {
    // do nothing
}
?>

shutdown_func 被调用。所以这意味着类析构函数不如关闭函数那么好。

其他提示

基于你应该完成你的开始的原则,我会说析构函数是免费通话的正确位置。

当对象出现时,将调用析构函数处置,而关闭功能将被调用,直到脚本执行完成。正如Wolfie所指出的,如果你强行停止服务器或脚本,这些不一定会发生,但那时,PHP分配的内存无论如何都会被释放。

Wolfie还指出,PHP将在脚本关闭时释放脚本资源,因此如果您只是实例化其中一个对象,那么您可能不会注意到巨大的差异。但是,如果你以后最终会实例化这些东西,或者在循环中这样做,那么你可能不想担心内存使用量的突然增加,所以为了未来的理智,我会回到我的身边。原始推荐;把它放在析构函数中。

我最近遇到了麻烦,因为我试图专门针对服务器遇到超时并且我想在错误日志中包含类数据的情况来处理销毁。在引用&amp; $ this时我会收到一个错误(虽然我已经看过它在一些例子中完成,可能是版本问题或symfony副作用),而我提出的解决方案相当干净:

class MyClass
{
    protected $myVar;

    /**
     * constructor, registers shutdown handling
     */
    public function __construct()
    {
        $this->myVar = array();

        // workaround: set $self because $this fails
        $self = $this;
        // register for error logging in case of timeout
        $shutdown = function () use (&$self) {
            $self->shutdown();
        };
        register_shutdown_function($shutdown);
    }

    /**
     * handle shutdown events
     */
    public function shutdown()
    {
        $error = error_get_last();
        // if shutdown in error
        if ($error['type'] === E_ERROR) {
            // write contents to error log
            error_log('MyClass->myVar on shutdown' . json_encode($this->myVar), 0);
        }
    }

    ...

希望这有助于某人!

我认为您错过的一件大事是,一旦脚本终止,PHP 在脚本执行期间分配的所有内存都会被释放。即使用户按下停止按钮,PHP 也会处理脚本直到完成,将其返回给 HTTP 守护进程以向访问者提供服务(或不返回,取决于守护进程的聪明程度)。

因此,在脚本执行结束时显式释放内存有点多余。有些人可能会认为这是一件好事,但它仍然是多余的。

但是,关于类析构函数,每当对象被销毁时就会调用它们,无论是通过 unset() 或在脚本完成/终止时。

开发人员建议明确释放图像处理中使用的内存,这只是为了绝对确保不会出现内存泄漏,因为位图可能会导致内存方面的压力(高度 * 宽度 * 位深度 * 3 (+ 1 如果您有 Alpha 通道))

为了满足您的维基百科需求:

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top