Automattic /
jetpack
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /* |
||
| 4 | Plugin Name: Automattic Debug Helpers |
||
| 5 | Description: <code>l( 'Code is Poetry' )</code> |
||
| 6 | Version: 1.0 |
||
| 7 | Author: Automattic |
||
| 8 | Author URI: http://automattic.com/ |
||
| 9 | */ |
||
| 10 | |||
| 11 | |||
| 12 | /** |
||
| 13 | * debug.php |
||
| 14 | * |
||
| 15 | * This file contains helpful debugging functions |
||
| 16 | */ |
||
| 17 | |||
| 18 | /** |
||
| 19 | * l() -- sweet error logging |
||
| 20 | * |
||
| 21 | * l($something_to_log); // error_log(print_r($something_to_log, true)); |
||
| 22 | * l(compact('v1','v2'); // log several variables with labels |
||
| 23 | * l($thing5, $thing10); // log two things |
||
| 24 | * l(); // log the file:line |
||
| 25 | * l(null, $stuff, $ba); // log the file:line, then log two things. |
||
| 26 | * |
||
| 27 | * The first call of l() will print an extra line containing a random ID & PID |
||
| 28 | * and the script name or URL. The ID prefixes every l() log entry thereafter. |
||
| 29 | * The extra line and ID will help you to indentify and correlate log entries. |
||
| 30 | * |
||
| 31 | * Example: |
||
| 32 | * wpsh> l('yo') |
||
| 33 | * wpsh> l('dude') |
||
| 34 | * /tmp/php-errors: |
||
| 35 | * [21-Jun-2012 14:45:13] 1566-32201 => /home/wpcom/public_html/bin/wpshell/wpshell.php |
||
| 36 | * [21-Jun-2012 14:45:13] 1566-32201 yo |
||
| 37 | * [21-Jun-2012 14:50:23] 1566-32201 dude |
||
| 38 | * |
||
| 39 | * l() returns its input so you can safely wrap most kinds of expressions to log them. |
||
| 40 | * l($arg1, $arg2) will call l($arg1) and l($arg2) and then return $arg1. |
||
| 41 | * |
||
| 42 | * A null argument will log the file and line number of the l() call. |
||
| 43 | */ |
||
| 44 | function l( $stuff = null ) { |
||
| 45 | // Do nothing when debugging is off |
||
| 46 | if ( !defined( 'WP_DEBUG' ) || WP_DEBUG === false ) { |
||
| 47 | return $stuff; |
||
| 48 | } |
||
| 49 | static $pageload; |
||
| 50 | // Call l() on each argument |
||
| 51 | if ( func_num_args() > 1 ) { |
||
| 52 | foreach ( func_get_args() as $arg ) |
||
| 53 | l($arg); |
||
| 54 | return $stuff; |
||
| 55 | } |
||
| 56 | if ( !isset( $pageload ) ) { |
||
| 57 | $pageload = substr( md5( mt_rand() ), 0, 4 ); |
||
| 58 | if ( !empty( $_SERVER['argv'] ) ) |
||
| 59 | $hint = implode( ' ', $_SERVER['argv'] ); |
||
| 60 | elseif ( isset( $_SERVER['HTTP_HOST'] ) && isset( $_SERVER['REQUEST_URI'] ) ) |
||
| 61 | $hint = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; |
||
| 62 | else |
||
| 63 | $hint = php_sapi_name(); |
||
| 64 | error_log( sprintf( "[%s-%s => %s]", $pageload, getmypid(), $hint ) ); |
||
| 65 | } |
||
| 66 | $pid = $pageload . '-' . getmypid(); |
||
| 67 | if ( is_null( $stuff ) ) { |
||
| 68 | // Log the file and line number |
||
| 69 | $backtrace = debug_backtrace(false); |
||
| 70 | View Code Duplication | while ( isset( $backtrace[1]['function'] ) && $backtrace[1]['function'] == __FUNCTION__ ) |
|
| 71 | array_shift( $backtrace ); |
||
| 72 | $log = sprintf( '%s line %d', $backtrace[0]['file'], $backtrace[0]['line'] ); |
||
| 73 | } elseif ( is_bool( $stuff ) ) { |
||
| 74 | $log = $stuff ? 'TRUE' : 'FALSE'; |
||
| 75 | } elseif ( is_scalar( $stuff ) ) { |
||
| 76 | // Strings and numbers can be logged exactly |
||
| 77 | $log = $stuff; |
||
| 78 | } else { |
||
| 79 | // Are we in an output buffer handler? |
||
| 80 | // If so, print_r($stuff, true) is fatal so we must avoid that. |
||
| 81 | // This is not as slow as it looks: <1ms when !$in_ob_handler. |
||
| 82 | // Using json_encode_pretty() all the time is much slower. |
||
| 83 | do { |
||
| 84 | $in_ob_handler = false; |
||
| 85 | $ob_status = ob_get_status(true); |
||
| 86 | if ( ! $ob_status ) |
||
|
0 ignored issues
–
show
|
|||
| 87 | break; |
||
| 88 | foreach ( $ob_status as $ob ) |
||
| 89 | $obs[] = $ob['name']; |
||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$obs was never initialized. Although not strictly required by PHP, it is generally a good practice to add $obs = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. Loading history...
|
|||
| 90 | // This is not perfect: anonymous handlers appear as default. |
||
| 91 | if ( $obs == array( 'default output handler' ) ) |
||
|
0 ignored issues
–
show
The variable
$obs does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 92 | break; |
||
| 93 | $backtrace = debug_backtrace(false); |
||
| 94 | foreach ( $backtrace as $level ) { |
||
| 95 | $caller = ''; |
||
| 96 | if ( isset( $level['class'] ) ) |
||
| 97 | $caller = $level['class'] . '::'; |
||
| 98 | $caller .= $level['function']; |
||
| 99 | $bts[] = $caller; |
||
|
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
$bts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $bts = array(); before regardless.
Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code. Let’s take a look at an example: foreach ($collection as $item) {
$myArray['foo'] = $item->getFoo();
if ($item->hasBar()) {
$myArray['bar'] = $item->getBar();
}
// do something with $myArray
}
As you can see in this example, the array This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop. Loading history...
|
|||
| 100 | } |
||
| 101 | if ( array_intersect( $obs, $bts ) ) |
||
|
0 ignored issues
–
show
The variable
$bts does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
| 102 | $in_ob_handler = true; |
||
| 103 | } while ( false ); |
||
| 104 | if ( $in_ob_handler ) |
||
| 105 | $log = l_json_encode_pretty( $stuff ); |
||
| 106 | else |
||
| 107 | $log = print_r( $stuff, true ); |
||
| 108 | } |
||
| 109 | error_log( sprintf( "[%s] %s", $pid, $log ) ); |
||
| 110 | return $stuff; |
||
| 111 | } |
||
| 112 | |||
| 113 | // Log only once (suppresses logging on subsequent calls from the same file+line) |
||
| 114 | function lo( $stuff ) { |
||
| 115 | static $callers = array(); |
||
| 116 | $backtrace = debug_backtrace(false); |
||
| 117 | $caller = md5( $backtrace[0]['file'] . $backtrace[0]['line'] ); |
||
| 118 | if ( isset( $callers[$caller] ) ) |
||
| 119 | return $stuff; |
||
| 120 | $callers[$caller] = true; |
||
| 121 | $args = func_get_args(); |
||
| 122 | return call_user_func_array( 'l', $args ); |
||
| 123 | } |
||
| 124 | |||
| 125 | // Pretty print for JSON (stolen from public.api) |
||
| 126 | function l_json_encode_pretty( $data ) { |
||
| 127 | if ( defined( 'JSON_PRETTY_PRINT' ) ) { |
||
| 128 | // Added in PHP 5.4.0 |
||
| 129 | return json_encode( $data, JSON_PRETTY_PRINT ); |
||
| 130 | } |
||
| 131 | |||
| 132 | // Adapted from http://us3.php.net/manual/en/function.json-encode.php#80339 |
||
| 133 | $json = json_encode( $data ); |
||
| 134 | $len = strlen( $json ); |
||
| 135 | |||
| 136 | $tab = "\t"; |
||
| 137 | $new_json = ""; |
||
| 138 | $indent_level = 0; |
||
| 139 | $in_string = false; |
||
| 140 | |||
| 141 | $slashed = false; |
||
| 142 | for ( $c = 0; $c < $len; $c++ ) { |
||
| 143 | $char = $json[$c]; |
||
| 144 | if ( $in_string ) { |
||
| 145 | if ( '"' === $char && $c > 0 && !$slashed ) { |
||
| 146 | $in_string = false; |
||
| 147 | } |
||
| 148 | $new_json .= $char; |
||
| 149 | } else { |
||
| 150 | switch( $char ) { |
||
| 151 | case '{': |
||
| 152 | case '[': |
||
| 153 | $new_json .= $char . "\n" . str_repeat( $tab, ++$indent_level ); |
||
| 154 | break; |
||
| 155 | case '}': |
||
| 156 | case ']': |
||
| 157 | $new_json .= "\n" . str_repeat( $tab, --$indent_level ) . $char; |
||
| 158 | break; |
||
| 159 | case ',': |
||
| 160 | $new_json .= ",\n" . str_repeat( $tab, $indent_level ); |
||
| 161 | break; |
||
| 162 | case ':': |
||
| 163 | $new_json .= ": "; |
||
| 164 | break; |
||
| 165 | case '"': |
||
| 166 | if ( $c > 0 && !$slashed ) { |
||
| 167 | $in_string = true; |
||
| 168 | } |
||
| 169 | // no break |
||
| 170 | default: |
||
| 171 | $new_json .= $char; |
||
| 172 | break; |
||
| 173 | } |
||
| 174 | } |
||
| 175 | if ( '\\' == $char ) { |
||
| 176 | $slashed = !$slashed; |
||
| 177 | } else { |
||
| 178 | $slashed = false; |
||
| 179 | } |
||
| 180 | } |
||
| 181 | |||
| 182 | return $new_json; |
||
| 183 | } |
||
| 184 | |||
| 185 | /** |
||
| 186 | * A timer. Call once to start, call again to stop. Returns a float. |
||
| 187 | * Calling e($name) with different names permits simultaneous timers. |
||
| 188 | * |
||
| 189 | * e('stuff'); |
||
| 190 | * do_stuff(); |
||
| 191 | * $elapsed = e('stuff'); |
||
| 192 | */ |
||
| 193 | function e($name = '') { |
||
| 194 | static $times = array(); |
||
| 195 | if ( !array_key_exists($name, $times ) ) { |
||
| 196 | $times[$name] = microtime( true ); |
||
| 197 | return; |
||
| 198 | } |
||
| 199 | $elapsed = microtime( true ) - $times[$name]; |
||
| 200 | unset( $times[$name] ); |
||
| 201 | return $elapsed; |
||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * A wrapper for e() which also logs the result with l(). |
||
| 206 | * Each log entry begins with a tag common to that pageload. |
||
| 207 | * You can save a keystroke by calling e() then el(). |
||
| 208 | * |
||
| 209 | * e($name); |
||
| 210 | * do_stuff(); |
||
| 211 | * el($name); |
||
| 212 | */ |
||
| 213 | function el($name = '') { |
||
| 214 | $elapsed = e( $name ); |
||
| 215 | if ( $elapsed !== null ) |
||
| 216 | l( sprintf( "%9.6f e('%s')", $elapsed, $name ) ); |
||
| 217 | return $elapsed; |
||
| 218 | } |
||
| 219 | |||
| 220 | /** |
||
| 221 | * A persistent timer. After the initial call, each call to t() |
||
| 222 | * will log the file:line and time elapsed since the initial call. |
||
| 223 | */ |
||
| 224 | function t() { |
||
| 225 | static $start; |
||
| 226 | $now = microtime( true ); |
||
| 227 | if ( !isset( $start ) ) |
||
| 228 | $start = $now; |
||
| 229 | |||
| 230 | $backtrace = debug_backtrace(false); |
||
| 231 | View Code Duplication | while ( isset( $backtrace[1]['function'] ) && $backtrace[1]['function'] == __FUNCTION__ ) |
|
| 232 | array_shift( $backtrace ); |
||
| 233 | |||
| 234 | $file = $backtrace[0]['file']; |
||
| 235 | $line = $backtrace[0]['line']; |
||
| 236 | $format = 't() => %9.6f at %s line %d'; |
||
| 237 | $elapsed = $now - $start; |
||
| 238 | l( sprintf( $format, $elapsed, $file, $line ) ); |
||
| 239 | } |
||
| 240 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.