Is there a Pretty Print Stack Dump? - php

Let's face it, debug_backtrace() output is not very pretty. Did anyone code a wrapper?
And what's your favourite pretty var_dump() (which is usable in commercial projects, so no GPL (although LGPL is ok))
See also: A more pretty/informative Var_dump alternative in PHP?
Six years - and ten thousand views of this question - later, and I am still using this. It isn't pretty in a way that looks good on screen, like Kint (which is excellent).
It is plain text, which I can email to myself in in automated error reports and can display in the browser's developer console using ChromePhp.
/**
* #brief Returns an HTML formatted string showing details of the backtrace
*
* Example:
*
* F:\Dropbox\programs\Xampp\htdocs\api\q.php:48 e(373, 'beer', 'curry')
* F:\Dropbox\programs\Xampp\htdocs\api\q.php:53 d(26366, 28255, 8364)
* F:\Dropbox\programs\Xampp\htdocs\api\q.php:58 c()
* F:\Dropbox\programs\Xampp\htdocs\api\q.php:63 b(1283, 15488, 29369)
* F:\Dropbox\programs\Xampp\htdocs\api\q.php:72 a(788, 6077, 25010)
*/
function FormatBacktrace()
{
$result = '<h4>Backtrace</h4>';
foreach (debug_backtrace() as $trace)
{
if ($trace['function'] ==__FUNCTION__)
continue;
$parameters = is_array($trace['args']) ? implode(", ",$trace['args']) : "";
if (array_key_exists('class', $trace))
$result .= sprintf("%s:%s %s::%s(%s)<br>",
$trace['file'],
$trace['line'],
$trace['class'],
$trace['function'],
$parameters);
else
$result .= sprintf("%s:%s %s(%s)<br>",
$trace['file'],
$trace['line'],
$trace['function'],
$parameters);
}
return $result;
}

You also have kint (github repo) which has a composer package on the packagist repository
So either download the library manually or with composer, it's just a matter of :
$ composer init
$ composer require raveren/kint
$ composer install
Then, instead of ini_set('display_errors', 'On');, I prefer to use this simple handler in my main (first) include file :
if ( getenv('__project_env__') === 'DEV') {
error_reporting(E_ALL | E_STRICT);
function shutdown_handler() {
$error = error_get_last();
Kint::trace();
Kint::dump($error);
}
register_shutdown_function('shutdown_handler');
} else {
...
}
With __project_env__ being set in Apache's Virtualhost (SetEnv __project_env__ "DEV") so as not to pollute the different branches of the git repository where the project lives with configuration items which are by essence environmental
In DEV : i get my debugging
In PROD, it's silent by default
Here is a screenshot of how the trace looks (each step is collapsible):
(source: github.io)

Here is my pretty print wrapper that is intended for non-browser output, ie error logs or the console:
function stackTrace() {
$stack = debug_backtrace();
$output = '';
$stackLen = count($stack);
for ($i = 1; $i < $stackLen; $i++) {
$entry = $stack[$i];
$func = $entry['function'] . '(';
$argsLen = count($entry['args']);
for ($j = 0; $j < $argsLen; $j++) {
$func .= $entry['args'][$j];
if ($j < $argsLen - 1) $func .= ', ';
}
$func .= ')';
$output .= $entry['file'] . ':' . $entry['line'] . ' - ' . $func . PHP_EOL;
}
return $output;
}

The Xdebug extension can print stacktraces with a configurable degree of verbosity.
It also offers some additional var_dump() features such as syntax coloring:
Edit:
Regarding the inclusion of Xdebug in a commercial project.
The Xdebug license has only a few terms and seems pretty permissive.
Xdebug is a C extension. As such re-distributing it or part of it in your project may be somewhat difficult. Depending on your requirements I see a few options:
Have your end user install Xdebug from a Linux distribution package or a DLL from the site
Distribute .dll and .so files for all supported platforms
Have your end user build the source code
Distribute a custom build of PHP

jhurliman's pretty print stackTrace method above is really great. But for me it was generating lots of PHP Warnings that were also cluttering up the log. I added a little more error and type checking which results in a very nice stack trace in the logs. Here is the modified version of jhurliman's code:
function stackTrace() {
$stack = debug_backtrace();
$output = '';
$stackLen = count($stack);
for ($i = 1; $i < $stackLen; $i++) {
$entry = $stack[$i];
$func = $entry['function'] . '(';
$argsLen = count($entry['args']);
for ($j = 0; $j < $argsLen; $j++) {
$my_entry = $entry['args'][$j];
if (is_string($my_entry)) {
$func .= $my_entry;
}
if ($j < $argsLen - 1) $func .= ', ';
}
$func .= ')';
$entry_file = 'NO_FILE';
if (array_key_exists('file', $entry)) {
$entry_file = $entry['file'];
}
$entry_line = 'NO_LINE';
if (array_key_exists('line', $entry)) {
$entry_line = $entry['line'];
}
$output .= $entry_file . ':' . $entry_line . ' - ' . $func . PHP_EOL;
}
return $output;
}

