Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of the Symfony package.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) Fabien Potencier <fabien@symfony.com>
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Symfony\Component\VarDumper\Dumper;
|
Chris@0
|
13
|
Chris@0
|
14 use Symfony\Component\VarDumper\Cloner\Data;
|
Chris@0
|
15 use Symfony\Component\VarDumper\Cloner\DumperInterface;
|
Chris@0
|
16
|
Chris@0
|
17 /**
|
Chris@0
|
18 * Abstract mechanism for dumping a Data object.
|
Chris@0
|
19 *
|
Chris@0
|
20 * @author Nicolas Grekas <p@tchwork.com>
|
Chris@0
|
21 */
|
Chris@0
|
22 abstract class AbstractDumper implements DataDumperInterface, DumperInterface
|
Chris@0
|
23 {
|
Chris@0
|
24 const DUMP_LIGHT_ARRAY = 1;
|
Chris@0
|
25 const DUMP_STRING_LENGTH = 2;
|
Chris@0
|
26 const DUMP_COMMA_SEPARATOR = 4;
|
Chris@0
|
27 const DUMP_TRAILING_COMMA = 8;
|
Chris@0
|
28
|
Chris@0
|
29 public static $defaultOutput = 'php://output';
|
Chris@0
|
30
|
Chris@0
|
31 protected $line = '';
|
Chris@0
|
32 protected $lineDumper;
|
Chris@0
|
33 protected $outputStream;
|
Chris@0
|
34 protected $decimalPoint; // This is locale dependent
|
Chris@0
|
35 protected $indentPad = ' ';
|
Chris@0
|
36 protected $flags;
|
Chris@0
|
37
|
Chris@0
|
38 private $charset;
|
Chris@0
|
39
|
Chris@0
|
40 /**
|
Chris@0
|
41 * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput
|
Chris@18
|
42 * @param string|null $charset The default character encoding to use for non-UTF8 strings
|
Chris@0
|
43 * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation
|
Chris@0
|
44 */
|
Chris@0
|
45 public function __construct($output = null, $charset = null, $flags = 0)
|
Chris@0
|
46 {
|
Chris@0
|
47 $this->flags = (int) $flags;
|
Chris@0
|
48 $this->setCharset($charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8');
|
Chris@0
|
49 $this->decimalPoint = localeconv();
|
Chris@0
|
50 $this->decimalPoint = $this->decimalPoint['decimal_point'];
|
Chris@0
|
51 $this->setOutput($output ?: static::$defaultOutput);
|
Chris@17
|
52 if (!$output && \is_string(static::$defaultOutput)) {
|
Chris@0
|
53 static::$defaultOutput = $this->outputStream;
|
Chris@0
|
54 }
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 /**
|
Chris@0
|
58 * Sets the output destination of the dumps.
|
Chris@0
|
59 *
|
Chris@0
|
60 * @param callable|resource|string $output A line dumper callable, an opened stream or an output path
|
Chris@0
|
61 *
|
Chris@0
|
62 * @return callable|resource|string The previous output destination
|
Chris@0
|
63 */
|
Chris@0
|
64 public function setOutput($output)
|
Chris@0
|
65 {
|
Chris@0
|
66 $prev = null !== $this->outputStream ? $this->outputStream : $this->lineDumper;
|
Chris@0
|
67
|
Chris@17
|
68 if (\is_callable($output)) {
|
Chris@0
|
69 $this->outputStream = null;
|
Chris@0
|
70 $this->lineDumper = $output;
|
Chris@0
|
71 } else {
|
Chris@17
|
72 if (\is_string($output)) {
|
Chris@0
|
73 $output = fopen($output, 'wb');
|
Chris@0
|
74 }
|
Chris@0
|
75 $this->outputStream = $output;
|
Chris@17
|
76 $this->lineDumper = [$this, 'echoLine'];
|
Chris@0
|
77 }
|
Chris@0
|
78
|
Chris@0
|
79 return $prev;
|
Chris@0
|
80 }
|
Chris@0
|
81
|
Chris@0
|
82 /**
|
Chris@0
|
83 * Sets the default character encoding to use for non-UTF8 strings.
|
Chris@0
|
84 *
|
Chris@0
|
85 * @param string $charset The default character encoding to use for non-UTF8 strings
|
Chris@0
|
86 *
|
Chris@0
|
87 * @return string The previous charset
|
Chris@0
|
88 */
|
Chris@0
|
89 public function setCharset($charset)
|
Chris@0
|
90 {
|
Chris@0
|
91 $prev = $this->charset;
|
Chris@0
|
92
|
Chris@0
|
93 $charset = strtoupper($charset);
|
Chris@0
|
94 $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset;
|
Chris@0
|
95
|
Chris@0
|
96 $this->charset = $charset;
|
Chris@0
|
97
|
Chris@0
|
98 return $prev;
|
Chris@0
|
99 }
|
Chris@0
|
100
|
Chris@0
|
101 /**
|
Chris@0
|
102 * Sets the indentation pad string.
|
Chris@0
|
103 *
|
Chris@12
|
104 * @param string $pad A string that will be prepended to dumped lines, repeated by nesting level
|
Chris@0
|
105 *
|
Chris@12
|
106 * @return string The previous indent pad
|
Chris@0
|
107 */
|
Chris@0
|
108 public function setIndentPad($pad)
|
Chris@0
|
109 {
|
Chris@0
|
110 $prev = $this->indentPad;
|
Chris@0
|
111 $this->indentPad = $pad;
|
Chris@0
|
112
|
Chris@0
|
113 return $prev;
|
Chris@0
|
114 }
|
Chris@0
|
115
|
Chris@0
|
116 /**
|
Chris@0
|
117 * Dumps a Data object.
|
Chris@0
|
118 *
|
Chris@0
|
119 * @param Data $data A Data object
|
Chris@0
|
120 * @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
|
121 *
|
Chris@0
|
122 * @return string|null The dump as string when $output is true
|
Chris@0
|
123 */
|
Chris@0
|
124 public function dump(Data $data, $output = null)
|
Chris@0
|
125 {
|
Chris@0
|
126 $this->decimalPoint = localeconv();
|
Chris@0
|
127 $this->decimalPoint = $this->decimalPoint['decimal_point'];
|
Chris@0
|
128
|
Chris@0
|
129 if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(LC_NUMERIC, 0) : null) {
|
Chris@0
|
130 setlocale(LC_NUMERIC, 'C');
|
Chris@0
|
131 }
|
Chris@0
|
132
|
Chris@0
|
133 if ($returnDump = true === $output) {
|
Chris@0
|
134 $output = fopen('php://memory', 'r+b');
|
Chris@0
|
135 }
|
Chris@0
|
136 if ($output) {
|
Chris@0
|
137 $prevOutput = $this->setOutput($output);
|
Chris@0
|
138 }
|
Chris@0
|
139 try {
|
Chris@0
|
140 $data->dump($this);
|
Chris@0
|
141 $this->dumpLine(-1);
|
Chris@0
|
142
|
Chris@0
|
143 if ($returnDump) {
|
Chris@0
|
144 $result = stream_get_contents($output, -1, 0);
|
Chris@0
|
145 fclose($output);
|
Chris@0
|
146
|
Chris@0
|
147 return $result;
|
Chris@0
|
148 }
|
Chris@0
|
149 } finally {
|
Chris@0
|
150 if ($output) {
|
Chris@0
|
151 $this->setOutput($prevOutput);
|
Chris@0
|
152 }
|
Chris@0
|
153 if ($locale) {
|
Chris@0
|
154 setlocale(LC_NUMERIC, $locale);
|
Chris@0
|
155 }
|
Chris@0
|
156 }
|
Chris@0
|
157 }
|
Chris@0
|
158
|
Chris@0
|
159 /**
|
Chris@0
|
160 * Dumps the current line.
|
Chris@0
|
161 *
|
Chris@0
|
162 * @param int $depth The recursive depth in the dumped structure for the line being dumped,
|
Chris@0
|
163 * or -1 to signal the end-of-dump to the line dumper callable
|
Chris@0
|
164 */
|
Chris@0
|
165 protected function dumpLine($depth)
|
Chris@0
|
166 {
|
Chris@17
|
167 \call_user_func($this->lineDumper, $this->line, $depth, $this->indentPad);
|
Chris@0
|
168 $this->line = '';
|
Chris@0
|
169 }
|
Chris@0
|
170
|
Chris@0
|
171 /**
|
Chris@0
|
172 * Generic line dumper callback.
|
Chris@0
|
173 *
|
Chris@0
|
174 * @param string $line The line to write
|
Chris@0
|
175 * @param int $depth The recursive depth in the dumped structure
|
Chris@0
|
176 * @param string $indentPad The line indent pad
|
Chris@0
|
177 */
|
Chris@0
|
178 protected function echoLine($line, $depth, $indentPad)
|
Chris@0
|
179 {
|
Chris@0
|
180 if (-1 !== $depth) {
|
Chris@0
|
181 fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n");
|
Chris@0
|
182 }
|
Chris@0
|
183 }
|
Chris@0
|
184
|
Chris@0
|
185 /**
|
Chris@0
|
186 * Converts a non-UTF-8 string to UTF-8.
|
Chris@0
|
187 *
|
Chris@0
|
188 * @param string $s The non-UTF-8 string to convert
|
Chris@0
|
189 *
|
Chris@0
|
190 * @return string The string converted to UTF-8
|
Chris@0
|
191 */
|
Chris@0
|
192 protected function utf8Encode($s)
|
Chris@0
|
193 {
|
Chris@0
|
194 if (preg_match('//u', $s)) {
|
Chris@0
|
195 return $s;
|
Chris@0
|
196 }
|
Chris@0
|
197
|
Chris@17
|
198 if (!\function_exists('iconv')) {
|
Chris@0
|
199 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
|
200 }
|
Chris@0
|
201
|
Chris@0
|
202 if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) {
|
Chris@0
|
203 return $c;
|
Chris@0
|
204 }
|
Chris@0
|
205 if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) {
|
Chris@0
|
206 return $c;
|
Chris@0
|
207 }
|
Chris@0
|
208
|
Chris@0
|
209 return iconv('CP850', 'UTF-8', $s);
|
Chris@0
|
210 }
|
Chris@0
|
211 }
|