Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

PHP has many different ways to print things, and I don't understand the difference between them. There are at least the following:

  • stdout and stderr. These can be denoted as php://stdout and php://stderr. There are also constants STDOUT and STDERR, and I think these refer to the same thing. So far, so good; these are standard.
  • php://output. What is this? Where does it go? Is it a synonym for php://stdout, or something else? The docs say it writes "to the output buffer mechanism", but I don't know where the contents of this buffer go after that.
  • print and echo. The docs say that these print to php://output. They are both language constructs, but at a guess, the difference is that print is an expression, but echo is a statement.
  • printf and many friends. Do these all also go to php://output?
  • Escaping. There are lots of alternative syntaxes for escaping, but I'm guessing they all have the same semantics. But what are the semantics? Where does the escaped text get printed to? Also to php://output? Currently, I understand ?>foo<?php as syntactic sugar for echo 'foo';; is this correct?

Are there more ways of doing output? What exactly are the differences? What settings and environments affect their behavior?

like image 364
jameshfisher Avatar asked Dec 26 '22 16:12

jameshfisher


1 Answers

First off, stdin and stdout are your standard input and output streams that most languages have. If you were to run php though the console you could create a script like this:

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

echo $line;

or

$line = trim(fgets(STDIN));

echo $line;

These scripts will both open the standard console input and allow you to enter input terminated by a return.

Now from the command line 'php://stdout' and 'php://output' function rather similarly, assuming you don't have output buffering on by default, and will both give you standard output to the console. By doing something like:

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

or

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

Both of these will output Hello World! to the console as expected.

Now as for output buffering is concerned, it is by default set to 0 in the php configuration file(meaning it is disabled). Output buffering is a way of 'holding back' output whether it be written to the console or to a browser. If you use the ob_start function to turn on output buffering none of your output will go to the console/browser. Instead it will be put in the buffer and wait until the buffer reaches it's max capacity(or until you flush it manually), then it will dump the buffer contents to stdout.

On to print and echo. These are not real functions they are language constructs where echo does not return anything and print always returns 1. The main difference between the two is that echo can print multiple strings delimited by a comma.

Both print and echo print to the output buffer but since, by default, output buffering is disabled they appear to output directly to the console/browser.

Now as for the differences between php://output and STDOUT. There is only a noticeable difference if output buffering is turned on. If it is turned on then stdout output will still go to the standard output of the console/browser but php://output will go to the buffer until the buffer reaches it's capacity or you manually flush the buffer. This example illustrates the difference:

<?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
?>

Notice how only Hello World! is output rather than the rest of the output statements in this script. If we comment out the ob* statements than we see that all of the other output was put in the output buffer. If we used ob_end_flush() at the end of the script instead we would Hello World! followed by all of the output from the output buffer, in the order than it was put into the buffer. Furthermore, from this example we can also see that printf also prints to the output buffer(probably using the underlying functionality of echo or print) and I'm assuming that is how all the rest of the formatting functions work but don't quote me on that.

As far as the escaping you are referring to, that is usually done to display html conditionally or when you have an array of stuff that you don't want to hard code. For instance consider:

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

This code could be used to output an array of options for a select without hard coding values and without the need to use write echo or print or print statements(note echo is used indirectly via the syntax ).

Surprisingly this output is also written to the output buffer and includes any whitespace you enter in this region but only if you are at the console(browsers interpret whitespace differently). Also, escape characters like \n, \t, etc.. have no meaning in this context and are interpreted exactly as they are seen. This can be seen by modifying the code above to:

<?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();
?>

As you can see Jelly Bean is printed when the output buffering statements are commented out, but if you comment them back in Jelly Bean doesn't appear in the output. Again if you uncomment the ob* statements and make the last statement ob_end_flush() you will see all of the input from the buffer output to stdout, in the order that it was put into the buffer.

like image 145
elitechief21 Avatar answered Jan 10 '23 19:01

elitechief21