1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
<h1>Output and errors</h1>
<p>
You can use regular C++ streams for IO, with the regular << operator
and special functions like std::endl. It is however not a good idea to use
the 'std::cout' and 'std::cerr' streams.
</p>
<p>
When PHP runs as a webserver module, stdout is redirected to the
terminal <i>from which the webserver process was originally started</i>.
On production servers such a terminal is not active, so any output that
you send to stdout will be lost. Using std::cout in extensions that run in
a webserver module is thus a no-go. But even when PHP runs as a CLI script
(and std::cout <i>does</i> work) you still should not write to stdout
directly. Writing to stdout will bypass all output handlers that may have
been set up by the PHP user space script.
</p>
<p>
The PHP-CPP library offers a Php::out stream that can be used instead. This
Php::out variable is an instance of the well known std::ostream class, and
respects all the output buffering set up in PHP. It does essentially the same
as the echo() function in PHP scripts.
</p>
<p>
Php::out is a regular std::ostream object. This has as consequence that
it uses an internal buffer that needs to be flushed. This flushing
occurs automatically when you add 'std::endl' to the output, or when you
add 'std::flush' explicitly.
</p>
<p>
<pre class="language-c++"><code>
/**
* Example function that shows how to generate output
*/
void example()
{
// the C++ equivalent of the echo() function
Php::out << "example output" << std::endl;
// generate output without a newline, and ensure that it is flushed
Php::out << "example output" << std::flush;
// or call the flush() method
Php::out << "example output";
Php::out.flush();
// just like all PHP functions, you can call the echo() function
// from C++ code as well
Php::echo("Example output\n");
}
</code></pre>
</p>
<h2 id="warnings-and-notices">Errors, warnings and notices</h2>
<p>
When you want to trigger a PHP error (the C++ equivalent of the PHP
trigger_error()) function, you can use one of the Php::error, Php::notice,
Php::warning and Php::deprecated streams. These are also instances of the
std::ostream class.
</p>
<p>
<p>
<pre class="language-c++"><code>
/**
* Example function that shows how to generate output
*/
void example()
{
// generate a PHP notice
Php::notice << "this is a notice" << std::flush;
// generate a PHP warning
Php::warning << "this is a warning" << std::flush;
// inform the user that a call to a deprecated function was made
Php::deprecated << "this method is deprecated" << std::flush;
// generate a fatal error
Php::error << "fatal error" << std::flush;
// this code will no longer be called
Php::out << "regular output" << std::endl;
}
</code></pre>
</p>
<p>
In the above example you can see that we used std::flush and not std::endl.
The reason for this is that std::endl internally does two things: it
appends a newline, and it flushes the buffer. For errors, notices and
warnings we don't need the newline, but we still have to flush the
buffer to actually generate the output.
</p>
<p>
There is something very peculiar with the Php::error stream: when you flush
it, the PHP script ends with a fatal error <i>and your C++ algorithm
immediately exits!!</i> Under the hood, the PHP engine does a longjump to
a place deep inside the Zend engine. In the example function the
'Php::out << "regular output"; statement is therefore never executed.
</p>
<p>
This all is very unusual, and (according to us) in conflict with the general
rules of decent software engineering. An output-generating function should
not behave like throwing an exception. Code that looks like normal code,
should also behave like normal code, and not do unexpected things like
leaping out of the current call stack. We therefore advise not to use
Php::error - or use it with extreme care.
</p>
|