20
20
*/
21
21
abstract class AbstractCloner implements ClonerInterface
22
22
{
23
- protected $ maxItems = 2500 ;
23
+ public static $ defaultCasters = array (
24
+ 'o:Closure ' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castClosure ' ,
25
+ 'o:Reflector ' => 'Symfony\Component\VarDumper\Caster\ReflectionCaster::castReflector ' ,
26
+
27
+ 'r:curl ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castCurl ' ,
28
+ 'r:dba ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba ' ,
29
+ 'r:dba persistent ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castDba ' ,
30
+ 'r:gd ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castGd ' ,
31
+ 'r:mysql link ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castMysqlLink ' ,
32
+ 'r:process ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castProcess ' ,
33
+ 'r:stream ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStream ' ,
34
+ 'r:stream-context ' => 'Symfony\Component\VarDumper\Caster\ResourceCaster::castStreamContext ' ,
35
+ );
36
+
37
+ protected $ maxItems = 250 ;
24
38
protected $ maxString = -1 ;
25
39
40
+ private $ casters = array ();
26
41
private $ data = array (array (null ));
27
42
private $ prevErrorHandler ;
43
+ private $ classInfo = array ();
44
+
45
+ /**
46
+ * @param callable[]|null $casters A map of casters.
47
+ *
48
+ * @see addCasters
49
+ */
50
+ public function __construct (array $ casters = null )
51
+ {
52
+ if (null === $ casters ) {
53
+ $ casters = static ::$ defaultCasters ;
54
+ }
55
+ $ this ->addCasters ($ casters );
56
+ }
57
+
58
+ /**
59
+ * Adds casters for resources and objects.
60
+ *
61
+ * Maps resources or objects types to a callback.
62
+ * Types are in the key, with a callable caster for value.
63
+ * Objects class are to be prefixed with a `o:`,
64
+ * resources type are to be prefixed with a `r:`,
65
+ * see e.g. static::$defaultCasters.
66
+ *
67
+ * @param callable[] $casters A map of casters.
68
+ */
69
+ public function addCasters (array $ casters )
70
+ {
71
+ foreach ($ casters as $ type => $ callback ) {
72
+ $ this ->casters [strtolower ($ type )][] = $ callback ;
73
+ }
74
+ }
28
75
29
76
/**
30
77
* Sets the maximum number of items to clone past the first level in nested structures.
@@ -81,36 +128,71 @@ abstract protected function doClone($var);
81
128
/**
82
129
* Casts an object to an array representation.
83
130
*
84
- * @param string $class The class of the object.
85
- * @param object $obj The object itself.
131
+ * @param string $class The class of the object.
132
+ * @param object $obj The object itself.
133
+ * @param bool $isNested True if the object is nested in the dumped structure.
134
+ * @param int &$cut After the cast, number of items removed from $obj.
86
135
*
87
136
* @return array The object casted as array.
88
137
*/
89
- protected function castObject ($ class , $ obj )
138
+ protected function castObject ($ class , $ obj, $ isNested , & $ cut )
90
139
{
91
- if (method_exists ($ obj , '__debugInfo ' )) {
92
- if (!$ a = $ this ->callCaster (array ($ this , '__debugInfo ' ), $ obj , array ())) {
93
- $ a = (array ) $ obj ;
94
- }
140
+ if (isset ($ this ->classInfo [$ class ])) {
141
+ $ classInfo = $ this ->classInfo [$ class ];
142
+ } else {
143
+ $ classInfo = array (
144
+ method_exists ($ class , '__debugInfo ' ),
145
+ new \ReflectionClass ($ class ),
146
+ array_reverse (array ($ class => $ class ) + class_parents ($ class ) + class_implements ($ class ) + array ('* ' => '* ' )),
147
+ );
148
+
149
+ $ this ->classInfo [$ class ] = $ classInfo ;
150
+ }
151
+
152
+ if ($ classInfo [0 ]) {
153
+ $ a = $ this ->callCaster (array ($ obj , '__debugInfo ' ), $ obj , array (), $ isNested );
95
154
} else {
96
155
$ a = (array ) $ obj ;
97
156
}
157
+ $ cut = 0 ;
158
+
159
+ foreach ($ a as $ k => $ p ) {
160
+ if (!isset ($ k [0 ]) || ("\0" !== $ k [0 ] && !$ classInfo [1 ]->hasProperty ($ k ))) {
161
+ unset($ a [$ k ]);
162
+ $ a ["\0+ \0" .$ k ] = $ p ;
163
+ }
164
+ }
165
+
166
+ foreach ($ classInfo [2 ] as $ p ) {
167
+ if (!empty ($ this ->casters [$ p = 'o: ' .strtolower ($ p )])) {
168
+ foreach ($ this ->casters [$ p ] as $ p ) {
169
+ $ a = $ this ->callCaster ($ p , $ obj , $ a , $ isNested , $ cut );
170
+ }
171
+ }
172
+ }
98
173
99
174
return $ a ;
100
175
}
101
176
102
177
/**
103
178
* Casts a resource to an array representation.
104
179
*
105
- * @param string $type The type of the resource.
106
- * @param resource $res The resource.
180
+ * @param string $type The type of the resource.
181
+ * @param resource $res The resource.
182
+ * @param bool $isNested True if the object is nested in the dumped structure.
107
183
*
108
184
* @return array The resource casted as array.
109
185
*/
110
- protected function castResource ($ type , $ res )
186
+ protected function castResource ($ type , $ res, $ isNested )
111
187
{
112
188
$ a = array ();
113
189
190
+ if (!empty ($ this ->casters ['r: ' .$ type ])) {
191
+ foreach ($ this ->casters ['r: ' .$ type ] as $ c ) {
192
+ $ a = $ this ->callCaster ($ c , $ res , $ a , $ isNested );
193
+ }
194
+ }
195
+
114
196
return $ a ;
115
197
}
116
198
@@ -120,14 +202,15 @@ protected function castResource($type, $res)
120
202
* @param callable $callback The caster.
121
203
* @param object|resource $obj The object/resource being casted.
122
204
* @param array $a The result of the previous cast for chained casters.
205
+ * @param bool $isNested True if $obj is nested in the dumped structure.
206
+ * @param int &$cut After the cast, number of items removed from $obj.
123
207
*
124
208
* @return array The casted object/resource.
125
209
*/
126
- private function callCaster ($ callback , $ obj , $ a )
210
+ private function callCaster ($ callback , $ obj , $ a, $ isNested , & $ cut = 0 )
127
211
{
128
212
try {
129
- // Ignore invalid $callback
130
- $ cast = @call_user_func ($ callback , $ obj , $ a );
213
+ $ cast = call_user_func_array ($ callback , array ($ obj , $ a , $ isNested , &$ cut ));
131
214
132
215
if (is_array ($ cast )) {
133
216
$ a = $ cast ;
0 commit comments