通过引用传递参数时发生致命错误

时间:2018-07-26 11:40:23

标签: php fatal-error php-7.0

在我们的PHP应用程序中,有一个函数可以在收集发送过程的日志时使用PHPMailer发送邮件:

function sendWithLog(PHPMailer $mail, &$debug_log, $log_level = PHPMailer_SMTP::DEBUG_CONNECTION) {
    $debug_log = [];
    $mail->SMTPDebug = $log_level ?: PHPMailer_SMTP::DEBUG_CONNECTION;
    $mail->Debugoutput = function($message) use(&$debug_log) {
        $debug_log[] = $message;
    };

    $sent = $mail->send();

    $debug_log = !$sent
                ? $mail->ErrorInfo
                . ($debug_log ? "\n" . implode("\n", $debug_log) : "")
                : "";

    return $sent;
}

因此,通过引用传递的变量$debug_log首先应初始化为空数组,最后将其制成字符串。

如果再次调用该函数,并将其作为上一次调用的$debug_log的{​​{1}}传递,我会看到此错误:

  

PHP致命错误:未捕获错误:字符串不支持[]运算符

但是,在用$debug_log语句绑定到闭包之前,该变量仍应初始化为空数组,因此我真的不明白该错误怎么发生。

我尝试使用简化版本的代码here重现此行为,但似乎并未触发错误。

编辑:

我通过更改如下功能解决了这个问题:

use()

但是,我仍然想知道它最初如何触发错误。

用法示例如下:

function sendWithLog(PHPMailer $mail, &$debug_log, $log_level = PHPMailer_SMTP::DEBUG_CONNECTION) {
    $messages = []; // <-- different variable for collecting the log messages!
    $mail->SMTPDebug = $log_level ?: PHPMailer_SMTP::DEBUG_CONNECTION;
    $mail->Debugoutput = function($message) use(&$messages) {
        $messages[] = $message;
    };

    $sent = $mail->send();

    $debug_log = !$sent
                ? $mail->ErrorInfo
                . ($messages ? "\n" . implode("\n", $messages) : "")
                : "";

    return $sent;
}

编辑2

这是示例堆栈跟踪:

// $users -> query result from database
while($user = $users->fetch()) {
  // build mail and then
  $sent = sendWithLog($mail, $mail_log);
  // here $mail_log should be initialized to NULL the first time by the PHP engine
  // and in subsequent calls it is the log string of the previous call which should be
  // reset to [] first thing inside the function call

  if(!$sent) {
    error_log("ERROR SENDING MAIL: $mail_log");
  }
}

1 个答案:

答案 0 :(得分:1)

刚刚太久了,无法发表评论,所以让我在这里输入:

考虑到您的示例,我唯一想到的就是-我不确定这里的内部工作原理,但是无论如何,我还是要解释一下-

您将$mail->Debugoutput设置为可调用项,将一项附加到$debug_log。现在,在函数结束时,将$debug_log设置为字符串($debug_log = !$sent等),设置字符串期间,可能会发生以下情况:当由于某种原因而发生字符串串联时发生的implode()$mail->Debugoutput又被调用了(可能是在__toString()期间吗?),它试图将数组项附加到$debug_log,这是不可能的,因为它被设置为字符串。因此是错误。