在PHP中重定向I/O

在PHP中重定向I/O,php,Php,为什么到新STDOUT的重定向隐式工作,而从新STDIN的重定向必须显式发生?原始STDIN、STDOUT和STDERR是PHP中的系统常量。它们由PHP初始化时的标准输入、输出和错误的文件描述符资源填充 php.net文档描述了以下有关常量中资源的内容: 常数的值;只允许使用标量值和空值。 标量值是整数、浮点、字符串或布尔值。它是 可以定义资源常量,但不建议这样做 并可能导致不可预测的行为 调用fclose(STDOUT)时,文件描述符资源将关闭并与STDOUT常量分离。与常量的默认行为相反,

为什么到新STDOUT的重定向隐式工作,而从新STDIN的重定向必须显式发生?

原始STDIN、STDOUT和STDERR是PHP中的系统常量。它们由PHP初始化时的标准输入、输出和错误的文件描述符资源填充

php.net文档描述了以下有关常量中资源的内容:

常数的值;只允许使用标量值和空值。 标量值是整数、浮点、字符串或布尔值。它是 可以定义资源常量,但不建议这样做 并可能导致不可预测的行为

调用
fclose(STDOUT)
时,文件描述符资源将关闭并与STDOUT常量分离。与常量的默认行为相反,STDOUT常量被更改

当一个字符串像
echo“Hello,World!”
那样被回送时,PHP将不使用STDOUT常量,但它将从操作系统实时查询当前的“standard out”文件描述符。此外,一旦标准输出常量被fclose'd,它本身就变得不可用。即使像
fwrite(STDOUT,“hello”)
这样的语句也不会起作用

为标准输出配置新文件描述符时,此新文件描述符将方便地放入
$STDOUT
。请注意,这是一个变量,而不是常量。根据定义,在PHP中不可能重新定义常量,系统常量STDOUT在这里也不例外。目前无法将新文件描述符重新分配给标准输出常量


最后,为了使这项工作更直观,PHP团队应该考虑使用便利功能来重新分配这些文件描述符,或者至少使系统常量更像“魔术常数”。从某种意义上说,它们会自动计算为实际的文件描述符。

我在阅读代码片段时首先看到的是,首先尝试关闭STDIN、STDOUT等的常量,然后使用同名变量打开文件;因此,您使用的值是完全不同的,$STDIN与STDIN不同。您可能可以使用define函数重新定义STDIN,但我不确定,也无法在没有计算机atm的情况下进行检查。

这仅在类UNIX系统(linux等)中发生,因为当您打开文件时,UNIX使用次要文件描述符,因此在进程STDIN中,STDOUT和STDERR始终为0、1和2。 执行此操作时:

<?php
    fclose(STDIN);
    fclose(STDOUT);
    fclose(STDERR);

    $STDIN = fopen("/tmp/some-named-pipe", "r");
    $STDOUT = fopen("/tmp/foo.out", "wb");
    $STDERR = fopen("/tmp/foo.err", "wb");

    echo "Hello, World!";                 // goes to /tmp/foo.out, implied STDOUT
    fscanf($STDIN, "%s\n", $top_secret);  // explicit $STDIN, cant use STDIN
?>

您正在关闭STDIN(0)、STDOUT(1)和STDERR(2),因此当您以相同的顺序打开文件时,它们会得到0、1和2作为文件描述符。如果在windows上运行相同的代码,它将无法工作。

这是多次重定向标准输出的示例。 STDOUT的关闭第一次有效,但下一次有效 需要关闭$STDOUT

fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);

$STDIN = fopen("/tmp/some-named-pipe", "r");
$STDOUT = fopen("/tmp/foo.out", "wb");
$STDERR = fopen("/tmp/foo.err", "wb");

输出没有为我转到
/tmp/foo.out
。你使用的是什么版本的PHP?我根本找不到任何文档来解释你所说的$STDOUT行为。您的
$STDOUT
语法来自哪里?来自:
<?php
# Redirecting 10 times ...
# Need to close 'STDOUT' & '$STDOUT', otherwise the 2nd time
# the redirecting fails.

for ( $i = 1; $i <= 10; $i++ )
{
  $sLogName = sprintf("reopen_%02d.log", $i);
  echo "Redirecting to '" . $sLogName . "' ...\n";

  fclose(STDOUT);
  fclose($STDOUT);  # Needed for reopening after the first time.

  $STDOUT = fopen($sLogName, "w");
  echo "Now logging in file '" . $sLogName . "' ...\n";
}
?>