Requirements
We have production PHP code running on a webserver. In some sitations we want to enrich debug output (going e.g. to error.log) with context information. The context can have arbitrary fields and structure.
Our goal is to find a general purpose debug producing function which does not generate warnings in any of the corner cases. It is acceptable if the output is only partial.
TL;DR
All three PHP standard functions cause warnings with certain contexts:
Question
Is there a way to return the context of arbitrary objects as human readable string?
Test Cases
// Dealing with recursion:
$recObj = new stdClass();
$recObj->recursion = $recObj;
print_r ($recObj); // works
var_export($recObj); // throws: "Warning: var_export does not handle circular references"
var_dump ($recObj); // works
// dealing with mysqli
$mysqli = mysqli_connect('mysql', 'root', 'myPass', 'mysql');
print_r ($mysqli); // works
var_export($mysqli); // works as in "does not throw warnings" but all values are null
var_dump ($mysqli); // works
// Try again with closed connection
mysqli_close($mysqli);
print_r ($mysqli); // throws: "Warning: print_r(): Couldn't fetch mysqli"
var_export($mysqli); // works (again all values are null)
var_dump ($mysqli); // throws: Warning: var_dump(): Couldn't fetch mysqli
As per the relevance of a closed mysqli connection: If you do your context printing in an error handler or registered shutdown function (which is a good location to do so), the mysqli object will already have auto-closed the connection once you reach that handler.
As you can see, none of the build-in output methods gives the desired result of just being able to return whatever context you throw at it.
Options considered
serialize()
function does not produce warnings in any of the cases but it lacks in human-readability.json_encode()
function can be much more readable than serialize but it does not return anything in the recursion test case....The comment from @BlackXero is correct and works for me.
I did not find a build-in printing function which does not cause errors / warnings when containing a mysqli object with a closed connection (which I would actually classify as bug / unwanted behavior).
We ended up adding the Symfony Vardumper via
composer require symfony/var-dumper
and writing a little helper function for displaying proper and nice output both from cli scripts or the browser:
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
class Debug {
/**
* Method provides a function which can handle all our corner-cases for producing
* debug output.
*
* The corner cases are:
* - objects with recursion
* - mysqli references (also to closed connections in error handling)
*
* The returned result will be:
* - formatted for CLI if the script is run from cli
* - HTML formatted otherwise
* - The HTML formatted output is collapsed by default. Use CTRL-left click to
* expand/collapse all children
* - You can force html|cli formatting using the optional third parameter
*
* Uses the Symfony VarDumper composer module.
*
* @see https://github.com/symfony/var-dumper
* @see https://stackoverflow.com/questions/57520457/how-to-get-proper-debug-context-from-production-php-code-print-r-vs-var-export
* @param mixed $val - variable to be dumped
* @param bool $return - if true, will return the result as string
* @param string|null $format null|cli|html for forcing output format
* @return bool|string
*/
public static function varDump($val, $return = false, $format = null) {
if (is_null($format)) {
$format = php_sapi_name() == 'cli' ? 'cli' : 'html';
}
$cloner = new VarCloner();
if ($format === 'cli') {
$dumper = new CliDumper();
} else {
$dumper = new HtmlDumper();
}
$output = fopen('php://memory', 'r+b');
$dumper->dump($cloner->cloneVar($val), $output);
$res = stream_get_contents($output, -1, 0);
if ($return) {
return $res;
} else {
echo $res;
return true;
}
}
}
That method
So it ticks all boxes I asked for in the initial question.
Thanks @BlackXero for understanding the question correctly and pointing me in the right direction.