<?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
?>
为什么重定向到新STDOUT隐式工作,但新STDIN的重定向必须明确发生?
答案 0 :(得分:5)
原始的STDIN,STDOUT和STDERR是PHP中的系统常量。它们在PHP初始化时填充了标准输入,输出和错误的文件描述符资源。
php.net文档描述了有关常量资源的以下内容:
常数的值;只允许标量和空值。 标量值是整数,浮点数,字符串或布尔值。它是 可以定义资源常量,但不建议这样做 并可能导致不可预测的行为。
调用fclose(STDOUT)
时,文件描述符资源将关闭并与STDOUT常量分离。与常量的默认行为相反,STDOUT常量已更改。
当字符串像echo "Hello, World!"
一样被回显时,PHP将不使用STDOUT常量,但它将从操作系统实时查询当前的“标准输出”文件描述符。而且,STDOUT常量本身一旦被fclose'd就会变得无法使用。即使像fwrite(STDOUT, "hello")
这样的陈述也会不。
当为标准输出配置新的文件描述符时,这个新的文件描述符可以方便地放在$STDOUT
中。请注意,这是一个变量而不是常量。根据定义,不可能在PHP中重新定义常量,系统常量STDOUT在这里也不例外。目前无法将新文件描述符重新分配给STDOUT常量。
最终,为了使这项工作更直观,PHP团队应该考虑制作便利函数来重新分配这些文件描述符,或者至少使系统常量更像“魔术常量”,因为它们会自动评估实际文件描述符。
答案 1 :(得分:2)
这是多次重定向stdout的示例。 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";
}
?>
答案 2 :(得分:1)
仅在类UNIX系统(linux等)中发生这种情况,因为当您打开文件unix时使用次文件描述符,因此在进程STDIN中,STDOUT和STDERR始终为0,1和2。 当你这样做时:
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");
您正在关闭STDIN(0),STDOUT(1)和STDERR(2),因此当您以相同的顺序打开文件时,它们将获得0,1和2作为文件描述符。如果你在Windows上运行相同的代码,它将无法正常工作。
答案 3 :(得分:0)
我在阅读你的代码片段时首先看到的是你首先尝试关闭STDIN,STDOUT等的常量。但是然后使用具有相同名称的变量来打开文件;因此,您使用的值完全不同,$ STDIN与STDIN不同。您可以使用define函数重新定义STDIN,但我不确定并且无法在没有计算机的情况下进行检查..