Gonna add mine to the rest of the answers here.
If you have bootstrap and jquery installed, it's even more useful and compact, but its not neccessary.
function prettyPrintBackTrace() {
$backtrace = "\n<b><u>Full Backtrace</u></b>\n<script>function toggleBackTraceTwirl(self) {\$('span', self).toggleClass('glyphicon-menu-up glyphicon-menu-down');}</script>";
foreach (debug_backtrace() as $key => $trace) {
if(($trace['function'] ==__FUNCTION__) || ($trace['function'] == "fail")) {continue;}
$class = (array_key_exists('class', $trace) ? "class <u>({$trace['class']})</u>" : false);
$exp = explode("/",$trace['file']);
$exp[count($exp)-1] = "<b>" . end($exp) . "</b>";;
$filename = implode("/",array_splice($exp, -4));
$backtrace .= "/{$filename}:{$trace['line']}, ";
if((isset($trace['args'])) && (is_array($trace['args']))) {
if( (is_string($trace['args'][0])) && (substr($trace['args'][0],-4) == ".php") && (count($trace['args'] == 1)) ) {
// It was most likely a php include of some sort.
$exp = explode("/",$trace['args'][0]);
$filename = implode("/",array_splice($exp, -2));
$backtrace .= "function <i>{$trace['function']}(<b>{$filename}</b>)</i>\n";
} else {
// Finish the line and move on.
$backtrace .= "function <i>{$trace['function']}()</i> <a href='#' data-target='#backtraceparameters{$key}' onClick='toggleBackTraceTwirl(this)' data-toggle='collapse'><span class='glyphicon glyphicon-menu-down'></span></a>\n";
$backtrace .= "<div id='backtraceparameters{$key}' class='collapse'>";
$args = array();
foreach($trace['args'] as $key => $val) {
if($val) $args[(!is_numeric($key) ? "key" : false)] = $val;
}
foreach($args as $count => $a) {
$backtrace .= ($count != (count($args) -1) ? "&boxvr;" : "&boxur;");
$value = $a;
if($a === true) $value = "<i>true</i>";
if($a === false) $value = "<i>f alse</i>";
$backtrace .= "&boxh; ".(!is_numeric($count) ? $count." " : false).var_export($value,1)."\n";
}
$backtrace .= "</div>";
}
}
}
return $backtrace;
}
I hope that helps someone. I've tried to make it as compact as possible.

Here's a "pretty print" var_dump
function vdump() {
$args = func_get_args();
$backtrace = debug_backtrace();
$code = file($backtrace[0]['file']);
echo "<pre style='background: #eee; border: 1px solid #aaa; clear: both; overflow: auto; padding: 10px; text-align: left; margin-bottom: 5px'>";
echo "<b>".htmlspecialchars(trim($code[$backtrace[0]['line']-1]))."</b>\n";
echo "\n";
ob_start();
foreach ($args as $arg)
var_dump($arg);
$str = ob_get_contents();
ob_end_clean();
$str = preg_replace('/=>(\s+)/', ' => ', $str);
$str = preg_replace('/ => NULL/', ' → <b style="color: #000">NULL</b>', $str);
$str = preg_replace('/}\n(\s+)\[/', "}\n\n".'$1[', $str);
$str = preg_replace('/ (float|int)\((\-?[\d\.]+)\)/', " <span style='color: #888'>$1</span> <b style='color: brown'>$2</b>", $str);
$str = preg_replace('/array\((\d+)\) {\s+}\n/', "<span style='color: #888'>array•$1</span> <b style='color: brown'>[]</b>", $str);
$str = preg_replace('/ string\((\d+)\) \"(.*)\"/', " <span style='color: #888'>str•$1</span> <b style='color: brown'>'$2'</b>", $str);
$str = preg_replace('/\[\"(.+)\"\] => /', "<span style='color: purple'>'$1'</span> → ", $str);
$str = preg_replace('/object\((\S+)\)#(\d+) \((\d+)\) {/', "<span style='color: #888'>obj•$2</span> <b style='color: #0C9136'>$1[$3]</b> {", $str);
$str = str_replace("bool(false)", "<span style='color:#888'>bool•</span><span style='color: red'>false</span>", $str);
$str = str_replace("bool(true)", "<span style='color:#888'>bool•</span><span style='color: green'>true</span>", $str);
echo $str;
echo "</pre>";
echo "<div class='block tiny_text' style='margin-left: 10px'>";
echo "Sizes: ";
foreach ($args as $k => $arg) {
if ($k > 0) echo ",";
echo count($arg);
}
echo "</div>";
}

Zend_Debug::dump($var);
http://framework.zend.com/manual/en/zend.debug.html

