I/O and Filesystem
Nested Output Buffers and Callbacks
Being able to use output buffering to intercept any output generated before it is sent off to the client is a sometimes practical treat available since PHP 4 times and not new at all. PHP even supports nested stacking of output buffers:
ob_start();
echo "output #1\n";
ob_start();
echo "output #2\n";
ob_end_clean();
echo "output #3\n";
ob_flush();
Not particularly surprising and due to the fact the inner
echo
’s output is wrapped in a nested buffer whose value
is not used, the output is suppressed:
output #1
output #3
Attempting to open another output buffer within a callback for
ob_start()
, though, is not supported as the following
code example demonstrates:
function obHandler($buffer, $phase = NULL) {
ob_start();
//...
}
ob_start('obHandler');
Trying to register the example callback obHandler
triggers an error:
PHP Fatal error: ob_start():
Cannot use output buffering in output buffering display handlers
This is particularly impractical if the callback does not open the nested buffer itself but uses some other code units which could also be used in a different context. Since there is no way for such code to detect it is being run as part of an output buffer handler, in previous versions of PHP the code would have had to be duplicated.
For PHP 7, the error level got downgraded from
E_ERROR
to E_RECOVERABLE_ERROR
. This, in
combination with a custom error handler, allows for a relatively
simple workaround:
set_error_handler(
function
exception_error_handler($severity, $message, $file, $line)
{
throw new ErrorException(
$message, 0, $severity,
$file, $line
);
}
);
function obHandler($buffer, $phase = NULL)
{
try {
ob_start();
} catch (ErrorException $e) {
// ...
}
// ...
return $buffer;
}
ob_start('obHandler');
New Implementation for JSON Encoding and Decoding
PHP 5.2 introduced support to parse JSON data structures into
array or object structures – json_decode()
– as well as
encode those into a JSON string using json_encode()
. To
avoid reinventing the wheel the PHP project back then decided to
bundle an implementation originally developed by json.org.
Unfortunately, that implementation came with a nonstandard license which would have caused legal issues for various Linux distributions if they were to bundle this extension. A new extension was created to mitigate this problem. It was originally hosted on the PHP Extension Community Library (PECL) at pecl.php.net and most operating system distributions packaged it instead of the original extension without the majority of developers even noticing.
With PHP 7, the code of the PECL extension – named
jsond
– got merged back into the core language,
effectively replacing the original json.org implementation.
Along with this change of implementation, the JSON encoding and
decoding is now more strict in what it accepts as input. Passing an
empty string – or a value that when casted to string equals an empty
string like null
or false
– to
json_decode()
is now also considered invalid:
$x = json_decode(false);
var_dump($x, json_last_error_msg());
NULL
string(12) "Syntax error"
To be RFC 7159 compliant, float representations must have at
least one digit following their decimal point, a JSON string
"1."
is no longer considered valid:
$x = json_decode("1.");
var_dump($x, json_last_error_msg());
Running the code above with PHP 5.6 parses the value into a float:
double(1)
string(8) "No error"
With PHP 7, since the JSON string is not RFC 7159 compliant, the parsing fails:
NULL
string(12) "Syntax error"