橡皮擦擦

Yii2 echo输出导致 Headers already sent 解决方法

PHP

因为在Yii中使用了topthink/think-template模板引擎,输出模板的时候触发了Yii Response类的异常。


An Error occurred while handling another error:
yii\web\HeadersAlreadySentException: Headers already sent in \vendor\topthink\think-template\src\Template.php on line 194. in \vendor\yiisoft\yii2\web\Response.php:366
Stack trace:
#0 \vendor\yiisoft\yii2\web\Response.php(339): yii\web\Response->sendHeaders()
#1 \vendor\yiisoft\yii2\web\ErrorHandler.php(135): yii\web\Response->send()
#2 \vendor\yiisoft\yii2\base\ErrorHandler.php(111): yii\web\ErrorHandler->renderException(Object(yii\web\HeadersAlreadySentException))
#3 [internal function]: yii\base\ErrorHandler->handleException(Object(yii\web\HeadersAlreadySentException))
#4 {main}
Previous exception:
yii\web\HeadersAlreadySentException: Headers already sent in \vendor\topthink\think-template\src\Template.php on line 194. in \vendor\yiisoft\yii2\web\Response.php:366
Stack trace:
#0 \vendor\yiisoft\yii2\web\Response.php(339): yii\web\Response->sendHeaders()
#1 \vendor\yiisoft\yii2\base\Application.php(392): yii\web\Response->send()
#2 \backend\web\index.php(17): yii\base\Application->run()
#3 {main}

随之百度一下,说是在操作echo/var_dump/print_r之后在结尾die或者exit可以解决...唔,测试了一下确实可以,但是!这么丑的解决办法肯定不是最好的方案。如果直接die或者exit的话以后可能会导致各种猎奇问题产生(如:debug记录缺失、cli异常结束、回调方法失效等),那就看一下源码吧。

/**
 * Sends the response headers to the client.
 */
protected function sendHeaders()
{
    if (headers_sent($file, $line)) {
        throw new HeadersAlreadySentException($file, $line);
    }
    if ($this->_headers) {
        foreach ($this->getHeaders() as $name => $values) {
            $name = str_replace(' ', '-', ucwords(str_replace('-', ' ', $name)));
            // set replace for first occurrence of header but false afterwards to allow multiple
            $replace = true;
            foreach ($values as $value) {
                header("$name: $value", $replace);
                $replace = false;
            }
        }
    }
    $statusCode = $this->getStatusCode();
    header("HTTP/{$this->version} {$statusCode} {$this->statusText}");
    $this->sendCookies();
}

在yiiwebResponse里sendHeaders方法执行前进行了headers_sent()的验证,所以导致了异常的产生。解决方法就是在模板输出前先把headers设置好,所以在基类控制器重写了模板输出的fetch()方法,并在执行前先使用Response->send()设置headers。代码如下:

/**
 * 重写模板渲染
 * @access public
 * @param string    $template 模板文件
 * @param array     $vars 模板变量
 * @param array     $config 模板参数
 * @return void
 */
protected function fetch($template, $vars = [], $config = []) : void
{
    Yii::$app->response->send();

    $this->view->fetch($template,$vars,$config);
}

最后吐槽一句,还是Tp 5用着舒服!目前为止除了gii这个东西之外,完全感受不出Yii哪里好用了,特别是Yii的Orm真的是...用着很难受 囧

点我评论
打赏本文
二维码


30

文章

6

分类