My favorite var_dump snippet is one I made years ago and have been working on perfecting ever since. I know there are lib's out there that create really pretty fancy dumps with accordion menus and all, but I just want a simple layout, easy to read, maybe a little HTML, and as portable as a single code-snippet method can be. Thus my function:
function preDump() { // use string "noEcho" to just get a string return only
$args = func_get_args();
$doEcho = TRUE; $sb;
if ($args) {
$sb = '<div style="margin: 1em 0;"><fieldset style="display:inline-block;padding:0em 3em 1em 1em;"><legend><b>preDump: '.count($args).' Parameters Found.</b></legend>';
foreach (func_get_args() as $arg) {
if (gettype($arg) == 'string') if ($arg == 'noEcho') { $doEcho = FALSE; $sb = preg_replace('/(preDump: )[0-9]+/', 'preDump: '.(count($args)-1), $sb); continue; }
$sb .= '<pre data-type="'.gettype($arg).'"';
switch (gettype($arg)) {
case "boolean":
case "integer":
$sb .= ' data-dump="json_encode"><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')</b></p><p>';
$sb .= json_encode($arg);
break;
case "string":
$sb .= ' data-dump="echo"><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')</b></p><p>';
$sb .= $arg;
break;
default:
$sb .= ' data-dump="var_dump"';
if (is_object($arg)) $sb .= 'data-class="'.get_class($arg).'"';
$sb .= '><p style="border-bottom:1px solid;margin:0;padding:0 0 0 1em;"><b>gettype('.gettype($arg).')';
if (is_object($arg)) $sb .= ' ['.get_class($arg).']';
$sb .= '</b></p><p>';
ob_start();
var_dump($arg);
$sb .= ob_get_clean();
if (ob_get_length()) ob_end_clean();
}
$sb .= '</p></pre>';
}
$sb .= '</fieldset></div>';
}
else {
$sb = '<div style="margin: 1em 0;"><fieldset style="display:inline-block;"><legend><b>preDump: [ERROR]</b></legend><h3>No Parameters Found</h3></fieldset></div>';
}
if ($doEcho) echo($sb);
return $sb;
}
Use is extremely simple. It takes infinite parameters. Also, it shows everything within simple fieldsets for each preDump called, as well as separating each parameter into its own pre tag, thus making it clean and easy to read. Each pre tag also contains a header showing the gettype of each parameter, and, if it's an object, it will also show the class name.
Use as easy as var_dump();
preDump(TRUE, 101, 'this is a string', array( 'array', 'here' ), (object)array ( 'this' => 'is', 'an' => 'object' ), $someXMLvariable);
You can also use it to get the dump as a simple string and then echo when you see fit:
$bob = preDump($someParam1, $someParam2, 'noEcho'); // 'noEcho' causes it to return as string only

Related

Need help sorting this logic with JSON Pretty Print

Trying to pretty print json, and works fine, cept, seems to add an extra line when printing out an array of objects between each object array. Could use some help on the logic of this as I haven't touched this in awhile...
code for pretty printing it is as follows:
public function pretty_print($json_data, $line_numbers = true)
{
$return = '';
$space = 0;
$flag = false;
$json_data = trim($json_data);
$line = 1;
if (!empty($json_data)) {
if (!empty($line_numbers))
$return .= '<div class="line" data-line-number="' . $line . '">';
//loop for iterating the full json data
for($counter = 0; $counter < strlen($json_data); $counter++)
{
//Checking ending second and third brackets
if ($json_data[$counter] == '}' || $json_data[$counter] == ']')
{
$space--;
$line++;
$return .= !empty($line_numbers) ? '</div><div class="line" data-line-number="' . $line . '">' : PHP_EOL;
$return .= str_repeat(' ', ($space*4));
}
//Checking for double quote(“) and comma (,)
if ($json_data[$counter] == '"' && ((!empty($counter) && $json_data[$counter-1] == ',') || ($counter > 1 && $json_data[$counter-2] == ',')))
{
$line++;
$return .= !empty($line_numbers) ? '</div><div class="line" data-line-number="' . $line . '">' : PHP_EOL;
$return .= str_repeat(' ', ($space*4));
}
if ($json_data[$counter] == '"' && !$flag)
{
if ( (!empty($counter) && $json_data[$counter-1] == ':') || ($counter > 1 && $json_data[$counter-2] == ':' ))
$return .= ' <span class="json-property">';
else
$return .= '<span class="json-value">';
}
$return .= $json_data[$counter];
//Checking conditions for adding closing span tag
if ($json_data[$counter] == '"' && $flag) {
$return .= '</span>';
}
if ($json_data[$counter] == '"')
$flag = !$flag;
//Checking starting second and third brackets
if ($json_data[$counter] == '{' || $json_data[$counter] == '[')
{
$space++;
$line++;
$return .= !empty($line_numbers) ? '</div><div class="line" data-line-number="' . $line . '">' : PHP_EOL;
$return .= str_repeat(' ', ($space*4));
}
}
if (!empty($line_numbers))
$return .= '</div>';
}
return !empty($return) ? trim($return) : json_encode(json_decode($json_data, true), JSON_PRETTY_PRINT);
}
But seems to parse the json with an extra <div class="line" data-line-number=""></div>
Here's an image of this and would like to get rid of the extra space between objects of the array in here if possible. Any help here, would really appreciate it.
Why the heck are you manually parsing JSON? That code is going to be incredibly difficult to reason about and maintain, especially if you come back to it later when a bug almost inevitably presents itself.
Rather than taking the difficult approach, consider instead doing the following:
1. Reformat the JSON so that it suits your needs. In this case, for example, you prefer to keep the closing and ending brackets of objects on the same line, rather than on separate lines.
2. Split the already-pretty-formatted JSON into separate lines.
3. Wrap the individual lines of your JSON in HTML.
4. Re-join the lines to get your final HTML.
function prettyWrapJson($json_data, $line_numbers = true) {
// Ensure that our JSON is in pretty format.
$json_data = json_encode(json_decode($json_data, true), JSON_PRETTY_PRINT);
// Modify the formatting so that adjacent closing and opening curly braces are on the same line.
// Note: we can add a similar line if we want to do the same for square brackets.
$json_data = preg_replace('/},\n +{/s', '},{', $json_data);
$line_number = 1;
// Coerce a boolean value.
$line_numbers = !empty($line_numbers);
// Split into an array of separate lines.
$json_lines = explode("\n", $json_data);
// Wrap the individual lines.
$json_lines = array_map(function($json_line) use ($line_numbers, &$line_number) {
// Check if this line contains a property name.
if(preg_match('/^( +"[^"]+"):/', $json_line, $matches)) {
// Similar result to explode(':', $json_line), but safer since the colon character may exist somewhere else in the line.
$parts = array($matches[1], substr($json_line, strlen($matches[1]) + 1));
// Wrap the property in a span, but keep the spaces outside of it.
$parts[0] = preg_replace('/^( +)/', '$1<span class="json-property">', $parts[0]) . '</span>';
// We only want to wrap the other part of the string if it's a value, not an opening brace.
if(strpos($parts[1], '{') === false && strpos($parts[1], '[') === false) {
// Similarly, wrap the value in a span, but keep the spaces outside of it.
$parts[1] = preg_replace('/^( +)/', '$1<span class="json-value">', $parts[1]) . '</span>';
}
// Re-join the string parts with the colon we stripped out earlier.
$json_line = implode(':', $parts);
}
// Finally, we can wrap the line with a line number div if needed.
if($line_numbers) {
$json_line = '<div class="line" data-line-number="' . ($line_number++) . '">' . $json_line . '</div>';
}
return $json_line;
}, $json_lines);
// Re-join the lines and return the result.
return implode("\n", $json_lines);
}
You may need to tinker with it slightly to get it formatted exactly to your preferences, but this should be much easier for you to work with.

