Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\VarDumper\Dumper; Chris@0: Chris@0: use Symfony\Component\VarDumper\Cloner\Data; Chris@0: use Symfony\Component\VarDumper\Cloner\DumperInterface; Chris@0: Chris@0: /** Chris@0: * Abstract mechanism for dumping a Data object. Chris@0: * Chris@0: * @author Nicolas Grekas
Chris@0: */ Chris@0: abstract class AbstractDumper implements DataDumperInterface, DumperInterface Chris@0: { Chris@0: const DUMP_LIGHT_ARRAY = 1; Chris@0: const DUMP_STRING_LENGTH = 2; Chris@0: const DUMP_COMMA_SEPARATOR = 4; Chris@0: const DUMP_TRAILING_COMMA = 8; Chris@0: Chris@0: public static $defaultOutput = 'php://output'; Chris@0: Chris@0: protected $line = ''; Chris@0: protected $lineDumper; Chris@0: protected $outputStream; Chris@0: protected $decimalPoint; // This is locale dependent Chris@0: protected $indentPad = ' '; Chris@0: protected $flags; Chris@0: Chris@0: private $charset; Chris@0: Chris@0: /** Chris@0: * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput Chris@18: * @param string|null $charset The default character encoding to use for non-UTF8 strings Chris@0: * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation Chris@0: */ Chris@0: public function __construct($output = null, $charset = null, $flags = 0) Chris@0: { Chris@0: $this->flags = (int) $flags; Chris@0: $this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'); Chris@0: $this->decimalPoint = localeconv(); Chris@0: $this->decimalPoint = $this->decimalPoint['decimal_point']; Chris@0: $this->setOutput($output ?: static::$defaultOutput); Chris@17: if (!$output && \is_string(static::$defaultOutput)) { Chris@0: static::$defaultOutput = $this->outputStream; Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the output destination of the dumps. Chris@0: * Chris@0: * @param callable|resource|string $output A line dumper callable, an opened stream or an output path Chris@0: * Chris@0: * @return callable|resource|string The previous output destination Chris@0: */ Chris@0: public function setOutput($output) Chris@0: { Chris@0: $prev = null !== $this->outputStream ? $this->outputStream : $this->lineDumper; Chris@0: Chris@17: if (\is_callable($output)) { Chris@0: $this->outputStream = null; Chris@0: $this->lineDumper = $output; Chris@0: } else { Chris@17: if (\is_string($output)) { Chris@0: $output = fopen($output, 'wb'); Chris@0: } Chris@0: $this->outputStream = $output; Chris@17: $this->lineDumper = [$this, 'echoLine']; Chris@0: } Chris@0: Chris@0: return $prev; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the default character encoding to use for non-UTF8 strings. Chris@0: * Chris@0: * @param string $charset The default character encoding to use for non-UTF8 strings Chris@0: * Chris@0: * @return string The previous charset Chris@0: */ Chris@0: public function setCharset($charset) Chris@0: { Chris@0: $prev = $this->charset; Chris@0: Chris@0: $charset = strtoupper($charset); Chris@0: $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; Chris@0: Chris@0: $this->charset = $charset; Chris@0: Chris@0: return $prev; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Sets the indentation pad string. Chris@0: * Chris@12: * @param string $pad A string that will be prepended to dumped lines, repeated by nesting level Chris@0: * Chris@12: * @return string The previous indent pad Chris@0: */ Chris@0: public function setIndentPad($pad) Chris@0: { Chris@0: $prev = $this->indentPad; Chris@0: $this->indentPad = $pad; Chris@0: Chris@0: return $prev; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Dumps a Data object. Chris@0: * Chris@0: * @param Data $data A Data object Chris@0: * @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump Chris@0: * Chris@0: * @return string|null The dump as string when $output is true Chris@0: */ Chris@0: public function dump(Data $data, $output = null) Chris@0: { Chris@0: $this->decimalPoint = localeconv(); Chris@0: $this->decimalPoint = $this->decimalPoint['decimal_point']; Chris@0: Chris@0: if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(LC_NUMERIC, 0) : null) { Chris@0: setlocale(LC_NUMERIC, 'C'); Chris@0: } Chris@0: Chris@0: if ($returnDump = true === $output) { Chris@0: $output = fopen('php://memory', 'r+b'); Chris@0: } Chris@0: if ($output) { Chris@0: $prevOutput = $this->setOutput($output); Chris@0: } Chris@0: try { Chris@0: $data->dump($this); Chris@0: $this->dumpLine(-1); Chris@0: Chris@0: if ($returnDump) { Chris@0: $result = stream_get_contents($output, -1, 0); Chris@0: fclose($output); Chris@0: Chris@0: return $result; Chris@0: } Chris@0: } finally { Chris@0: if ($output) { Chris@0: $this->setOutput($prevOutput); Chris@0: } Chris@0: if ($locale) { Chris@0: setlocale(LC_NUMERIC, $locale); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Dumps the current line. Chris@0: * Chris@0: * @param int $depth The recursive depth in the dumped structure for the line being dumped, Chris@0: * or -1 to signal the end-of-dump to the line dumper callable Chris@0: */ Chris@0: protected function dumpLine($depth) Chris@0: { Chris@17: \call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad); Chris@0: $this->line = ''; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Generic line dumper callback. Chris@0: * Chris@0: * @param string $line The line to write Chris@0: * @param int $depth The recursive depth in the dumped structure Chris@0: * @param string $indentPad The line indent pad Chris@0: */ Chris@0: protected function echoLine($line, $depth, $indentPad) Chris@0: { Chris@0: if (-1 !== $depth) { Chris@0: fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n"); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Converts a non-UTF-8 string to UTF-8. Chris@0: * Chris@0: * @param string $s The non-UTF-8 string to convert Chris@0: * Chris@0: * @return string The string converted to UTF-8 Chris@0: */ Chris@0: protected function utf8Encode($s) Chris@0: { Chris@0: if (preg_match('//u', $s)) { Chris@0: return $s; Chris@0: } Chris@0: Chris@17: if (!\function_exists('iconv')) { Chris@0: throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); Chris@0: } Chris@0: Chris@0: if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { Chris@0: return $c; Chris@0: } Chris@0: if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { Chris@0: return $c; Chris@0: } Chris@0: Chris@0: return iconv('CP850', 'UTF-8', $s); Chris@0: } Chris@0: }