12

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

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

但是,我相信适合我班级的地方是在班级的析构函数中调用imagedestroy

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

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

4

4 回答 4

14

我刚刚用 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 中按 STOP 按钮不会停止此脚本
  • 如果我关闭 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 被调用。所以这意味着类析构函数不如关闭函数好。

于 2008-10-25T18:47:11.970 回答
2

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

析构函数将在对象被释放时被调用,而关闭函数在脚本执行完成之前不会被调用。正如 Wolfie 所指出的,如果您强制停止服务器或脚本,这些情况不一定会发生,但到那时,PHP 分配的内存无论如何都会被释放。

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

于 2008-10-25T23:25:11.037 回答
1

我最近遇到了麻烦,因为我试图专门针对服务器超时的情况处理破坏,并且我想在错误日志中包含类数据。引用 &$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);
        }
    }

    ...

希望这对某人有帮助!

于 2015-07-29T02:24:17.440 回答
0

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

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

但是,在类析构函数的主题上,只要对象被显式销毁unset()或在脚本完成/终止时,就会调用它们。

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

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

于 2008-10-25T18:28:37.123 回答