图像处理-PHP:析构函数与register_shutdown_function


image processing - PHP: destructor vs register_shutdown_function

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

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

然而,我相信我的类的合适位置是在类的析构函数中调用imagedestroy

我没有发现析构函数是否像关闭函数那样被调用?例如,如果用户在浏览器中按下STOP按钮时执行停止。

注意:无论你在答案中写什么,请指向支持它的文章或手册页面(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并且未调用destuctor时,它将停止

然而,这样做:

<?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。所以这意味着类destuctor不如关闭函数好。

基于应该完成开始的工作的原则,我认为析构函数是进行免费调用的正确位置。

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

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

我最近遇到了这个问题,因为我试图处理销毁,特别是在服务器超时的情况下,我想在错误日志中包括类数据。当引用&这(尽管我在一些例子中看到过,可能是版本问题或符号副作用),我提出的解决方案相当干净:

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(如果有alpha通道,则为+1))

满足您的维基需求:

  • http://php.net/manual/en/language.oop5.decon.php
  • http://php.net/manual/en/function.unset.php