Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Diagnostics
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
      • Diagnostics
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • PhpGenerator
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
  • NetteModule
  • none

Classes

  • Bar
  • BlueScreen
  • Debugger
  • Dumper
  • FireLogger
  • Helpers
  • Logger
  • OutputDebugger

Interfaces

  • IBarPanel
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Nette\Diagnostics;
  9: 
 10: use Nette;
 11: 
 12: 
 13: /**
 14:  * Dumps a variable.
 15:  *
 16:  * @author     David Grudl
 17:  */
 18: class Dumper
 19: {
 20:     const DEPTH = 'depth', // how many nested levels of array/object properties display (defaults to 4)
 21:         TRUNCATE = 'truncate', // how truncate long strings? (defaults to 150)
 22:         COLLAPSE = 'collapse', // always collapse? (defaults to false)
 23:         COLLAPSE_COUNT = 'collapsecount', // how big array/object are collapsed? (defaults to 7)
 24:         LOCATION = 'location'; // show location string? (defaults to false)
 25: 
 26:     /** @var array */
 27:     public static $terminalColors = array(
 28:         'bool' => '1;33',
 29:         'null' => '1;33',
 30:         'number' => '1;32',
 31:         'string' => '1;36',
 32:         'array' => '1;31',
 33:         'key' => '1;37',
 34:         'object' => '1;31',
 35:         'visibility' => '1;30',
 36:         'resource' => '1;37',
 37:         'indent' => '1;30',
 38:     );
 39: 
 40:     /** @var array */
 41:     public static $resources = array(
 42:         'stream' => 'stream_get_meta_data',
 43:         'stream-context' => 'stream_context_get_options',
 44:         'curl' => 'curl_getinfo',
 45:     );
 46: 
 47: 
 48:     /**
 49:      * Dumps variable to the output.
 50:      * @return mixed  variable
 51:      */
 52:     public static function dump($var, array $options = NULL)
 53:     {
 54:         if (PHP_SAPI !== 'cli' && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()))) {
 55:             echo self::toHtml($var, $options);
 56:         } elseif (self::detectColors()) {
 57:             echo self::toTerminal($var, $options);
 58:         } else {
 59:             echo self::toText($var, $options);
 60:         }
 61:         return $var;
 62:     }
 63: 
 64: 
 65:     /**
 66:      * Dumps variable to HTML.
 67:      * @return string
 68:      */
 69:     public static function toHtml($var, array $options = NULL)
 70:     {
 71:         $options = (array) $options + array(
 72:             self::DEPTH => 4,
 73:             self::TRUNCATE => 150,
 74:             self::COLLAPSE => FALSE,
 75:             self::COLLAPSE_COUNT => 7,
 76:             self::LOCATION => FALSE,
 77:         );
 78:         list($file, $line, $code) = $options[self::LOCATION] ? self::findLocation() : NULL;
 79:         return '<pre class="nette-dump"'
 80:             . ($file ? ' title="' . htmlspecialchars("$code\nin file $file on line $line", ENT_IGNORE | ENT_QUOTES) . '">' : '>')
 81:             . self::dumpVar($var, $options)
 82:             . ($file ? '<small>in ' . Helpers::editorLink($file, $line) . '</small>' : '')
 83:             . "</pre>\n";
 84:     }
 85: 
 86: 
 87:     /**
 88:      * Dumps variable to plain text.
 89:      * @return string
 90:      */
 91:     public static function toText($var, array $options = NULL)
 92:     {
 93:         return htmlspecialchars_decode(strip_tags(self::toHtml($var, $options)), ENT_QUOTES);
 94:     }
 95: 
 96: 
 97:     /**
 98:      * Dumps variable to x-terminal.
 99:      * @return string
100:      */
101:     public static function toTerminal($var, array $options = NULL)
102:     {
103:         return htmlspecialchars_decode(strip_tags(preg_replace_callback('#<span class="nette-dump-(\w+)">|</span>#', function ($m) {
104:             return "\033[" . (isset($m[1], Dumper::$terminalColors[$m[1]]) ? Dumper::$terminalColors[$m[1]] : '0') . "m";
105:         }, self::toHtml($var, $options))), ENT_QUOTES);
106:     }
107: 
108: 
109:     /**
110:      * Internal toHtml() dump implementation.
111:      * @param  mixed  variable to dump
112:      * @param  array  options
113:      * @param  int    current recursion level
114:      * @return string
115:      */
116:     private static function dumpVar(& $var, array $options, $level = 0)
117:     {
118:         if (method_exists(__CLASS__, $m = 'dump' . gettype($var))) {
119:             return self::$m($var, $options, $level);
120:         } else {
121:             return "<span>unknown type</span>\n";
122:         }
123:     }
124: 
125: 
126:     private static function dumpNull()
127:     {
128:         return "<span class=\"nette-dump-null\">NULL</span>\n";
129:     }
130: 
131: 
132:     private static function dumpBoolean(& $var)
133:     {
134:         return '<span class="nette-dump-bool">' . ($var ? 'TRUE' : 'FALSE') . "</span>\n";
135:     }
136: 
137: 
138:     private static function dumpInteger(& $var)
139:     {
140:         return "<span class=\"nette-dump-number\">$var</span>\n";
141:     }
142: 
143: 
144:     private static function dumpDouble(& $var)
145:     {
146:         $var = is_finite($var)
147:             ? ($tmp = json_encode($var)) . (strpos($tmp, '.') === FALSE ? '.0' : '')
148:             : var_export($var, TRUE);
149:         return "<span class=\"nette-dump-number\">$var</span>\n";
150:     }
151: 
152: 
153:     private static function dumpString(& $var, $options)
154:     {
155:         return '<span class="nette-dump-string">'
156:             . self::encodeString($options[self::TRUNCATE] && strlen($var) > $options[self::TRUNCATE] ? substr($var, 0, $options[self::TRUNCATE]) . ' ... ' : $var)
157:             . '</span>' . (strlen($var) > 1 ? ' (' . strlen($var) . ')' : '') . "\n";
158:     }
159: 
160: 
161:     private static function dumpArray(& $var, $options, $level)
162:     {
163:         static $marker;
164:         if ($marker === NULL) {
165:             $marker = uniqid("\x00", TRUE);
166:         }
167: 
168:         $out = '<span class="nette-dump-array">array</span> (';
169: 
170:         if (empty($var)) {
171:             return $out . ")\n";
172: 
173:         } elseif (isset($var[$marker])) {
174:             return $out . (count($var) - 1) . ") [ <i>RECURSION</i> ]\n";
175: 
176:         } elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH]) {
177:             $collapsed = $level ? count($var) >= $options[self::COLLAPSE_COUNT] : $options[self::COLLAPSE];
178:             $out = '<span class="nette-toggle' . ($collapsed ? '-collapsed' : '') . '">' . $out . count($var) . ")</span>\n<div" . ($collapsed ? ' class="nette-collapsed"' : '') . '>';
179:             $var[$marker] = TRUE;
180:             foreach ($var as $k => & $v) {
181:                 if ($k !== $marker) {
182:                     $out .= '<span class="nette-dump-indent">   ' . str_repeat('|  ', $level) . '</span>'
183:                         . '<span class="nette-dump-key">' . (preg_match('#^\w+\z#', $k) ? $k : self::encodeString($k)) . '</span> => '
184:                         . self::dumpVar($v, $options, $level + 1);
185:                 }
186:             }
187:             unset($var[$marker]);
188:             return $out . '</div>';
189: 
190:         } else {
191:             return $out . count($var) . ") [ ... ]\n";
192:         }
193:     }
194: 
195: 
196:     private static function dumpObject(& $var, $options, $level)
197:     {
198:         if ($var instanceof \Closure) {
199:             $rc = new \ReflectionFunction($var);
200:             $fields = array();
201:             foreach ($rc->getParameters() as $param) {
202:                 $fields[] = '$' . $param->getName();
203:             }
204:             $fields = array(
205:                 'file' => $rc->getFileName(), 'line' => $rc->getStartLine(),
206:                 'variables' => $rc->getStaticVariables(), 'parameters' => implode(', ', $fields)
207:             );
208:         } elseif ($var instanceof \SplFileInfo) {
209:             $fields = array('path' => $var->getPathname());
210:         } elseif ($var instanceof \SplObjectStorage) {
211:             $fields = array();
212:             foreach (clone $var as $obj) {
213:                 $fields[] = array('object' => $obj, 'data' => $var[$obj]);
214:             }
215:         } else {
216:             $fields = (array) $var;
217:         }
218: 
219:         static $list = array();
220:         $rc = $var instanceof \Closure ? new \ReflectionFunction($var) : new \ReflectionClass($var);
221:         $out = '<span class="nette-dump-object"'
222:             . ($options[self::LOCATION] && $rc->getFileName() ? ' data-nette-href="' . htmlspecialchars(strtr(Debugger::$editor, array('%file' => rawurlencode($rc->getFileName()), '%line' => $rc->getStartLine()))) . '"' : '')
223:             . '>' . get_class($var) . '</span> <span class="nette-dump-hash">#' . substr(md5(spl_object_hash($var)), 0, 4) . '</span>';
224: 
225:         if (empty($fields)) {
226:             return $out . "\n";
227: 
228:         } elseif (in_array($var, $list, TRUE)) {
229:             return $out . " { <i>RECURSION</i> }\n";
230: 
231:         } elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH] || $var instanceof \Closure) {
232:             $collapsed = $level ? count($fields) >= $options[self::COLLAPSE_COUNT] : $options[self::COLLAPSE];
233:             $out = '<span class="nette-toggle' . ($collapsed ? '-collapsed' : '') . '">' . $out . "</span>\n<div" . ($collapsed ? ' class="nette-collapsed"' : '') . '>';
234:             $list[] = $var;
235:             foreach ($fields as $k => & $v) {
236:                 $vis = '';
237:                 if ($k[0] === "\x00") {
238:                     $vis = ' <span class="nette-dump-visibility">' . ($k[1] === '*' ? 'protected' : 'private') . '</span>';
239:                     $k = substr($k, strrpos($k, "\x00") + 1);
240:                 }
241:                 $out .= '<span class="nette-dump-indent">   ' . str_repeat('|  ', $level) . '</span>'
242:                     . '<span class="nette-dump-key">' . (preg_match('#^\w+\z#', $k) ? $k : self::encodeString($k)) . "</span>$vis => "
243:                     . self::dumpVar($v, $options, $level + 1);
244:             }
245:             array_pop($list);
246:             return $out . '</div>';
247: 
248:         } else {
249:             return $out . " { ... }\n";
250:         }
251:     }
252: 
253: 
254:     private static function dumpResource(& $var, $options, $level)
255:     {
256:         $type = get_resource_type($var);
257:         $out = '<span class="nette-dump-resource">' . htmlSpecialChars($type) . ' resource</span>';
258:         if (isset(self::$resources[$type])) {
259:             $out = "<span class=\"nette-toggle-collapsed\">$out</span>\n<div class=\"nette-collapsed\">";
260:             foreach (call_user_func(self::$resources[$type], $var) as $k => $v) {
261:                 $out .= '<span class="nette-dump-indent">   ' . str_repeat('|  ', $level) . '</span>'
262:                     . '<span class="nette-dump-key">' . htmlSpecialChars($k) . "</span> => " . self::dumpVar($v, $options, $level + 1);
263:             }
264:             return $out . '</div>';
265:         }
266:         return "$out\n";
267:     }
268: 
269: 
270:     private static function encodeString($s)
271:     {
272:         static $table;
273:         if ($table === NULL) {
274:             foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
275:                 $table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
276:             }
277:             $table["\\"] = '\\\\';
278:             $table["\r"] = '\r';
279:             $table["\n"] = '\n';
280:             $table["\t"] = '\t';
281:         }
282: 
283:         if (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $s) || preg_last_error()) {
284:             $s = strtr($s, $table);
285:         }
286:         return '"' . htmlSpecialChars($s, ENT_NOQUOTES) . '"';
287:     }
288: 
289: 
290:     /**
291:      * Finds the location where dump was called.
292:      * @return array [file, line, code]
293:      */
294:     private static function findLocation()
295:     {
296:         foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) {
297:             if (isset($item['class']) && $item['class'] === __CLASS__) {
298:                 $location = $item;
299:                 continue;
300:             } elseif (isset($item['function'])) {
301:                 try {
302:                     $reflection = isset($item['class'])
303:                         ? new \ReflectionMethod($item['class'], $item['function'])
304:                         : new \ReflectionFunction($item['function']);
305:                     if (preg_match('#\s@tracySkipLocation\s#', $reflection->getDocComment())) {
306:                         $location = $item;
307:                         continue;
308:                     }
309:                 } catch (\ReflectionException $e) {}
310:             }
311:             break;
312:         }
313: 
314:         if (isset($location['file'], $location['line']) && is_file($location['file'])) {
315:             $lines = file($location['file']);
316:             $line = $lines[$location['line'] - 1];
317:             return array(
318:                 $location['file'],
319:                 $location['line'],
320:                 trim(preg_match('#\w*dump(er::\w+)?\(.*\)#i', $line, $m) ? $m[0] : $line)
321:             );
322:         }
323:     }
324: 
325: 
326:     /**
327:      * @return bool
328:      */
329:     private static function detectColors()
330:     {
331:         return self::$terminalColors &&
332:             (getenv('ConEmuANSI') === 'ON'
333:             || getenv('ANSICON') !== FALSE
334:             || (defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT)));
335:     }
336: 
337: }
338: 
Nette 2.1 API documentation generated by ApiGen 2.8.0