Перенаправление ввода-вывода в PHP

<?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 должно происходить явно?

Исходные STDIN, STDOUT и STDERR являются системными константами в PHP. Они заполняются файловыми дескрипторами ресурсов стандартного ввода, вывода и ошибки при инициализации PHP.

В документации php.net описываются следующие ресурсы в константах:

Значение константы; допускаются только скалярные и нулевые значения. Скалярными значениями являются значения integer, float, string или boolean. Можно определить константы ресурсов, однако это не рекомендуется и может привести к непредсказуемому поведению.

Когда fclose(STDOUT) , ресурс дескриптора файла закрывается и отключается от константы STDOUT. В отличие от поведения констант по умолчанию константа STDOUT изменяется.

Когда строка echo'ed напоминает echo "Hello, World!" , PHP не будет использовать константу STDOUT, но он будет запрашивать текущий файловый дескриптор стандартного вывода в режиме реального времени из операционной системы. Более того, константа STDOUT сама по себе становится непригодной, если она является fclose'd. Даже утверждение типа fwrite(STDOUT, "hello") не будет работать.

Когда для стандартного вывода настроен новый файловый дескриптор, этот новый дескриптор файла удобно помещается в $STDOUT . Обратите внимание, что это переменная, а не константа. По определению невозможно переопределить константу в PHP, а системная константа STDOUT здесь не является исключением. В настоящее время нет возможности переназначить новый файловый дескриптор в константу STDOUT.

В конечном счете, чтобы сделать эту работу более интуитивно, команда PHP должна рассмотреть возможность использования функций удобства для переназначения этих файловых дескрипторов или, по крайней мере, сделать системные константы более похожими на «магические константы» в том смысле, что они автоматически оценивают фактические дескрипторы файлов.

Это пример перенаправления 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"; } ?> 

Это происходит только в 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 в качестве дескриптора файла. Если вы запустите тот же код в окнах, он не будет работать.

Первое, что я вижу при чтении вашего фрагмента, это то, что вы сначала пытаетесь закрыть константы STDIN, STDOUT и т. Д. Но затем используйте переменные, которые имеют одинаковое имя для открытия файлов; поэтому значения, с которыми вы работаете, совершенно разные, $ STDIN – это не то же самое, что и STDIN. Возможно, вы сможете переопределить STDIN с помощью функции define, но я не уверен и не могу проверить без компьютера atm.