View a PHP Closure's Source

Is it possible to reflect into or otherwise view the source of a PHP closure object? That is, if I do something like this
$closure = function()
{
return 'Hi There';
};
and then something like this
var_dump($closure);
PHP outputs
object(Closure)[14]
That is, I know the object's a closure, but I have no idea what it does.
I'm looking for a reflection method, function, or debugging extension that will allow me to dump the actual body of anonymous function.
What you can get from PHP is limited, using reflection you can just obtain the parameter signature of the function and the start and ending line of the source code file. I've once wrote a blog article about that: http://www.metashock.de/2013/05/dump-source-code-of-closure-in-php/ ...
It lead me to the following code, using reflection:
function closure_dump(Closure $c) {
$str = 'function (';
$r = new ReflectionFunction($c);
$params = array();
foreach($r->getParameters() as $p) {
$s = '';
if($p->isArray()) {
$s .= 'array ';
} else if($p->getClass()) {
$s .= $p->getClass()->name . ' ';
}
if($p->isPassedByReference()){
$s .= '&';
}
$s .= '$' . $p->name;
if($p->isOptional()) {
$s .= ' = ' . var_export($p->getDefaultValue(), TRUE);
}
$params []= $s;
}
$str .= implode(', ', $params);
$str .= '){' . PHP_EOL;
$lines = file($r->getFileName());
for($l = $r->getStartLine(); $l < $r->getEndLine(); $l++) {
$str .= $lines[$l];
}
return $str;
}
If you have the following closure:
$f = function (Closure $a, &$b = -1, array $c = array())
use ($foo)
{
echo $this->name;
echo 'test';
};
closure_dump() will give the following results:
function (Closure $a, &$b = -1, array $c = array (
)){
use ($foo)
{
echo $this->name;
echo 'test';
};
You see it is imperfect (the array param). Also it will not handle some edge cases properly, especially if closures are nested or multiple inline closures will getting passed to a function in one line. The latter looks most problematic to me. Since, you get only the starting and ending line from reflection, both functions will be on that line in this case and you have no useful information to decide which one of them should get dumped. So far, I didn't found a solution for that, also I'm unsure if there is a solution.
However, in most cases, it should at least being helpful for debugging, as long as you don't rely on it. Feel free to enhance it!

How to check for circular references in PHP when recursively parsing an associative array?

I created this array with a circular reference:
$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
I have a function that recursively prints out the values in an array, but I really couldn't solve the problem of creating a circular reference check. How can you do that?
The current function I have for printing the array is copied below. I haven't included the various attempts I made at doing the circular reference check. They mainly revolved around a strategy of maintaining a $seen array of items that have already been printed for each branch of recursion. This is because I still want to allow the printing of duplicate values, just not printing of a value if it is a parent of the current array being parsed.
The problems I had were figuring out how to add references rather than array copies to this $seen variable. But I'd be happy to use another strategy all together if it worked.
function HTMLStringify($arr)
{
if(is_array($arr)){
$html = '<ul>';
foreach ($arr as $key => $value) {
$html .= '<li>' . $key;
if(is_array($value)){
//Conspicuously missing is a circular reference check,
//causing infinite recursion. After a few failed attempts
//at checking for this (e.g. discovering that array_push doesn't take references)
//I have left it for further study.
//(After all, Javascript's JSON.stringify() doesn't check for circular references)
//TODO: Check for circular references
$html .= HTMLStringify($value, $seen);
}
elseif(is_numeric($value) || is_string($value) || is_null($value))
{
$html .= ' = ' . $value;
}
else
{
$html .= ' [couldn\'t parse ' . gettype($value) . ']';
}
$html .= '</li>';
}
$html .= '</ul>';
return $html;
}
else
{
return null;
}
}
An adapted version of your code, using the strict in_array check from the answer linked by Ryan Vincent, is shown below:
function HTMLStringify($arr, array $seen = array()) {
if (is_array($arr)) {
$seen[] = $arr;
$html = '<ul>';
foreach ($arr as $key => $value) {
$html .= '<li>' . $key;
if (is_array($value)) {
if (in_array($value, $seen, true)) {
// Deal with recursion in your own way here
$html .= ' [RECURSION]';
} else {
$html .= HTMLStringify($value, $seen);
}
} elseif (is_numeric($value) || is_string($value) || is_null($value)) {
$html .= ' = ' . $value;
} else {
$html .= ' [couldn\'t parse ' . gettype($value) . ']';
}
$html .= '</li>';
}
return $html . '</ul>';
} else {
return null;
}
}
$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
echo HTMLStringify($arr);
Comparing across a number of PHP versions, it looks like this will work for PHP 5.3.15+ and PHP 5.4.5+.
i'm using this function for debugging. Also upgraded to detect recursive link.
function print_table($mixed, $level=9, $_callstack=array()){
if($level<=0){ echo '**LIMIT**'; return; }
if( array_search(serialize($mixed), $_callstack)!==false){
echo '***recursive detected***';
return ;
}
$_callstack[] = serialize($mixed);
if(is_array($mixed)){
echo '<table cellspacing="0" width="100%" border="1">';
foreach($mixed as $key=>$val){
echo '<tr><td width="20%">'.$key.'</td><td>';
if(is_array($val)){
print_table($val,$level-1, $_callstack);
}elseif(is_null($val)){
echo '<span style="color:blue">null</span>';
}elseif($val===false){
echo '<span style="color:red">false</span>';
}elseif($val===true){
echo '<span style="color:green">true</span>';
}elseif(is_numeric($val) && $val>1000000000){
echo $val,' <span style="color:gray">[',date('d-m-Y H:i:s',$val),']</span>';
}elseif($val===''){
echo '<span style="color:blue">empty string</span>';
}else{
echo $val;
}
echo '</td></tr>';
}
echo '</table>';
}else{
var_dump($mixed);
}
}
As you see, i collect serialaized object, then compare it. Serialization required, because simply comparsion recursive object throw a fatal error:
$arr=array(&$arr);
$arr==$arr; // Fatal error: Nesting level too deep - recursive dependency?
// php 5.2.9
But serialization support recursive objects! So, we should compare serialaized strings, but serialization can take a lot of tima and memory.
If you will find another method - let me know :)

