首页 > 解决方案 > 如何在 foreach 循环中使用输出缓冲区?

问题描述

我正在构建一个简单的类,它可以通过模板包含和我在输出缓冲区中提取的数据数组的组合为我的电子邮件正文生成 html。

问题是,当我在循环内使用输出缓冲区运行该方法时(根据用户信息创建电子邮件),我收到以下错误:

ob_end_clean():删除缓冲区失败。没有要删除的缓冲区...无法修改标头信息-标头已由...发送

我必须更改什么才能使其既适用于单个电子邮件又适用于循环内?

电子邮件类

<?php
class Email {

   protected $_html;

   protected $_data;

   public function __construct( array $email_data = [] ) {
      $this->_data = $email_data;
      $this->generate_html();
   }

   protected function generate_html() {
      $template_path = 'path/to/email-template.php';
      ob_start();
      extract( $this->_data );
        include $template_path;
      $this->_html = ob_get_contents();
      ob_end_clean();
   }

   public send( $to = [] ) {
      mail( $to, 'Test email', $this->_html, ['Content-Type: text/html; charset=UTF-8'] );
   }

}
?>

测试我的代码:

<?php 
function send_test_email( $id, $to ) {
   $email_data = [
      'id'    => $id,
      'name'  => 'Joe',
      'price' => '30.00'
   ];
   $email = new Email( $email_data );
   $email->send( $to );
}

// Works
send_test_email( 122, 'joe@example.com' );

// Does not work
// ob_end_clean(): failed to delete buffer. No buffer to delete in
// Cannot modify header information - headers already sent by ...
foreach ( $users as $user ) {
   send_test_email( $user->id, $user->email );
}
?>

标签: phpbuffer

解决方案


让我们看看输出缓冲区是如何工作的:

// Works
send_test_email( 122, 'joe@example.com' );

/*
    When you have executed send_test_email() above the method generate_html() is 
    executed and ob_start and ob_end_clean() is executed. This means that the output 
    buffer is initiated and stopped with ob_end_clean(). 

    When output buffer is ended it is sent to the client (browser).
*/

//If you do the same again...
send_test_email( 122, 'joe@example.com' );

/*
  ...this won't work because output buffer is sent to the browser. After this is done
  you are not able to modify header information. Because you cannot modify header 
  information you can not start a new output buffer either.

  That is why you get the error below:

  ob_end_clean(): failed to delete buffer. No buffer to delete in
  Cannot modify header information - headers already sent by ...
*/

为了解决这个问题,我会尝试这样的事情:

移出ob_start()和移出ob_end_clean() 并将它们从方法中删除generate_html()

protected function generate_html() {
    $template_path = 'path/to/email-template.php';
    extract( $this->_data );
    include $template_path;
    $this->_html = ob_get_contents();
}

测试你的代码:

ob_start();
send_test_email( 122, 'joe@example.com' );

foreach ( $users as $user ) {
   send_test_email( $user->id, $user->email );
}
ob_end_clean();

更新 您可以在不弄乱输出缓冲区的情况下解决这个问题,例如:

protected function generate_html() {
    $template_path = 'path/to/email-template.php';
    extract( $this->_data );

    //requires the template file to have a return to able to store the
    //content in a variable
    //
    //Look at $foo = include 'return.php'; 
    //at https://www.php.net/manual/en/function.include.php
    $this->_html = include $template_path; 
}

推荐阅读