I have a static method in a helper class Utility::error_log() for helping us gracefully debug HUGE objects in PHP. The method, and it's helper-method Utility::toArray() are below:
static function error_log($message, $data=null, $max=2)
{
if(is_array($data) || is_object($data))
$data = print_r(self::toArray($data, $max),true);
if(is_array($message) || is_object($message))
$message = print_r(self::toArray($message, $max),true);
if(!empty($data))
$data = "\n".$data;
if (!strstr($message, PHP_EOL))
$message = str_pad(" ".$message." ", 50,'=',STR_PAD_BOTH);
error_log($message.$data);
}
static function toArray($object, $max = 2, $current = 0)
{
if($current > $max)
return ucfirst(gettype($object)).'( ... )';
$current++;
$return = array();
foreach((array) $object as $key => $data)
if (is_object($data))
$return[$key] = self::toArray($data, $max, $current);
elseif (is_array($data))
$return[$key] = self::toArray($data, $max, $current);
else
$return[$key] = $data;
return $return;
}
Now that may be a bit to look at, but the gist is, toArray makes a HUGE object (lots of recursion) orders of a magnitude smaller, and returns all properties as either arrays or strings. Much easier to work with... The idea being that print_r($array,true)
then makes the array a string, and we log it.
This doesn't work as expected, however. The result is:
[05-Apr-2013 05:29:00] ==================================== PERSISTING SUITS & SHIRTS ===================================
Array
(
[
And then nothing, where when I call print_r($data)
and print to the browser, I get:
Array
(
[BRS\PageBundle\Entity\Pageroot_folder_name] => Pages
[id] => 43
[title] => Suits & Shirts
[depth_title] => Suits & Shirts
[description] => ( ... AND SO ON ... )
Before you say it is an error_log() length limitation, I will mention that I can successfully $data = var_export($data,true)
and send the result to error_log() with no problems:
[05-Apr-2013 06:00:08] ==================================== PERSISTING SUITS & SHIRTS ===================================
array (
'' . "\0" . 'BRS\\PageBundle\\Entity\\Page' . "\0" . 'root_folder_name' => 'Pages',
'id' => 43,
'title' => 'Suits & Shirts',
'depth_title' => 'Suits & Shirts',
'description' => ( ... AND SO ON ... )
What is the problem? Why does it work with var_export($data,true)
, and print_r($data,false)
, but not with print_r($data,true)
??
The answer is non-printable characters. In the conversion of Objects to Arrays, and their various Properties to Strings, these Strings contain non-printing control characters that we never see, but as they exist, break PHP's
error_log()
.The solution is a rather simple, but essential:
Called before sending the $message to the Error Log, this removes many non-printing characters while preserving many characters other pregs I found removed. Just in case you need them:
In the end, there was some additional rewriting to isolate some functionality for use elsewhere, but the ultimate solution is as simple.
EDIT: Upon further review, it seems this is more specifically related to Bug #64439 - "\0 causes error_log strings to be truncated".
For those wondering, \0 (or \x00 or \x0) is the NULL character, and in the particular above case, is a result of the Casting of the Object as an Array, which returns a Key value of
NULL.classname.NULL.propname
.