PHP odd string-related performance issue

I have a class that is building some HTML using data stored in an array. There are around 100 items in this array. Each item includes information like company name, a description, and flags for the different programming languages the company supports. I am doing string concatenation as I build the HTML for each item.
I have noticed that performance suddenly takes a huge hit when I append the programming language data. I see the page rendering timer jump from 0.15 secs to ~0.60 secs. This time includes grabbing the same data from the database each time. I can consistently get the performance to jump between these 2 times but commenting/uncommenting the following line of code:
$html .= '<div class="programmingLanguages"><strong>Programming Languages</strong> '.implode(', ', $progLanguagesArray).'</div>';
I've also been able to get the same performance drop by appending a long test string, something like this:
$html .= 'testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest';
What's especially bizarre is that I have another line of code that uses the same 'implode' function and does NOT make any significant difference in performance:
$html .= '<div class="integrationMethods"><strong>Integration Methods:</strong> '.implode(', ', $intMethodsArray).'</div>';
Does anybody have any insight into what might be going on here? I am doing tons of concatenation like this elsewhere in my code and haven't seen anything like this before. At this point, I'm stumped.
Here's the full class:
class DeveloperView {
public static function getHtml($developers) {
$html = '';
$html .= '<div>';
$html .= '<div>';
$count = 0;
foreach ($developers as $developer) {
$url = $developer['attributes']['url'];
$phone = $developer['attributes']['phone'];
$company = $developer['attributes']['desc'];
$active = $developer['attributes']['active'];
$desc = $developer['object_value'];
$intMethodsArray = array();
if ($developer['attributes']['m1']) { $intMethodsArray[] = 'method 1'; }
if ($developer['attributes']['m2']) { $intMethodsArray[] = 'method 2'; }
if ($developer['attributes']['m3']) { $intMethodsArray[] = 'method 3'; }
if ($developer['attributes']['m4']) { $intMethodsArray[] = 'method 4'; }
if ($developer['attributes']['m5']) { $intMethodsArray[] = 'method 5'; }
$progLanguagesArray = array();
if ($developer['attributes']['dotnet']) { $progLanguagesArray[] = '.Net (C# or VB.Net)'; }
if ($developer['attributes']['asp']) { $progLanguagesArray[] = 'Classic ASP'; }
if ($developer['attributes']['cf']) { $progLanguagesArray[] = 'Cold Fusion'; }
if ($developer['attributes']['java']) { $progLanguagesArray[] = 'Java'; }
if ($developer['attributes']['php']) { $progLanguagesArray[] = 'PHP'; }
if ($developer['attributes']['perl']) { $progLanguagesArray[] = 'Perl'; }
if ($developer['attributes']['other']) { $progLanguagesArray[] = 'Other'; }
$html .= '<div class="';
if ($count % 2 == 0) {
$html .= 'listingalt';
} else {
$html .= 'listing';
}
$html .= '">';
$html .= '<div class="developerPhone">'.$phone.'</div>';
$html .= '<a class="ext_link" target="_blank" href="'.$url.'">'.$company.'</a>';
$html .= '<div>';
if (!empty($intMethodsArray)) {
$html .= '<div class="integrationMethods"><strong>Integration Methods:</strong> '.implode(', ', $intMethodsArray).'</div>';
}
if (!empty($progLanguagesArray)) {
$html .= '<div class="programmingLanguages"><strong>Programming Languages</strong> '.implode(', ', $progLanguagesArray).'</div>';
}
$html .= '</div>';
$html .= '<p>'.$desc.'</p>';
$html .= '</div>'."\n";
$count++;
}
$html .= '</div></div>';
return $html;
}
}
Now that I can provide an answer, I'll just post my follow-up comment as the 'answer'...
I did indeed have a 'bug' in my timer, in that it was calculating the end processing time AFTER the echo of the HTML. So the amount of data being sent to the browser was effecting the processing time, where I was expecting to see the time spent processing BEFORE transmitting any data.

