Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Utils
  • none
  • Tracy
    • Bridges
      • Nette

Classes

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

Interfaces

  • IBarPanel
  • ILogger
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Other releases
  • Nette homepage
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Tracy (https://tracy.nette.org)
  5:  * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
  6:  */
  7: 
  8: namespace Tracy;
  9: 
 10: use Tracy;
 11: 
 12: 
 13: /**
 14:  * Dumps a variable.
 15:  */
 16: class Dumper
 17: {
 18:     const
 19:         DEPTH = 'depth', // how many nested levels of array/object properties display (defaults to 4)
 20:         TRUNCATE = 'truncate', // how truncate long strings? (defaults to 150)
 21:         COLLAPSE = 'collapse', // collapse top array/object or how big are collapsed? (defaults to 14)
 22:         COLLAPSE_COUNT = 'collapsecount', // how big array/object are collapsed? (defaults to 7)
 23:         LOCATION = 'location', // show location string? (defaults to 0)
 24:         OBJECT_EXPORTERS = 'exporters', // custom exporters for objects (defaults to Dumper::$objectexporters)
 25:         LIVE = 'live'; // will be rendered using JavaScript
 26: 
 27:     const
 28:         LOCATION_SOURCE = 1, // shows where dump was called
 29:         LOCATION_LINK = 2, // appends clickable anchor
 30:         LOCATION_CLASS = 4; // shows where class is defined
 31: 
 32:     /** @var array */
 33:     public static $terminalColors = array(
 34:         'bool' => '1;33',
 35:         'null' => '1;33',
 36:         'number' => '1;32',
 37:         'string' => '1;36',
 38:         'array' => '1;31',
 39:         'key' => '1;37',
 40:         'object' => '1;31',
 41:         'visibility' => '1;30',
 42:         'resource' => '1;37',
 43:         'indent' => '1;30',
 44:     );
 45: 
 46:     /** @var array */
 47:     public static $resources = array(
 48:         'stream' => 'stream_get_meta_data',
 49:         'stream-context' => 'stream_context_get_options',
 50:         'curl' => 'curl_getinfo',
 51:     );
 52: 
 53:     /** @var array */
 54:     public static $objectExporters = array(
 55:         'Closure' => 'Tracy\Dumper::exportClosure',
 56:         'SplFileInfo' => 'Tracy\Dumper::exportSplFileInfo',
 57:         'SplObjectStorage' => 'Tracy\Dumper::exportSplObjectStorage',
 58:         '__PHP_Incomplete_Class' => 'Tracy\Dumper::exportPhpIncompleteClass',
 59:     );
 60: 
 61:     /** @var string @internal */
 62:     public static $livePrefix;
 63: 
 64:     /** @var array  */
 65:     private static $liveStorage = array();
 66: 
 67: 
 68:     /**
 69:      * Dumps variable to the output.
 70:      * @return mixed  variable
 71:      */
 72:     public static function dump($var, array $options = NULL)
 73:     {
 74:         if (PHP_SAPI !== 'cli' && !preg_match('#^Content-Type: (?!text/html)#im', implode("\n", headers_list()))) {
 75:             echo self::toHtml($var, $options);
 76:         } elseif (self::detectColors()) {
 77:             echo self::toTerminal($var, $options);
 78:         } else {
 79:             echo self::toText($var, $options);
 80:         }
 81:         return $var;
 82:     }
 83: 
 84: 
 85:     /**
 86:      * Dumps variable to HTML.
 87:      * @return string
 88:      */
 89:     public static function toHtml($var, array $options = NULL)
 90:     {
 91:         $options = (array) $options + array(
 92:             self::DEPTH => 4,
 93:             self::TRUNCATE => 150,
 94:             self::COLLAPSE => 14,
 95:             self::COLLAPSE_COUNT => 7,
 96:             self::OBJECT_EXPORTERS => NULL,
 97:         );
 98:         $loc = & $options[self::LOCATION];
 99:         $loc = $loc === TRUE ? ~0 : (int) $loc;
100: 
101:         $options[self::OBJECT_EXPORTERS] = (array) $options[self::OBJECT_EXPORTERS] + self::$objectExporters;
102:         uksort($options[self::OBJECT_EXPORTERS], function ($a, $b) {
103:             return $b === '' || (class_exists($a, FALSE) && ($rc = new \ReflectionClass($a)) && $rc->isSubclassOf($b)) ? -1 : 1;
104:         });
105: 
106:         $live = !empty($options[self::LIVE]) && $var && (is_array($var) || is_object($var) || is_resource($var));
107:         list($file, $line, $code) = $loc ? self::findLocation() : NULL;
108:         $locAttrs = $file && $loc & self::LOCATION_SOURCE ? Helpers::formatHtml(
109:             ' title="%in file % on line %" data-tracy-href="%"', "$code\n", $file, $line, Helpers::editorUri($file, $line)
110:         ) : NULL;
111: 
112:         return '<pre class="tracy-dump' . ($live && $options[self::COLLAPSE] === TRUE ? ' tracy-collapsed' : '') . '"'
113:             . $locAttrs
114:             . ($live ? " data-tracy-dump='" . json_encode(self::toJson($var, $options), JSON_HEX_APOS | JSON_HEX_AMP) . "'>" : '>')
115:             . ($live ? '' : self::dumpVar($var, $options))
116:             . ($file && $loc & self::LOCATION_LINK ? '<small>in ' . Helpers::editorLink($file, $line) . '</small>' : '')
117:             . "</pre>\n";
118:     }
119: 
120: 
121:     /**
122:      * Dumps variable to plain text.
123:      * @return string
124:      */
125:     public static function toText($var, array $options = NULL)
126:     {
127:         return htmlspecialchars_decode(strip_tags(self::toHtml($var, $options)), ENT_QUOTES);
128:     }
129: 
130: 
131:     /**
132:      * Dumps variable to x-terminal.
133:      * @return string
134:      */
135:     public static function toTerminal($var, array $options = NULL)
136:     {
137:         return htmlspecialchars_decode(strip_tags(preg_replace_callback('#<span class="tracy-dump-(\w+)">|</span>#', function ($m) {
138:             return "\033[" . (isset($m[1], Dumper::$terminalColors[$m[1]]) ? Dumper::$terminalColors[$m[1]] : '0') . 'm';
139:         }, self::toHtml($var, $options))), ENT_QUOTES);
140:     }
141: 
142: 
143:     /**
144:      * Internal toHtml() dump implementation.
145:      * @param  mixed  variable to dump
146:      * @param  array  options
147:      * @param  int    current recursion level
148:      * @return string
149:      */
150:     private static function dumpVar(& $var, array $options, $level = 0)
151:     {
152:         if (method_exists(__CLASS__, $m = 'dump' . gettype($var))) {
153:             return self::$m($var, $options, $level);
154:         } else {
155:             return "<span>unknown type</span>\n";
156:         }
157:     }
158: 
159: 
160:     private static function dumpNull()
161:     {
162:         return "<span class=\"tracy-dump-null\">NULL</span>\n";
163:     }
164: 
165: 
166:     private static function dumpBoolean(& $var)
167:     {
168:         return '<span class="tracy-dump-bool">' . ($var ? 'TRUE' : 'FALSE') . "</span>\n";
169:     }
170: 
171: 
172:     private static function dumpInteger(& $var)
173:     {
174:         return "<span class=\"tracy-dump-number\">$var</span>\n";
175:     }
176: 
177: 
178:     private static function dumpDouble(& $var)
179:     {
180:         $var = is_finite($var)
181:             ? ($tmp = json_encode($var)) . (strpos($tmp, '.') === FALSE ? '.0' : '')
182:             : str_replace('.0', '', var_export($var, TRUE)); // workaround for PHP 7.0.2
183:         return "<span class=\"tracy-dump-number\">$var</span>\n";
184:     }
185: 
186: 
187:     private static function dumpString(& $var, $options)
188:     {
189:         return '<span class="tracy-dump-string">"'
190:             . htmlspecialchars(self::encodeString($var, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8')
191:             . '"</span>' . (strlen($var) > 1 ? ' (' . strlen($var) . ')' : '') . "\n";
192:     }
193: 
194: 
195:     private static function dumpArray(& $var, $options, $level)
196:     {
197:         static $marker;
198:         if ($marker === NULL) {
199:             $marker = uniqid("\x00", TRUE);
200:         }
201: 
202:         $out = '<span class="tracy-dump-array">array</span> (';
203: 
204:         if (empty($var)) {
205:             return $out . ")\n";
206: 
207:         } elseif (isset($var[$marker])) {
208:             return $out . (count($var) - 1) . ") [ <i>RECURSION</i> ]\n";
209: 
210:         } elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH]) {
211:             $collapsed = $level ? count($var) >= $options[self::COLLAPSE_COUNT]
212:                 : (is_int($options[self::COLLAPSE]) ? count($var) >= $options[self::COLLAPSE] : $options[self::COLLAPSE]);
213:             $out = '<span class="tracy-toggle' . ($collapsed ? ' tracy-collapsed' : '') . '">'
214:                 . $out . count($var) . ")</span>\n<div" . ($collapsed ? ' class="tracy-collapsed"' : '') . '>';
215:             $var[$marker] = TRUE;
216:             foreach ($var as $k => & $v) {
217:                 if ($k !== $marker) {
218:                     $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"';
219:                     $out .= '<span class="tracy-dump-indent">   ' . str_repeat('|  ', $level) . '</span>'
220:                         . '<span class="tracy-dump-key">' . $k . '</span> => '
221:                         . self::dumpVar($v, $options, $level + 1);
222:                 }
223:             }
224:             unset($var[$marker]);
225:             return $out . '</div>';
226: 
227:         } else {
228:             return $out . count($var) . ") [ ... ]\n";
229:         }
230:     }
231: 
232: 
233:     private static function dumpObject(& $var, $options, $level)
234:     {
235:         $fields = self::exportObject($var, $options[self::OBJECT_EXPORTERS]);
236:         $editor = NULL;
237:         if ($options[self::LOCATION] & self::LOCATION_CLASS) {
238:             $rc = $var instanceof \Closure ? new \ReflectionFunction($var) : new \ReflectionClass($var);
239:             $editor = Helpers::editorUri($rc->getFileName(), $rc->getStartLine());
240:         }
241:         $out = '<span class="tracy-dump-object"'
242:             . ($editor ? Helpers::formatHtml(
243:                 ' title="Declared in file % on line %" data-tracy-href="%"', $rc->getFileName(), $rc->getStartLine(), $editor
244:             ) : '')
245:             . '>' . htmlspecialchars(Helpers::getClass($var)) . '</span> <span class="tracy-dump-hash">#' . substr(md5(spl_object_hash($var)), 0, 4) . '</span>';
246: 
247:         static $list = array();
248: 
249:         if (empty($fields)) {
250:             return $out . "\n";
251: 
252:         } elseif (in_array($var, $list, TRUE)) {
253:             return $out . " { <i>RECURSION</i> }\n";
254: 
255:         } elseif (!$options[self::DEPTH] || $level < $options[self::DEPTH] || $var instanceof \Closure) {
256:             $collapsed = $level ? count($fields) >= $options[self::COLLAPSE_COUNT]
257:                 : (is_int($options[self::COLLAPSE]) ? count($fields) >= $options[self::COLLAPSE] : $options[self::COLLAPSE]);
258:             $out = '<span class="tracy-toggle' . ($collapsed ? ' tracy-collapsed' : '') . '">'
259:                 . $out . "</span>\n<div" . ($collapsed ? ' class="tracy-collapsed"' : '') . '>';
260:             $list[] = $var;
261:             foreach ($fields as $k => & $v) {
262:                 $vis = '';
263:                 if (isset($k[0]) && $k[0] === "\x00") {
264:                     $vis = ' <span class="tracy-dump-visibility">' . ($k[1] === '*' ? 'protected' : 'private') . '</span>';
265:                     $k = substr($k, strrpos($k, "\x00") + 1);
266:                 }
267:                 $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . htmlspecialchars(self::encodeString($k, $options[self::TRUNCATE]), ENT_NOQUOTES, 'UTF-8') . '"';
268:                 $out .= '<span class="tracy-dump-indent">   ' . str_repeat('|  ', $level) . '</span>'
269:                     . '<span class="tracy-dump-key">' . $k . "</span>$vis => "
270:                     . self::dumpVar($v, $options, $level + 1);
271:             }
272:             array_pop($list);
273:             return $out . '</div>';
274: 
275:         } else {
276:             return $out . " { ... }\n";
277:         }
278:     }
279: 
280: 
281:     private static function dumpResource(& $var, $options, $level)
282:     {
283:         $type = get_resource_type($var);
284:         $out = '<span class="tracy-dump-resource">' . htmlSpecialChars($type, ENT_IGNORE, 'UTF-8') . ' resource</span> '
285:             . '<span class="tracy-dump-hash">#' . intval($var) . '</span>';
286:         if (isset(self::$resources[$type])) {
287:             $out = "<span class=\"tracy-toggle tracy-collapsed\">$out</span>\n<div class=\"tracy-collapsed\">";
288:             foreach (call_user_func(self::$resources[$type], $var) as $k => $v) {
289:                 $out .= '<span class="tracy-dump-indent">   ' . str_repeat('|  ', $level) . '</span>'
290:                     . '<span class="tracy-dump-key">' . htmlSpecialChars($k, ENT_IGNORE, 'UTF-8') . '</span> => ' . self::dumpVar($v, $options, $level + 1);
291:             }
292:             return $out . '</div>';
293:         }
294:         return "$out\n";
295:     }
296: 
297: 
298:     /**
299:      * @return mixed
300:      */
301:     private static function toJson(& $var, $options, $level = 0)
302:     {
303:         if (is_bool($var) || is_null($var) || is_int($var)) {
304:             return $var;
305: 
306:         } elseif (is_float($var)) {
307:             return is_finite($var)
308:                 ? (strpos($tmp = json_encode($var), '.') ? $var : array('number' => "$tmp.0"))
309:                 : array('type' => (string) $var);
310: 
311:         } elseif (is_string($var)) {
312:             return self::encodeString($var, $options[self::TRUNCATE]);
313: 
314:         } elseif (is_array($var)) {
315:             static $marker;
316:             if ($marker === NULL) {
317:                 $marker = uniqid("\x00", TRUE);
318:             }
319:             if (isset($var[$marker]) || $level >= $options[self::DEPTH]) {
320:                 return array(NULL);
321:             }
322:             $res = array();
323:             $var[$marker] = TRUE;
324:             foreach ($var as $k => & $v) {
325:                 if ($k !== $marker) {
326:                     $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . self::encodeString($k, $options[self::TRUNCATE]) . '"';
327:                     $res[] = array($k, self::toJson($v, $options, $level + 1));
328:                 }
329:             }
330:             unset($var[$marker]);
331:             return $res;
332: 
333:         } elseif (is_object($var)) {
334:             $obj = & self::$liveStorage[spl_object_hash($var)];
335:             if ($obj && $obj['level'] <= $level) {
336:                 return array('object' => $obj['id']);
337:             }
338: 
339:             if ($options[self::LOCATION] & self::LOCATION_CLASS) {
340:                 $rc = $var instanceof \Closure ? new \ReflectionFunction($var) : new \ReflectionClass($var);
341:                 $editor = Helpers::editorUri($rc->getFileName(), $rc->getStartLine());
342:             }
343:             static $counter = 1;
344:             $obj = $obj ?: array(
345:                 'id' => self::$livePrefix . '0' . $counter++, // differentiate from resources
346:                 'name' => Helpers::getClass($var),
347:                 'editor' => empty($editor) ? NULL : array('file' => $rc->getFileName(), 'line' => $rc->getStartLine(), 'url' => $editor),
348:                 'level' => $level,
349:                 'object' => $var,
350:             );
351: 
352:             if ($level < $options[self::DEPTH] || !$options[self::DEPTH]) {
353:                 $obj['level'] = $level;
354:                 $obj['items'] = array();
355: 
356:                 foreach (self::exportObject($var, $options[self::OBJECT_EXPORTERS]) as $k => $v) {
357:                     $vis = 0;
358:                     if (isset($k[0]) && $k[0] === "\x00") {
359:                         $vis = $k[1] === '*' ? 1 : 2;
360:                         $k = substr($k, strrpos($k, "\x00") + 1);
361:                     }
362:                     $k = preg_match('#^\w{1,50}\z#', $k) ? $k : '"' . self::encodeString($k, $options[self::TRUNCATE]) . '"';
363:                     $obj['items'][] = array($k, self::toJson($v, $options, $level + 1), $vis);
364:                 }
365:             }
366:             return array('object' => $obj['id']);
367: 
368:         } elseif (is_resource($var)) {
369:             $obj = & self::$liveStorage[(string) $var];
370:             if (!$obj) {
371:                 $type = get_resource_type($var);
372:                 $obj = array('id' => self::$livePrefix . (int) $var, 'name' => $type . ' resource');
373:                 if (isset(self::$resources[$type])) {
374:                     foreach (call_user_func(self::$resources[$type], $var) as $k => $v) {
375:                         $obj['items'][] = array($k, self::toJson($v, $options, $level + 1));
376:                     }
377:                 }
378:             }
379:             return array('resource' => $obj['id']);
380: 
381:         } else {
382:             return array('type' => 'unknown type');
383:         }
384:     }
385: 
386: 
387:     /** @return array  */
388:     public static function fetchLiveData()
389:     {
390:         $res = array();
391:         foreach (self::$liveStorage as $obj) {
392:             $id = $obj['id'];
393:             unset($obj['level'], $obj['object'], $obj['id']);
394:             $res[$id] = $obj;
395:         }
396:         self::$liveStorage = array();
397:         return $res;
398:     }
399: 
400: 
401:     /**
402:      * @internal
403:      * @return string UTF-8
404:      */
405:     public static function encodeString($s, $maxLength = NULL)
406:     {
407:         static $table;
408:         if ($table === NULL) {
409:             foreach (array_merge(range("\x00", "\x1F"), range("\x7F", "\xFF")) as $ch) {
410:                 $table[$ch] = '\x' . str_pad(dechex(ord($ch)), 2, '0', STR_PAD_LEFT);
411:             }
412:             $table['\\'] = '\\\\';
413:             $table["\r"] = '\r';
414:             $table["\n"] = '\n';
415:             $table["\t"] = '\t';
416:         }
417: 
418:         if (preg_match('#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{10FFFF}]#u', $s) || preg_last_error()) {
419:             if ($shortened = ($maxLength && strlen($s) > $maxLength)) {
420:                 $s = substr($s, 0, $maxLength);
421:             }
422:             $s = strtr($s, $table);
423: 
424:         } elseif ($shortened = ($maxLength && strlen(utf8_decode($s)) > $maxLength)) {
425:             if (function_exists('iconv_substr')) {
426:                 $s = iconv_substr($s, 0, $maxLength, 'UTF-8');
427:             } else {
428:                 $i = $len = 0;
429:                 do {
430:                     if (($s[$i] < "\x80" || $s[$i] >= "\xC0") && (++$len > $maxLength)) {
431:                         $s = substr($s, 0, $i);
432:                         break;
433:                     }
434:                 } while (isset($s[++$i]));
435:             }
436:         }
437: 
438:         return $s . (empty($shortened) ? '' : ' ... ');
439:     }
440: 
441: 
442:     /**
443:      * @return array
444:      */
445:     private static function exportObject($obj, array $exporters)
446:     {
447:         foreach ($exporters as $type => $dumper) {
448:             if (!$type || $obj instanceof $type) {
449:                 return call_user_func($dumper, $obj);
450:             }
451:         }
452:         return (array) $obj;
453:     }
454: 
455: 
456:     /**
457:      * @return array
458:      */
459:     private static function exportClosure(\Closure $obj)
460:     {
461:         $rc = new \ReflectionFunction($obj);
462:         $res = array();
463:         foreach ($rc->getParameters() as $param) {
464:             $res[] = '$' . $param->getName();
465:         }
466:         return array(
467:             'file' => $rc->getFileName(),
468:             'line' => $rc->getStartLine(),
469:             'variables' => $rc->getStaticVariables(),
470:             'parameters' => implode(', ', $res),
471:         );
472:     }
473: 
474: 
475:     /**
476:      * @return array
477:      */
478:     private static function exportSplFileInfo(\SplFileInfo $obj)
479:     {
480:         return array('path' => $obj->getPathname());
481:     }
482: 
483: 
484:     /**
485:      * @return array
486:      */
487:     private static function exportSplObjectStorage(\SplObjectStorage $obj)
488:     {
489:         $res = array();
490:         foreach (clone $obj as $item) {
491:             $res[] = array('object' => $item, 'data' => $obj[$item]);
492:         }
493:         return $res;
494:     }
495: 
496: 
497:     /**
498:      * @return array
499:      */
500:     private static function exportPhpIncompleteClass(\__PHP_Incomplete_Class $obj)
501:     {
502:         $info = array('className' => NULL, 'private' => array(), 'protected' => array(), 'public' => array());
503:         foreach ((array) $obj as $name => $value) {
504:             if ($name === '__PHP_Incomplete_Class_Name') {
505:                 $info['className'] = $value;
506:             } elseif (preg_match('#^\x0\*\x0(.+)\z#', $name, $m)) {
507:                 $info['protected'][$m[1]] = $value;
508:             } elseif (preg_match('#^\x0(.+)\x0(.+)\z#', $name, $m)) {
509:                 $info['private'][$m[1] . '::$' . $m[2]] = $value;
510:             } else {
511:                 $info['public'][$name] = $value;
512:             }
513:         }
514:         return $info;
515:     }
516: 
517: 
518:     /**
519:      * Finds the location where dump was called.
520:      * @return array [file, line, code]
521:      */
522:     private static function findLocation()
523:     {
524:         foreach (debug_backtrace(PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : FALSE) as $item) {
525:             if (isset($item['class']) && $item['class'] === __CLASS__) {
526:                 $location = $item;
527:                 continue;
528:             } elseif (isset($item['function'])) {
529:                 try {
530:                     $reflection = isset($item['class'])
531:                         ? new \ReflectionMethod($item['class'], $item['function'])
532:                         : new \ReflectionFunction($item['function']);
533:                     if ($reflection->isInternal() || preg_match('#\s@tracySkipLocation\s#', $reflection->getDocComment())) {
534:                         $location = $item;
535:                         continue;
536:                     }
537:                 } catch (\ReflectionException $e) {
538:                 }
539:             }
540:             break;
541:         }
542: 
543:         if (isset($location['file'], $location['line']) && is_file($location['file'])) {
544:             $lines = file($location['file']);
545:             $line = $lines[$location['line'] - 1];
546:             return array(
547:                 $location['file'],
548:                 $location['line'],
549:                 trim(preg_match('#\w*dump(er::\w+)?\(.*\)#i', $line, $m) ? $m[0] : $line),
550:             );
551:         }
552:     }
553: 
554: 
555:     /**
556:      * @return bool
557:      */
558:     private static function detectColors()
559:     {
560:         return self::$terminalColors &&
561:             (getenv('ConEmuANSI') === 'ON'
562:             || getenv('ANSICON') !== FALSE
563:             || getenv('term') === 'xterm-256color'
564:             || (defined('STDOUT') && function_exists('posix_isatty') && posix_isatty(STDOUT)));
565:     }
566: 
567: }
568: 
Nette 2.3-20161221 API API documentation generated by ApiGen 2.8.0