Permalink
Browse files

Merge remote-tracking branch 'core-logger/master'

* core-logger/master:
  fix
  tweaks
  caster related refacto
  dump on stderr by default
  global dump() function
  add maxString param to CliColorDumper
  use default Reflector caster instead of ReflectionCaster
  fix
  reflector caster

Conflicts:
	core/logger/bootup.logger.php
  • Loading branch information...
2 parents ef8c6b3 + cea4db8 commit 62ec83585ec22ccbd7efea60e4c70163a7905733 @nicolas-grekas committed Nov 9, 2014
View
75 ...er/class/Patchwork/PHP/CliColorDumper.php → .../logger/class/Patchwork/PHP/CliDumper.php
@@ -1,6 +1,6 @@
<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
/*
- * Copyright (C) 2012 Nicolas Grekas - p@tchwork.com
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the (at your option):
@@ -11,18 +11,18 @@
namespace Patchwork\PHP;
/**
- * CliColorDumper dumps variable for command line output.
+ * CliDumper dumps variable for command line output.
*/
-class CliColorDumper extends Dumper
+class CliDumper extends Dumper
{
public
- $maxStringWidth = 80;
+ $colors = true,
+ $maxString = 100000,
+ $maxStringWidth = 120;
protected
- $line = '',
- $lastHash = 0,
$styles = array(
// See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
'num' => '1;38;5;33',
@@ -37,27 +37,6 @@ class CliColorDumper extends Dumper
'meta' => '38;5;27',
);
- static function dump(&$a)
- {
- $d = new self;
- $d->setCallback('line', array(__CLASS__, 'echoLine'));
- $d->walk($a);
- }
-
-
- function walk(&$a)
- {
- $this->line = '';
- $this->lastHash = 0;
- parent::walk($a);
- '' !== $this->line && $this->dumpLine(0);
- }
-
- protected function dumpLine($depth_offset)
- {
- call_user_func($this->callbacks['line'], $this->line, $this->depth + $depth_offset);
- $this->line = '';
- }
protected function dumpRef($is_soft, $ref_counter = null, &$ref_value = null, $ref_type = null)
{
@@ -142,7 +121,7 @@ protected function dumpString($a, $is_key, $style = null)
$this->dumpLine(-$is_key);
$is_key = ': ';
- $a = explode(':', $a);
+ $a = explode(':', $a, 2);
if (isset($a[1]))
{
@@ -167,7 +146,7 @@ protected function dumpString($a, $is_key, $style = null)
}
else $is_key = '';
- if ('' === $a) return $this->line .= '"' . $is_key;
+ if ('' === $a) return $this->line .= "''" . $is_key;
isset($style) or $style = 'str';
@@ -176,9 +155,16 @@ protected function dumpString($a, $is_key, $style = null)
$a = utf8_encode($a);
}
+ if (0 < $this->maxString && $this->maxString < $len = iconv_strlen($a, 'UTF-8'))
+ {
+ $a = iconv_substr($a, 0, $this->maxString - 1, 'UTF-8');
+ $cutBy = $len - $this->maxString + 1;
+ }
+ else $cutBy = 0;
+
$a = explode("\n", $a);
$x = isset($a[1]);
- $i = 0;
+ $i = $len = 0;
foreach ($a as $a)
{
@@ -188,12 +174,13 @@ protected function dumpString($a, $is_key, $style = null)
$is_key or $this->line .= ' ';
}
- $len = iconv_strlen($a);
+ $len = iconv_strlen($a, 'UTF-8');
if (0 < $this->maxStringWidth && $this->maxStringWidth < $len)
{
$a = iconv_substr($a, 0, $this->maxStringWidth - 1, 'UTF-8');
$a = $this->style($style, $a) . '';
+ $cutBy += $len - $this->maxStringWidth + 1;
}
else
{
@@ -214,6 +201,16 @@ protected function dumpString($a, $is_key, $style = null)
else $this->line .= $a;
}
+ if ($cutBy)
+ {
+ if (0 >= $this->maxStringWidth || $this->maxStringWidth >= $len)
+ {
+ $this->line .= '';
+ }
+
+ $this->dumpScalar($cutBy);
+ }
+
$this->line .= $is_key;
}
@@ -222,9 +219,6 @@ protected function walkHash($type, &$a, $len)
if ('array:0' === $type) $this->line .= '[]';
else
{
- $h = $this->lastHash;
- $this->lastHash = $this->counter;
-
$is_array = 0 === strncmp($type, 'array:', 6);
if ($is_array)
@@ -240,11 +234,10 @@ protected function walkHash($type, &$a, $len)
$this->line .= ' ' . $this->style('ref', "#$this->counter");
+ $startCounter = $this->counter;
$refs = parent::walkHash($type, $a, $len);
+ if ($this->counter !== $startCounter) $this->dumpLine(1);
- if ($this->counter !== $this->lastHash) $this->dumpLine(1);
-
- $this->lastHash = $h;
$this->line .= $is_array ? ']' : '}';
if ($refs)
@@ -297,6 +290,8 @@ protected function walkHash($type, &$a, $len)
protected function style($style, $a)
{
+ if (! $this->colors) return $a;
+
switch ($style)
{
case 'str':
@@ -323,10 +318,4 @@ protected function style($style, $a)
return sprintf("\e[%sm%s\e[m", $this->styles[$style], $a);
}
-
-
- protected static function echoLine($line, $depth)
- {
- echo str_repeat(' ', $depth), $line, "\n";
- }
}
View
140 core/logger/class/Patchwork/PHP/Dumper.php
@@ -1,6 +1,6 @@
<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
/*
- * Copyright (C) 2012 Nicolas Grekas - p@tchwork.com
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the (at your option):
@@ -26,38 +26,90 @@
$maxLength = 1000,
$maxDepth = 10;
+ static
+
+ $defaultCasters = array(
+ 'o:Closure' => array('Patchwork\PHP\Dumper\BaseCaster', 'castClosure'),
+ 'o:Reflector' => array('Patchwork\PHP\Dumper\BaseCaster', 'castReflector'),
+ 'o:PDO' => array('Patchwork\PHP\Dumper\PdoCaster', 'castPdo'),
+ 'o:PDOStatement' => array('Patchwork\PHP\Dumper\PdoCaster', 'castPdoStatement'),
+ 'o:Exception' => array('Patchwork\PHP\Dumper\ExceptionCaster', 'castException'),
+ 'o:ErrorException' => array('Patchwork\PHP\Dumper\ExceptionCaster', 'castErrorException'),
+ 'o:Patchwork\PHP\InDepthRecoverableErrorException'
+ => array('Patchwork\PHP\Dumper\ExceptionCaster', 'castInDepthException'),
+ 'o:Doctrine\ORM\Proxy\Proxy'
+ => array('Patchwork\PHP\Dumper\DoctrineCaster', 'castOrmProxy'),
+ 'o:Doctrine\Common\Proxy\Proxy'
+ => array('Patchwork\PHP\Dumper\DoctrineCaster', 'castCommonProxy'),
+ 'r:dba' => array('Patchwork\PHP\Dumper\BaseCaster', 'castDba'),
+ 'r:dba persistent' => array('Patchwork\PHP\Dumper\BaseCaster', 'castDba'),
+ 'r:process' => array('Patchwork\PHP\Dumper\BaseCaster', 'castProcess'),
+ 'r:stream' => array('Patchwork\PHP\Dumper\BaseCaster', 'castStream'),
+ );
+
protected
+ $line = '',
+ $lines = array(),
+ $lastHash = 0,
$dumpLength = 0,
$depthLimited = array(),
$objectsDepth = array(),
$reserved = array('_' => 1, '__cutBy' => 1, '__refs' => 1, '__proto__' => 1),
- $callbacks = array(
- 'o:pdo' => array('Patchwork\PHP\Dumper\Caster', 'castPdo'),
- 'o:pdostatement' => array('Patchwork\PHP\Dumper\Caster', 'castPdoStatement'),
- 'o:closure' => array('Patchwork\PHP\Dumper\Caster', 'castClosure'),
- 'r:stream' => 'stream_get_meta_data',
- 'r:process' => 'proc_get_status',
- 'r:dba persistent' => array('Patchwork\PHP\Dumper\Caster', 'castDba'),
- 'r:dba' => array('Patchwork\PHP\Dumper\Caster', 'castDba'),
- );
+ $lineDumper = array(__CLASS__, 'echoLine'),
+ $casters = array();
+
+
+ function __construct(array $defaultCasters = null)
+ {
+ $this->setLineDumper(array($this, 'stackLine'));
+ isset($defaultCasters) or $defaultCasters = static::$defaultCasters;
+ $this->addCasters($defaultCasters);
+ }
+ function addCasters(array $casters)
+ {
+ foreach ($casters as $type => $callback)
+ {
+ $this->casters[strtolower($type)][] = $callback;
+ }
+ }
- function setCallback($type, $callback)
+ function setLineDumper($callback)
{
- $this->callbacks[strtolower($type)] = $callback;
+ $prev = $this->lineDumper;
+ $this->lineDumper = $callback;
+
+ return $prev;
}
function walk(&$a)
{
+ $this->line = '';
+ $this->lastHash = 0;
+
try {parent::walk($a);}
catch (\Exception $e) {}
$this->depthLimited = $this->objectsDepth = array();
+ '' !== $this->line && $this->dumpLine(0);
if (isset($e)) throw $e;
+
+ $lines = implode("\n", $this->lines);
+ $this->lines = array();
+
+ return $lines;
}
+ static function dump(&$a)
+ {
+ $d = new static;
+ $d->setLineDumper(array(get_called_class(), 'echoLine'));
+ $d->walk($a);
+ }
+
+
protected function dumpObject($obj, $hash)
{
if (isset($this->objectsDepth[$hash]))
@@ -71,46 +123,46 @@ protected function dumpObject($obj, $hash)
else unset($this->objectsDepth[$hash]);
}
+ $a = (array) $obj;
$c = get_class($obj);
$p = array($c => $c)
+ class_parents($obj)
+ class_implements($obj)
+ array('*' => '*');
- foreach ($p as $p)
+ foreach (array_reverse($p) as $p)
{
- if (isset($this->callbacks[$p = 'o:' . strtolower($p)]))
+ if (! empty($this->casters[$p = 'o:' . strtolower($p)]))
{
- if (!$p = $this->callbacks[$p]) $a = array();
- else
+ foreach ($this->casters[$p] as $p)
{
- try {$a = call_user_func($p, $obj);}
- catch (\Exception $e) {unset($a); continue;}
+ try {$a = call_user_func($p, $obj, $a);}
+ catch (\Exception $e) {}
}
- break;
}
}
- isset($a) || $a = (array) $obj;
-
$this->walkHash($c, $a, count($a));
}
protected function dumpResource($res)
{
- $h = get_resource_type($res);
+ $type = get_resource_type($res);
$a = array();
+ $b = array();
- if (! empty($this->callbacks['r:' . $h]))
+ if (! empty($this->casters['r:' . $type]))
{
- try {$res = call_user_func($this->callbacks['r:' . $h], $res);}
- catch (\Exception $e) {$res = array();}
-
- foreach ($res as $k => $v)
- $a["\0~\0" . $k] = $v;
+ foreach ($this->casters['r:' . $type] as $c)
+ {
+ try {$b = call_user_func($c, $res, $b);}
+ catch (\Exception $e) {}
+ }
}
- $this->walkHash("resource:{$h}", $a, count($a));
+ foreach ($b as $b => $c) $a["\0~\0$b"] = $c;
+
+ $this->walkHash("resource:{$type}", $a, count($a));
}
protected function dumpRef($is_soft, $ref_counter = null, &$ref_value = null, $ref_type = null)
@@ -153,6 +205,9 @@ protected function dumpRef($is_soft, $ref_counter = null, &$ref_value = null, $r
protected function walkHash($type, &$a, $len)
{
+ $lastHash = $this->lastHash;
+ $this->lastHash = $this->counter;
+
if ($len && $this->depth >= $this->maxDepth && 0 < $this->maxDepth)
{
$this->depthLimited[$this->counter] = 1;
@@ -165,7 +220,12 @@ protected function walkHash($type, &$a, $len)
$len = 0;
}
- if (!$len) return array();
+ if (! $len)
+ {
+ $this->lastHash = $lastHash;
+
+ return array();
+ }
++$this->depth;
if (0 === strncmp($type, 'array:', 6)) unset($type);
@@ -225,8 +285,28 @@ protected function walkHash($type, &$a, $len)
while (end($this->objectsDepth) === $this->depth) array_pop($this->objectsDepth);
+ $this->lastHash = $lastHash;
+
if (--$this->depth) return array();
$this->depthLimited = array();
return $this->cleanRefPools();
}
+
+ protected function dumpLine($depth_offset)
+ {
+ call_user_func($this->lineDumper, $this->line, $this->depth + $depth_offset);
+ $this->line = '';
+ }
+
+ protected function stackLine($line, $depth)
+ {
+ $this->lines[] = str_repeat(' ', $depth) . $line;
+ }
+
+ protected static function echoLine($line, $depth)
+ {
+ static $stderr;
+ isset($stderr) or $stderr = fopen('php://stderr', 'wb');
+ fwrite($stderr, str_repeat(' ', $depth) . $line . "\n");
+ }
}
View
47 core/logger/class/Patchwork/PHP/Dumper/BaseCaster.php
@@ -0,0 +1,47 @@
+<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
+/*
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the (at your option):
+ * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
+ * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
+ */
+
+namespace Patchwork\PHP\Dumper;
+
+class BaseCaster
+{
+ static function castReflector(\Reflector $c, array $a)
+ {
+ $a["\0~\0reflection"] = $c->__toString();
+
+ return $a;
+ }
+
+ static function castClosure(\Closure $c, array $a)
+ {
+ $a = static::castReflector(new \ReflectionFunction($c), $a);
+ unset($a[0], $a['name']);
+
+ return $a;
+ }
+
+ static function castDba($dba, array $a)
+ {
+ $list = dba_list();
+ $a['file'] = $list[substr((string) $dba, 13)];
+
+ return $a;
+ }
+
+ static function castProcess($process, array $a)
+ {
+ return proc_get_status($process);
+ }
+
+ static function castStream($stream, array $a)
+ {
+ return stream_get_meta_data($stream);
+ }
+}
View
155 core/logger/class/Patchwork/PHP/Dumper/Caster.php
@@ -1,155 +0,0 @@
-<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
-/*
- * Copyright (C) 2012 Nicolas Grekas - p@tchwork.com
- *
- * This library is free software; you can redistribute it and/or modify it
- * under the terms of the (at your option):
- * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
- * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
- */
-
-namespace Patchwork\PHP\Dumper;
-
-/**
- * Caster is a collection of methods each specific to one type of objet for
- * casting to array suitable for extensive dumping by Patchwork\PHP\Dumper.
- */
-class Caster
-{
- const META_PREFIX = "\0~\0";
-
- static function castClosure($c)
- {
- $a = array();
- if (!class_exists('ReflectionFunction', false) || 'Closure' !== get_class($c)) return $a;
- $c = new \ReflectionFunction($c);
-
- foreach ($c->getParameters() as $p)
- {
- $n = strstr($p->__toString(), '>');
- $n = substr($n, 2, strpos($n, ' = ') - 2);
-
- try
- {
- if (strpos($n, ' or NULL ')) $a[str_replace(' or NULL', '', $n)] = null;
- else if ($p->isDefaultValueAvailable()) $a[$n] = $p->getDefaultValue();
- else $a[] = $n;
- }
- catch (\ReflectionException $p)
- {
- // This will be reached on PHP 5.3.16 because of https://bugs.php.net/62715
- $a[] = $n;
- }
- }
-
- $m = self::META_PREFIX;
- $a = array(
- $m . 'returnsRef' => true,
- $m . 'args' => $a,
- );
- if (!$c->returnsReference()) unset($a[$m . 'returnsRef']);
- $a[$m . 'use'] = array();
-
- if (false === $a[$m . 'file'] = $c->getFileName()) unset($a[$m . 'file']);
- else $a[$m . 'lines'] = $c->getStartLine() . '-' . $c->getEndLine();
-
- if (!$c = $c->getStaticVariables()) unset($a[$m . 'use']);
- else foreach ($c as $p => &$c) $a[$m . 'use']['$' . $p] =& $c;
-
- return $a;
- }
-
-
- static $pdoAttributes = array(
- 'CASE' => array(
- \PDO::CASE_LOWER => 'LOWER',
- \PDO::CASE_NATURAL => 'NATURAL',
- \PDO::CASE_UPPER => 'UPPER',
- ),
- 'ERRMODE' => array(
- \PDO::ERRMODE_SILENT => 'SILENT',
- \PDO::ERRMODE_WARNING => 'WARNING',
- \PDO::ERRMODE_EXCEPTION => 'EXCEPTION',
- ),
- 'TIMEOUT',
- 'PREFETCH',
- 'AUTOCOMMIT',
- 'PERSISTENT',
- 'DRIVER_NAME',
- 'SERVER_INFO',
- 'ORACLE_NULLS' => array(
- \PDO::NULL_NATURAL => 'NATURAL',
- \PDO::NULL_EMPTY_STRING => 'EMPTY_STRING',
- \PDO::NULL_TO_STRING => 'TO_STRING',
- ),
- 'CLIENT_VERSION',
- 'SERVER_VERSION',
- 'STATEMENT_CLASS',
- 'EMULATE_PREPARES',
- 'CONNECTION_STATUS',
- 'STRINGIFY_FETCHES',
- 'DEFAULT_FETCH_MODE' => array(
- \PDO::FETCH_ASSOC => 'ASSOC',
- \PDO::FETCH_BOTH => 'BOTH',
- \PDO::FETCH_LAZY => 'LAZY',
- \PDO::FETCH_NUM => 'NUM',
- \PDO::FETCH_OBJ => 'OBJ',
- ),
- );
-
- static function castPdo($c)
- {
- $a = array();
- $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE);
- $c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
-
- foreach (self::$pdoAttributes as $attr => $values)
- {
- if (!isset($attr[0]))
- {
- $attr = $values;
- $values = array();
- }
-
- try
- {
- $a[$attr] = 'ERRMODE' === $attr ? $errmode : $c->getAttribute(constant("PDO::ATTR_{$attr}"));
- if (isset($values[$attr][$a[$attr]])) $a[$attr] = $values[$attr][$a[$attr]];
- }
- catch (\Exception $attr)
- {
- }
- }
-
- $m = self::META_PREFIX;
-
- $a = (array) $c + array(
- $m . 'inTransaction' => method_exists($c, 'inTransaction'),
- $m . 'errorInfo' => $c->errorInfo(),
- $m . 'attributes' => $a,
- );
-
- if ($a[$m . 'inTransaction']) $a[$m . 'inTransaction'] = $c->inTransaction();
- else unset($a[$m . 'inTransaction']);
-
- if (!isset($a[$m . 'errorInfo'][1], $a[$m . 'errorInfo'][2])) unset($a[$m . 'errorInfo']);
-
- $c->setAttribute(\PDO::ATTR_ERRMODE, $errmode);
-
- return $a;
- }
-
- static function castPdoStatement($c)
- {
- $m = self::META_PREFIX;
- $a = (array) $c + array($m . 'errorInfo' => $c->errorInfo());
- if (!isset($a[$m . 'errorInfo'][1], $a[$m . 'errorInfo'][2])) unset($a[$m . 'errorInfo']);
- return $a;
- }
-
- static function castDba($dba)
- {
- $list = dba_list();
- return array('file' => $list[substr((string) $dba, 13)]);
- }
-}
View
37 core/logger/class/Patchwork/PHP/Dumper/DoctrineCaster.php
@@ -0,0 +1,37 @@
+<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
+/*
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the (at your option):
+ * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
+ * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
+ */
+
+namespace Patchwork\PHP\Dumper;
+
+class DoctrineCaster
+{
+ static function castCommonProxy(\Doctrine\Common\Proxy\Proxy $p, array $a)
+ {
+ unset(
+ $a['__cloner__'],
+ $a['__initializer__'],
+ $a['__isInitialized__']
+ );
+
+ return $a;
+ }
+
+ static function castOrmProxy(\Doctrine\ORM\Proxy\Proxy $p, array $a)
+ {
+ $p = "\0" . get_class($p) . "\0";
+ unset(
+ $a[$p . '_entityPersister'],
+ $a[$p . '_identifier'],
+ $a['__isInitialized__']
+ );
+
+ return $a;
+ }
+}
View
95 core/logger/class/Patchwork/PHP/Dumper/ExceptionCaster.php
@@ -0,0 +1,95 @@
+<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
+/*
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the (at your option):
+ * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
+ * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
+ */
+
+namespace Patchwork\PHP\Dumper;
+
+use Patchwork\PHP\InDepthRecoverableErrorException as InDepthException;
+
+class ExceptionCaster
+{
+ static public
+
+ $errorTypes = array(
+ E_DEPRECATED => 'E_DEPRECATED',
+ E_USER_DEPRECATED => 'E_USER_DEPRECATED',
+ E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
+ E_ERROR => 'E_ERROR',
+ E_WARNING => 'E_WARNING',
+ E_PARSE => 'E_PARSE',
+ E_NOTICE => 'E_NOTICE',
+ E_CORE_ERROR => 'E_CORE_ERROR',
+ E_CORE_WARNING => 'E_CORE_WARNING',
+ E_COMPILE_ERROR => 'E_COMPILE_ERROR',
+ E_COMPILE_WARNING => 'E_COMPILE_WARNING',
+ E_USER_ERROR => 'E_USER_ERROR',
+ E_USER_WARNING => 'E_USER_WARNING',
+ E_USER_NOTICE => 'E_USER_NOTICE',
+ E_STRICT => 'E_STRICT',
+ );
+
+ static function castException(\Exception $e, array $a)
+ {
+ $trace = $a["\0Exception\0trace"];
+ unset($a["\0Exception\0trace"]); // Ensures the trace is always last
+
+ static::filterTrace($trace, $e instanceof InDepthException ? $e->traceOffset : 0, 1);
+
+ if (isset($trace)) $a["\0Exception\0trace"] = $trace;
+ if (empty($a["\0Exception\0previous"])) unset($a["\0Exception\0previous"]);
+ unset($a["\0Exception\0string"], $a['xdebug_message'], $a['__destructorException']);
+
+ return $a;
+ }
+
+ static function castErrorException(\ErrorException $e, array $a)
+ {
+ if (isset($a[$s = "\0*\0severity"], self::$errorTypes[$a[$s]])) $a[$s] = self::$errorTypes[$a[$s]];
+
+ return $a;
+ }
+
+ static function castInDepthException(InDepthException $e, array $a)
+ {
+ unset($a['traceOffset']);
+
+ if (! isset($a['context'])) unset($a['context']);
+ else if (isset($a["\0Exception\0trace"]['seeHash']))
+ {
+ $a['context'] = $a["\0Exception\0trace"];
+ }
+
+ return $a;
+ }
+
+ static function filterTrace(&$trace, $offset, $dumpArgs)
+ {
+ if (0 > $offset || empty($trace[$offset])) return $trace = null;
+
+ $t = $trace[$offset];
+
+ if (empty($t['class']) && isset($t['function']))
+ if ('user_error' === $t['function'] || 'trigger_error' === $t['function'])
+ ++$offset;
+
+ $offset && array_splice($trace, 0, $offset);
+
+ foreach ($trace as &$t)
+ {
+ $offset = (isset($t['class']) ? $t['class'] . $t['type'] : '')
+ . $t['function'] . '()'
+ . (isset($t['line']) ? " {$t['file']}:{$t['line']}" : '');
+
+ if (! isset($t['args']) || ! $dumpArgs) $t = array();
+ else $t = array('args' => $t['args']);
+
+ $t = array('call' => $offset) + $t;
+ }
+ }
+}
View
106 core/logger/class/Patchwork/PHP/Dumper/PdoCaster.php
@@ -0,0 +1,106 @@
+<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
+/*
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the (at your option):
+ * Apache License v2.0 (http://apache.org/licenses/LICENSE-2.0.txt), or
+ * GNU General Public License v2.0 (http://gnu.org/licenses/gpl-2.0.txt).
+ */
+
+namespace Patchwork\PHP\Dumper;
+
+use PDO;
+use PDOStatement;
+
+class PdoCaster
+{
+ static $pdoAttributes = array(
+ 'CASE' => array(
+ PDO::CASE_LOWER => 'LOWER',
+ PDO::CASE_NATURAL => 'NATURAL',
+ PDO::CASE_UPPER => 'UPPER',
+ ),
+ 'ERRMODE' => array(
+ PDO::ERRMODE_SILENT => 'SILENT',
+ PDO::ERRMODE_WARNING => 'WARNING',
+ PDO::ERRMODE_EXCEPTION => 'EXCEPTION',
+ ),
+ 'TIMEOUT',
+ 'PREFETCH',
+ 'AUTOCOMMIT',
+ 'PERSISTENT',
+ 'DRIVER_NAME',
+ 'SERVER_INFO',
+ 'ORACLE_NULLS' => array(
+ PDO::NULL_NATURAL => 'NATURAL',
+ PDO::NULL_EMPTY_STRING => 'EMPTY_STRING',
+ PDO::NULL_TO_STRING => 'TO_STRING',
+ ),
+ 'CLIENT_VERSION',
+ 'SERVER_VERSION',
+ 'STATEMENT_CLASS',
+ 'EMULATE_PREPARES',
+ 'CONNECTION_STATUS',
+ 'STRINGIFY_FETCHES',
+ 'DEFAULT_FETCH_MODE' => array(
+ PDO::FETCH_ASSOC => 'ASSOC',
+ PDO::FETCH_BOTH => 'BOTH',
+ PDO::FETCH_LAZY => 'LAZY',
+ PDO::FETCH_NUM => 'NUM',
+ PDO::FETCH_OBJ => 'OBJ',
+ ),
+ );
+
+ static function castPdo(PDO $c, array $a)
+ {
+ $a = array();
+ $errmode = $c->getAttribute(PDO::ATTR_ERRMODE);
+ $c->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ foreach (self::$pdoAttributes as $attr => $values)
+ {
+ if (! isset($attr[0]))
+ {
+ $attr = $values;
+ $values = array();
+ }
+
+ try
+ {
+ $a[$attr] = 'ERRMODE' === $attr ? $errmode : $c->getAttribute(constant("PDO::ATTR_{$attr}"));
+ if (isset($values[$a[$attr]])) $a[$attr] = $values[$a[$attr]];
+ }
+ catch (\Exception $m)
+ {
+ }
+ }
+
+ $m = "\0~\0";
+
+ $a = (array) $c + array(
+ $m . 'inTransaction' => method_exists($c, 'inTransaction'),
+ $m . 'errorInfo' => $c->errorInfo(),
+ $m . 'attributes' => $a,
+ );
+
+ if ($a[$m . 'inTransaction']) $a[$m . 'inTransaction'] = $c->inTransaction();
+ else unset($a[$m . 'inTransaction']);
+
+ if (! isset($a[$m . 'errorInfo'][1], $a[$m . 'errorInfo'][2])) unset($a[$m . 'errorInfo']);
+
+ $c->setAttribute(PDO::ATTR_ERRMODE, $errmode);
+
+ return $a;
+ }
+
+ static function castPdoStatement(PDOStatement $c, array $a)
+ {
+ $m = "\0~\0";
+
+ $a[$m . 'errorInfo'] = $c->errorInfo();
+ if (! isset($a[$m . 'errorInfo'][1], $a[$m . 'errorInfo'][2])) unset($a[$m . 'errorInfo']);
+
+ return $a;
+ }
+}
View
16 core/logger/class/Patchwork/PHP/InDepthErrorHandler.php
@@ -157,17 +157,17 @@ static function stackErrors()
/**
* Unstacks stacked errors and forwards them for logging.
*/
- static function unstackErrors($ret = null)
+ static function unstackErrors()
{
$e = array_pop(self::$stackedErrorLevels);
if (isset($e)) error_reporting($e);
- if (!empty(self::$stackedErrorLevels)) return $ret;
- if (empty(self::$stackedErrors)) return $ret;
- $e = self::$stackedErrors;
- self::$stackedErrors = array();
- $l = self::$handler->getLogger();
- foreach ($e as $e) $l->logError($e[0], $e[1], $e[2], $e[3]);
- return $ret;
+ if (empty(self::$stackedErrorLevels) && ! empty(self::$stackedErrors))
+ {
+ $e = self::$stackedErrors;
+ self::$stackedErrors = array();
+ $l = self::$handler->getLogger();
+ foreach ($e as $e) $l->logError($e[0], $e[1], $e[2], $e[3]);
+ }
}
/**
View
60 core/logger/class/Patchwork/PHP/JsonDumper.php
@@ -1,6 +1,6 @@
<?php // vi: set fenc=utf-8 ts=4 sw=4 et:
/*
- * Copyright (C) 2012 Nicolas Grekas - p@tchwork.com
+ * Copyright (C) 2014 Nicolas Grekas - p@tchwork.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the (at your option):
@@ -21,46 +21,6 @@ class JsonDumper extends Dumper
$maxString = 100000;
- protected
-
- $line = '',
- $lastHash = 0;
-
- protected static
-
- $lines = array();
-
- static function dump(&$a)
- {
- $d = new self;
- $d->setCallback('line', array(__CLASS__, 'echoLine'));
- $d->walk($a);
- }
-
- static function get($a)
- {
- $d = new self;
- $d->setCallback('line', array(__CLASS__, 'stackLine'));
- $d->walk($a);
- $d = implode("\n", self::$lines);
- self::$lines = array();
- return $d;
- }
-
-
- function walk(&$a)
- {
- $this->line = '';
- $this->lastHash = 0;
- parent::walk($a);
- '' !== $this->line && $this->dumpLine(0);
- }
-
- protected function dumpLine($depth_offset)
- {
- call_user_func($this->callbacks['line'], $this->line, $this->depth + $depth_offset);
- $this->line = '';
- }
protected function dumpRef($is_soft, $ref_counter = null, &$ref_value = null, $ref_type = null)
{
@@ -141,11 +101,11 @@ protected function walkHash($type, &$a, $len)
if ('array:0' === $type) $this->line .= '[]';
else
{
- $h = $this->lastHash;
$this->line .= '{"_":';
- $this->lastHash = $this->counter;
$this->dumpString($this->counter . ':' . $type, false);
+ $startCounter = $this->counter;
+
if ($type = parent::walkHash($type, $a, $len))
{
++$this->depth;
@@ -155,21 +115,9 @@ protected function walkHash($type, &$a, $len)
--$this->depth;
}
- if ($this->counter !== $this->lastHash) $this->dumpLine(1);
+ if ($this->counter !== $startCounter) $this->dumpLine(1);
- $this->lastHash = $h;
$this->line .= '}';
}
}
-
-
- protected static function echoLine($line, $depth)
- {
- echo str_repeat(' ', $depth), $line, "\n";
- }
-
- protected static function stackLine($line, $depth)
- {
- self::$lines[] = str_repeat(' ', $depth) . $line;
- }
}
View
116 core/logger/class/Patchwork/PHP/Logger.php
@@ -10,6 +10,8 @@
namespace Patchwork\PHP;
+use Patchwork\PHP\Dumper\ExceptionCaster;
+
/**
* Logger logs messages to an output stream.
*
@@ -21,8 +23,6 @@
*/
class Logger
{
- const META_PREFIX = "\0~\0";
-
public
$lineFormat = "%s",
@@ -36,26 +36,6 @@ class Logger
$startTime = 0,
$isFirstEvent = true;
- public static
-
- $errorTypes = array(
- E_DEPRECATED => 'E_DEPRECATED',
- E_USER_DEPRECATED => 'E_USER_DEPRECATED',
- E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR',
- E_ERROR => 'E_ERROR',
- E_WARNING => 'E_WARNING',
- E_PARSE => 'E_PARSE',
- E_NOTICE => 'E_NOTICE',
- E_CORE_ERROR => 'E_CORE_ERROR',
- E_CORE_WARNING => 'E_CORE_WARNING',
- E_COMPILE_ERROR => 'E_COMPILE_ERROR',
- E_COMPILE_WARNING => 'E_COMPILE_WARNING',
- E_USER_ERROR => 'E_USER_ERROR',
- E_USER_WARNING => 'E_USER_WARNING',
- E_USER_NOTICE => 'E_USER_NOTICE',
- E_STRICT => 'E_STRICT',
- );
-
function __construct($log_stream, $start_time = 0)
{
@@ -99,100 +79,54 @@ function logError($e, $trace_offset = -1, $trace_args = 0, $log_time = 0)
{
$e = array(
'mesg' => $e['message'],
- 'type' => self::$errorTypes[$e['type']] . ' ' . $e['file'] . ':' . $e['line'],
+ 'type' => ExceptionCaster::$errorTypes[$e['type']] . ' ' . $e['file'] . ':' . $e['line'],
) + $e;
unset($e['message'], $e['file'], $e['line']);
if (0 > $trace_offset) unset($e['trace']);
- else if (!empty($e['trace'])) $this->filterTrace($e['trace'], $trace_offset, $trace_args);
+ else if (!empty($e['trace'])) ExceptionCaster::filterTrace($e['trace'], $trace_offset, $trace_args);
$this->log('php-error', $e, $log_time);
}
- function castException($e)
+ function castException(\Exception $e, array $a)
{
- $a = (array) $e;
-
- $trace = $a["\0Exception\0trace"];
- unset($a["\0Exception\0trace"]); // Ensures the trace is always last
+ $trace = $e->getTrace();
- if (isset($trace[0]))
+ if (isset($trace[0][$this->uniqId]))
{
- if (isset($trace[0][$this->uniqId]))
- {
- $a["\0Exception\0trace"] = array('seeHash' => spl_object_hash($e));
- }
- else
- {
- static $traceProp;
-
- if (! isset($traceProp))
- {
- $traceProp = new \ReflectionProperty('Exception', 'trace');
- $traceProp->setAccessible(true);
- }
-
- $trace[0][$this->uniqId] = 1;
- $traceProp->setValue($e, $trace);
-
- $this->filterTrace($trace, $e instanceof InDepthRecoverableErrorException ? $e->traceOffset : 0, 1);
-
- if (isset($trace)) $a["\0Exception\0trace"] = $trace;
-
- $a[self::META_PREFIX . 'hash'] = spl_object_hash($e);
- }
+ $a["\0Exception\0trace"] = array();
+ $a = ExceptionCaster::castException($e, $a);
+ $a["\0Exception\0trace"] = array('seeHash' => spl_object_hash($e));
}
-
- if ($e instanceof InDepthRecoverableErrorException)
+ else if (isset($trace[0]))
{
- unset($a['traceOffset']);
+ static $traceProp;
- if (null === $a['context']) unset($a['context']);
- else if (isset($a["\0Exception\0trace"]['seeHash']))
+ if (! isset($traceProp))
{
- $a['context'] = $a["\0Exception\0trace"];
+ $traceProp = new \ReflectionProperty('Exception', 'trace');
+ $traceProp->setAccessible(true);
}
- }
-
- if (empty($a["\0Exception\0previous"])) unset($a["\0Exception\0previous"]);
- if ($e instanceof \ErrorException && isset(self::$errorTypes[$a["\0*\0severity"]])) $a["\0*\0severity"] = self::$errorTypes[$a["\0*\0severity"]];
- unset($a["\0Exception\0string"], $a['xdebug_message'], $a['__destructorException']);
-
- return $a;
- }
-
- function filterTrace(&$trace, $offset, $args)
- {
- if (0 > $offset || empty($trace[$offset])) return $trace = null;
- $t = $trace[$offset];
+ $trace[0][$this->uniqId] = 1;
+ $traceProp->setValue($e, $trace);
- if (empty($t['class']) && isset($t['function']))
- if ('user_error' === $t['function'] || 'trigger_error' === $t['function'])
- ++$offset;
-
- $offset && array_splice($trace, 0, $offset);
-
- foreach ($trace as &$t)
- {
- $offset = (isset($t['class']) ? $t['class'] . $t['type'] : '')
- . $t['function'] . '()'
- . (isset($t['line']) ? " {$t['file']}:{$t['line']}" : '');
-
- if (! isset($t['args']) || ! $args) $t = array();
- else $t = array('args' => $t['args']);
-
- $t = array('call' => $offset) + $t;
+ $a = ExceptionCaster::castException($e, $a);
+ $a["\0~\0hash"] = spl_object_hash($e);
}
+
+ return $a;
}
function writeEvent($type, $data)
{
fprintf($this->logStream, $this->lineFormat . PHP_EOL, "*** {$type} ***");
- $d = new JsonDumper;
- $d->setCallback('line', array($this, 'writeLine'));
- $d->setCallback('o:exception', array($this, 'castException'));
+ $d = JsonDumper::$defaultCasters;
+ $d['o:Exception'] = array($this, 'castException');
+ $d = new JsonDumper($d);
+ $d->setLineDumper(array($this, 'writeLine'));
$d->walk($data);
fprintf($this->logStream, $this->lineFormat . PHP_EOL, '***');
View
3 core/logger/composer.json
@@ -16,6 +16,9 @@
"php": ">=5.3.0"
},
"autoload": {
+ "files": [
+ "bootup.logger.php"
+ ],
"psr-0": {
"Patchwork": "class/"
}
View
30 core/logger/tests/Patchwork/Tests/PHP/JsonDumperTest.php
@@ -32,6 +32,9 @@ function testGet()
$v['snobj'] =& $v['nobj'][0];
$v['snobj2'] = $v['nobj'][0];
+ $json = new JsonDumper;
+ $json = $json->walk($v);
+
$this->assertSame(
'{"_":"1:array:23",
"number": 1,
@@ -59,27 +62,22 @@ function testGet()
"8": {"_":"23:resource:Unknown"},
"obj": {"_":"24:stdClass"},
"closure": {"_":"25:Closure",
- "~:args": {"_":"26:array:2",
- "0": "$a",
- "PDO &$b": null
- },
- "~:file": "' . __FILE__ . '",
- "~:lines": "' . $v['line'] . '-' . $v['line'] . '"
+ "~:reflection": "Closure [ <user> public method Patchwork\\\\Tests\\\\PHP\\\\{closure} ] {\n @@ ' . __FILE__ . ' 22 - 22\n\n - Parameters [2] {\n Parameter #0 [ <required> $a ]\n Parameter #1 [ <optional> PDO or NULL &$b = NULL ]\n }\n}\n"
},
"line": ' . $v['line'] . ',
- "nobj": {"_":"32:array:1",
- "0": "r`33:33"
+ "nobj": {"_":"28:array:1",
+ "0": "r`29:29"
},
- "recurs": {"_":"34:array:1",
- "0": "R`35:34"
+ "recurs": {"_":"30:array:1",
+ "0": "R`31:30"
},
- "9": "R`36:",
- "sobj": "r`37:24",
- "snobj": {"_":"38:stdClass"},
- "snobj2": "r`39:33",
- "__refs": {"3":[-36],"34":[-35],"24":[37],"33":[-38,39]}
+ "9": "R`32:",
+ "sobj": "r`33:24",
+ "snobj": {"_":"34:stdClass"},
+ "snobj2": "r`35:29",
+ "__refs": {"3":[-32],"30":[-31],"24":[33],"29":[-34,35]}
}',
- JsonDumper::get($v)
+ $json
);
}
}
View
6 core/logger/tests/bootstrap.php
@@ -4,7 +4,11 @@
require_once $dir . '/class/Patchwork/PHP/Walker.php';
require_once $dir . '/class/Patchwork/PHP/Dumper.php';
-require_once $dir . '/class/Patchwork/PHP/Dumper/Caster.php';
+require_once $dir . '/class/Patchwork/PHP/Dumper/BaseCaster.php';
+require_once $dir . '/class/Patchwork/PHP/Dumper/ExceptionCaster.php';
+require_once $dir . '/class/Patchwork/PHP/Dumper/PdoCaster.php';
+require_once $dir . '/class/Patchwork/PHP/Dumper/DoctrineCaster.php';
+require_once $dir . '/class/Patchwork/PHP/CliDumper.php';
require_once $dir . '/class/Patchwork/PHP/JsonDumper.php';
require_once $dir . '/class/Patchwork/PHP/Logger.php';
require_once $dir . '/class/Patchwork/PHP/ThrowingErrorHandler.php';

0 comments on commit 62ec835

Please sign in to comment.