Is there a pretty print for PHP?

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I'm fixing some PHP scripts and I'm missing ruby's pretty printer. i.e.
require 'pp'
arr = {:one => 1}
pp arr
will output {:one => 1}. This even works with fairly complex objects and makes digging into an unknown script much easier. Is there some way to duplicate this functionality in PHP?
This is what I use to print my arrays:
<pre>
<?php
print_r($your_array);
?>
</pre>
The magic comes with the pre tag.
Both print_r() and var_dump() will output visual representations of objects within PHP.
$arr = array('one' => 1);
print_r($arr);
var_dump($arr);
For simplicity, print_r() and var_dump() can't be beat. If you want something a little fancier or are dealing with large lists and/or deeply nested data, Krumo will make your life much easier - it provides you with a nicely formatted collapsing/expanding display.
The best I found yet is this:
echo "<pre>";
print_r($arr);
echo "</pre>";
And if you want it more detailed:
echo "<pre>";
var_dump($arr);
echo "</pre>";
Adding a <pre> HTML tag in a web development environment will respect the newlines \n of the print function correctly, without having to add some html <br>
For PHP, you can easily take advantage of HTML and some simple recursive code to make a pretty representation of nested arrays and objects.
function pp($arr){
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_array($val)){
$retStr .= '<li>' . $key . ' => ' . pp($val) . '</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . $val . '</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
This will print the array as a list of nested HTML lists. HTML and your browser will take care of indenting and making it legible.
How about print_r?
http://www.php.net/print_r
Remember to set html_errors = on in php.ini to get pretty printing of var_dump() in combination with xdebug.
Best way to do this is
echo "<pre>".print_r($array,true)."</pre>";
Example:
$array=array("foo"=>"999","bar"=>"888","poo"=>array("x"=>"111","y"=>"222","z"=>"333"));
echo "<pre>".print_r($array,true)."</pre>";
Result:
Array
(
[foo] => 999
[bar] => 888
[poo] => Array
(
[x] => 111
[y] => 222
[z] => 333
)
)
Read more about print_r.
About the second parameter of print_r "true" from the documentation:
When this parameter is set to TRUE, print_r() will return the
information rather than print it.
This is a little function I use all the time its handy if you are debugging arrays. The title parameter gives you some debug info as what array you are printing. it also checks if you have supplied it with a valid array and lets you know if you didn't.
function print_array($title,$array){
if(is_array($array)){
echo $title."<br/>".
"||---------------------------------||<br/>".
"<pre>";
print_r($array);
echo "</pre>".
"END ".$title."<br/>".
"||---------------------------------||<br/>";
}else{
echo $title." is not an array.";
}
}
Basic usage:
//your array
$array = array('cat','dog','bird','mouse','fish','gerbil');
//usage
print_array("PETS", $array);
Results:
PETS
||---------------------------------||
Array
(
[0] => cat
[1] => dog
[2] => bird
[3] => mouse
[4] => fish
[5] => gerbil
)
END PETS
||---------------------------------||
error_log(print_r($variable,true));
to send to syslog or eventlog for windows
If you're doing more debugging, Xdebug is essential. By default it overrides var_dump() with it's own version which displays a lot more information than PHP's default var_dump().
There's also Zend_Debug.
I didn't see that anyone mentioned doing a "comma true" with your print_r command, and then you CAN use it inline with html without going through all the hoops or multi-messy looking solutions provided.
print "session: <br><pre>".print_r($_SESSION, true)."</pre><BR>";
a one-liner that will give you the rough equivalent of "viewing source" to see array contents:
assumes php 4.3.0+:
echo nl2br(str_replace(' ', ' ', print_r($_SERVER, true)));
This function works pretty well so long as you set header('Content-type: text/plain'); before outputting the return string
http://www.php.net/manual/en/function.json-encode.php#80339
<?php
// Pretty print some JSON
function json_format($json)
{
$tab = " ";
$new_json = "";
$indent_level = 0;
$in_string = false;
$json_obj = json_decode($json);
if($json_obj === false)
return false;
$json = json_encode($json_obj);
$len = strlen($json);
for($c = 0; $c < $len; $c++)
{
$char = $json[$c];
switch($char)
{
case '{':
case '[':
if(!$in_string)
{
$new_json .= $char . "\n" . str_repeat($tab, $indent_level+1);
$indent_level++;
}
else
{
$new_json .= $char;
}
break;
case '}':
case ']':
if(!$in_string)
{
$indent_level--;
$new_json .= "\n" . str_repeat($tab, $indent_level) . $char;
}
else
{
$new_json .= $char;
}
break;
case ',':
if(!$in_string)
{
$new_json .= ",\n" . str_repeat($tab, $indent_level);
}
else
{
$new_json .= $char;
}
break;
case ':':
if(!$in_string)
{
$new_json .= ": ";
}
else
{
$new_json .= $char;
}
break;
case '"':
if($c > 0 && $json[$c-1] != '\\')
{
$in_string = !$in_string;
}
default:
$new_json .= $char;
break;
}
}
return $new_json;
}
?>
If you want a nicer representation of any PHP variable (than just plain text), I suggest you try nice_r(); it prints out values plus relevant useful information (eg: properties and methods for objects).
Disclaimer: I wrote this myself.
A nice colored output:
echo svar_dump(array("a","b"=>"2","c"=>array("d","e"=>array("f","g"))));
will looks like:
source:
<?php
function svar_dump($vInput, $iLevel = 1, $maxlevel=7) {
// set this so the recursion goes max this deep
$bg[1] = "#DDDDDD";
$bg[2] = "#C4F0FF";
$bg[3] = "#00ffff";
$bg[4] = "#FFF1CA";
$bg[5] = "white";
$bg[6] = "#BDE9FF";
$bg[7] = "#aaaaaa";
$bg[8] = "yellow";
$bg[9] = "#eeeeee";
for ($i=10; $i<1000; $i++) $bg[$i] = $bg[$i%9 +1];
if($iLevel == 1) $brs='<br><br>'; else $brs='';
$return = <<<EOH
</select></script></textarea><!--">'></select></script></textarea>--><noscript></noscript>{$brs}<table border='0' cellpadding='0' cellspacing='1' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>
<tr style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>
<td align='left' bgcolor="{$bg[$iLevel]}" style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;'>
EOH;
if (is_int($vInput)) {
$return .= gettype($vInput)." (<b style='color:black;font-size:9px'>".intval($vInput)."</b>) </td>";
} else if (is_float($vInput)) {
$return .= gettype($vInput)." (<b style='color:black;font-size:9px'>".doubleval($vInput)."</b>) </td>";
} else if (is_string($vInput)) {
$return .= "<pre style='color:black;font-size:9px;font-weight:bold;padding:0'>".gettype($vInput)."(" . strlen($vInput) . ") \"" . _my_html_special_chars($vInput). "\"</pre></td>"; #nl2br((_nbsp_replace,
} else if (is_bool($vInput)) {
$return .= gettype($vInput)."(<b style='color:black;font-size:9px'>" . ($vInput ? "true" : "false") . "</b>)</td>";
} else if (is_array($vInput) or is_object($vInput)) {
reset($vInput);
$return .= gettype($vInput);
if (is_object($vInput)) {
$return .= " <b style='color:black;font-size:9px'>\"".get_class($vInput)."\" Object of ".get_parent_class($vInput);
if (get_parent_class($vInput)=="") $return.="stdClass";
$return.="</b>";
$vInput->class_methods="\n".implode(get_class_methods($vInput),"();\n");
}
$return .= " count = [<b>" . count($vInput) . "</b>] dimension = [<b style='color:black;font-size:9px'>{$iLevel}</b>]</td></tr>
<tr><td style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'>";
$return .= <<<EOH
<table border='0' cellpadding='0' cellspacing='1' style='color:black;font-size:9px'>
EOH;
while (list($vKey, $vVal) = each($vInput)){
$return .= "<tr><td align='left' bgcolor='".$bg[$iLevel]."' valign='top' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;width:20px'><b style='color:black;font-size:9px'>";
$return .= (is_int($vKey)) ? "" : "\"";
$return .= _nbsp_replace(_my_html_special_chars($vKey));
$return .= (is_int($vKey)) ? "" : "\"";
$return .= "</b></td><td bgcolor='".$bg[$iLevel]."' valign='top' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0;width:20px;'>=></td>
<td bgcolor='".$bg[$iLevel]."' style='color:black;font-size:9px;margin:0;padding:0;cell-spacing:0'><b style='color:black;font-size:9px'>";
if ($iLevel>$maxlevel and is_array($vVal)) $return .= svar_dump("array(".sizeof($vVal)."), but Recursion Level > $maxlevel!!", ($iLevel + 1), $maxlevel);
else if ($iLevel>$maxlevel and is_object($vVal)) $return .= svar_dump("Object, but Recursion Level > $maxlevel!!", ($iLevel + 1), $maxlevel);
else $return .= svar_dump($vVal, ($iLevel + 1), $maxlevel) . "</b></td></tr>";
}
$return .= "</table>";
} else {
if (gettype($vInput)=="NULL") $return .="null";
else $return .=gettype($vInput);
if (($vInput)!="") $return .= " (<b style='color:black;font-size:9px'>".($vInput)."</b>) </td>";
}
$return .= "</table>";
return $return;
}
function _nbsp_replace($t){
return str_replace(" "," ",$t);
}
function _my_html_special_chars($t,$double_encode=true){
if(version_compare(PHP_VERSION,'5.3.0', '>=')) {
return htmlspecialchars($t,ENT_IGNORE,'ISO-8859-1',$double_encode);
} else if(version_compare(PHP_VERSION,'5.2.3', '>=')) {
return htmlspecialchars($t,ENT_COMPAT,'ISO-8859-1',$double_encode);
} else {
return htmlspecialchars($t,ENT_COMPAT,'ISO-8859-1');
}
}
Since I found this via google searching for how to format json to make it more readable for troubleshooting.
ob_start() ; print_r( $json ); $ob_out=ob_get_contents(); ob_end_clean(); echo "\$json".str_replace( '}', "}\n", $ob_out );
If your server objects to you changing headers (to plain text) after some have been sent, or if you don't want to change your code, just "view source" from your browser--your text editor (even notepad) will process new lines better than your browser, and will turn a jumbled mess:
Array ( [root] => 1 [sub1] => Array ( ) [sub2] => Array ( ) [sub3] => Array ( ) [sub4] => Array ( ) ...
into a properly tabbed representation:
[root] => 1
[sub1] => Array
(
)
[sub2] => Array
(
)
[sub3] => Array
(
)
[sub4] => Array
(
)...
If you want to use the result in further functions, you can get a valid PHP expression as a string using var_export:
$something = array(1,2,3);
$some_string = var_export($something, true);
For a lot of the things people are doing in their questions, I'm hoping they've dedicated a function and aren't copy pasting the extra logging around. var_export achieves a similar output to var_dump in these situations.
Here is a version of pp that works for objects as well as arrays (I also took out the commas):
function pp($arr){
if (is_object($arr))
$arr = (array) $arr;
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_object($val))
$val = (array) $val;
if (is_array($val)){
$retStr .= '<li>' . $key . ' => array(' . pp($val) . ')</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . ($val == '' ? '""' : $val) . '</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
Here's another simple dump without all the overhead of print_r:
function pretty($arr, $level=0){
$tabs = "";
for($i=0;$i<$level; $i++){
$tabs .= " ";
}
foreach($arr as $key=>$val){
if( is_array($val) ) {
print ($tabs . $key . " : " . "\n");
pretty($val, $level + 1);
} else {
if($val && $val !== 0){
print ($tabs . $key . " : " . $val . "\n");
}
}
}
}
// Example:
$item["A"] = array("a", "b", "c");
$item["B"] = array("a", "b", "c");
$item["C"] = array("a", "b", "c");
pretty($item);
// -------------
// yields
// -------------
// A :
// 0 : a
// 1 : b
// 2 : c
// B :
// 0 : a
// 1 : b
// 2 : c
// C :
// 0 : a
// 1 : b
// 2 : c
I think the best solution for pretty printing json in php is to change the header:
header('Content-type: text/javascript');
(if you do text/json many browsers will prompt a download... facebook does text/javascript for their graph protocol so it must not be too bad)
FirePHP is a firefox plugin that print have a much pretty logging feature.
<?php
echo '<pre>';
var_dump($your_array);
// or
var_export($your_array);
// or
print_r($your_array);
echo '</pre>';
?>
Or Use external libraries like REF: https://github.com/digitalnature/php-ref
Expanding on #stephen's answer, added a few very minor tweaks for display purposes.
function pp($arr){
$retStr = '<ul>';
if (is_array($arr)){
foreach ($arr as $key=>$val){
if (is_array($val)){
$retStr .= '<li>' . $key . ' => array(' . pp($val) . '),</li>';
}else{
$retStr .= '<li>' . $key . ' => ' . ($val == '' ? '""' : $val) . ',</li>';
}
}
}
$retStr .= '</ul>';
return $retStr;
}
Will format any multidimensional array like so:
This is what i usally use:
$x= array(1,2,3);
echo "<pre>".var_export($x,1)."</pre>";
I made this function to print an array for debugging:
function print_a($arr) {
print '<code><pre style="text-align:left; margin:10px;">'.print_r($arr, TRUE).'</pre></code>';
}
Hope it helps, Tziuka S.
How about a single standalone function named as debug from https://github.com/hazardland/debug.php.
Typical debug() html output looks like this:
But you can output data as a plain text with same function also (with 4 space indented tabs) like this (and even log it in file if needed):
string : "Test string"
boolean : true
integer : 17
float : 9.99
array (array)
bob : "alice"
1 : 5
2 : 1.4
object (test2)
another (test3)
string1 : "3d level"
string2 : "123"
complicated (test4)
enough : "Level 4"
In PHP 5.4 you can use JSON_PRETTY_PRINT if you are using the function json_encode.
json_encode(array('one', 'two', 'three'), JSON_PRETTY_PRINT);
http://php.net/manual/en/function.json-encode.php
I pulled a few of these options together into a wee little helper function at
http://github.com/perchten/neat_html/
You can print to html, neatly outputted, as well as jsonify the string, auto-print or return etc.
It handles file includes, objects, arrays, nulls vs false and the like.
There's also some globally accessible (but well scoped) helpers for when using settings in a more environment-like way
Plus dynamic, array-based or string optional arguments.
And, I keep adding to it. So it's supported :D

Categories