在 PHP 中,输出缓冲区打印到哪里?什么东西打印到它


In PHP, where does the output buffer print to? What things print to it?

PHP 有许多不同的打印方式,我不明白它们之间的区别。至少有以下几点:

  • Stdout 和 Stderr。这些可以表示为 php://stdoutphp://stderr .还有常数STDOUTSTDERR,我认为它们指的是同一件事。目前为止,一切都好;这些是标准的。
  • php://output .这是怎麽?它去哪儿了?它是php://stdout的同义词,还是别的什么?文档说它写入"输出缓冲区机制",但我不知道这个缓冲区的内容之后去了哪里。
  • printecho .文档说这些打印到php://output.它们都是语言结构,但猜测一下,区别在于print是一个表达式,而echo是一个语句。
  • printf和许多朋友。这些也都去php://output吗?
  • 逃避。有很多用于转义的替代语法,但我猜它们都具有相同的语义。但是语义是什么?转义文本打印到哪里?还要php://output?目前,我将?>foo<?php理解为echo 'foo';的句法糖;这是对的吗?

还有更多输出方法吗?究竟有什么区别?哪些设置和环境会影响他们的行为?

首先,stdin 和 stdout 是大多数语言都有的标准输入和输出流。 如果要通过控制台运行 php,则可以创建如下脚本:

$input = fopen("php://stdin", "r");
$line = trim(fgets($input));
echo $line;

$line = trim(fgets(STDIN));
echo $line;

这些脚本将打开标准控制台输入,并允许您输入由返回终止的输入。

现在从命令行"php://stdout"和"php://output"功能非常相似,假设默认情况下没有打开输出缓冲,并且都将为您提供控制台的标准输出。通过执行以下操作:

$out = fopen("php://stdout", "w");
fwrite($out, "Hello World!");

$out = fopen("php://output", "w");
fwrite($out, "Hello World!");

这两者都将按预期将 Hello World! 输出到控制台。

现在关于输出缓冲,它在 php 配置文件中默认设置为 0(意味着它被禁用(。 输出缓冲是一种"阻止"输出的方法,无论是写入控制台还是浏览器。 如果使用ob_start函数打开输出缓冲,则任何输出都不会转到控制台/浏览器。 相反,它将被放入缓冲区中并等待缓冲区达到其最大容量(或直到您手动刷新它(,然后它将缓冲区内容转储到 stdout。

继续打印和回显。这些不是真正的函数,它们是语言结构,其中 echo 不返回任何内容,打印始终返回 1。 两者之间的主要区别在于 echo 可以打印多个由逗号分隔的字符串。

打印和回显都打印到输出缓冲区,但由于默认情况下禁用了输出缓冲,因此它们似乎直接输出到控制台/浏览器。

现在至于 php://output 和STDOUT之间的区别。只有打开输出缓冲才会有明显的差异。 如果它已打开,则 stdout 输出仍将转到控制台/浏览器的标准输出,但 php://output 将转到缓冲区,直到缓冲区达到其容量或您手动刷新缓冲区。 此示例说明了差异:

<?php
    $out1 = fopen("php://stdout", 'w');
    $out2 = fopen("php://output", "w");
    ob_start();   //enable output buffering
    echo "This is an echo'n";
    print "This is a print'n";
    printf("%d", 52);
    echo "'n";
    fwrite($out1, "Hello World!");
    fwrite($out2, "'nGoodbye World!");
    ob_end_clean(); //turn off output buffering and get rid of it's contents without printing them
?>

请注意,此脚本中只有 Hello World! 是输出,而不是其余的输出语句。 如果我们注释掉 ob* 语句,则会看到所有其他输出都放在输出缓冲区中。 如果我们在脚本末尾使用 ob_end_flush((,我们将 Hello World!后跟输出缓冲区的所有输出,按放入缓冲区的顺序排列。 此外,从这个例子中我们还可以看到 printf 也打印到输出缓冲区(可能使用 echo 或 print 的底层功能(,我假设这就是所有其他格式化函数的工作方式,但不要引用我的话。

就您所指的转义而言,这通常是为了有条件地显示html,或者当您有一系列不想硬编码的内容时。例如,考虑:

<select>
<? foreach($array as $option){ ?>
    <option value="<?=$option?>"><?=$option?></option>
<? }?>
</select>

此代码可用于输出选择的选项数组,而无需硬编码值,也无需使用写入回显或打印或打印语句(注意 echo 通过语法间接使用(。

令人惊讶的是,此输出也会写入输出缓冲区,并包含您在此区域中输入的任何空格,但前提是您在控制台上(浏览器对空格的解释不同(。 此外,转义字符,如 '、''t 等。在此上下文中没有任何意义,并且完全按照所见进行解释。这可以通过将上面的代码修改为:

<?php
$out1 = fopen("php://stdout", 'w');
$out2 = fopen("php://output", "w");
//ob_start();
echo "This is an echo'n";
print "This is a print'n";
printf("%d", 52);
echo "'n";
?>
Jelly Bean
<?php
fwrite($out1, "Hello World!");
fwrite($out2, "'nGoodbye World!");
//ob_end_clean();
?>

如您所见,当输出缓冲语句被注释掉时,会打印 Jelly Bean,但如果在 Jelly Bean 中注释它们,则不会出现在输出中。 同样,如果您取消注释 ob* 语句并将最后一个语句设为 ob_end_flush((,您将看到从缓冲区输出到 stdout 的所有输入,按照放入缓冲区的顺序。