Line # | Frequency | Source Line |
1 | | <?php |
2 | | /** |
3 | | * base include file for SimpleTest |
4 | | * @package SimpleTest |
5 | | * @subpackage UnitTester |
6 | | * @version $Id: dumper.php 1672 2008-03-02 04:47:34Z edwardzyang $ |
7 | | */ |
8 | | /** |
9 | | * does type matter |
10 | | */ |
11 | | if (! defined('TYPE_MATTERS')) { |
12 | | define('TYPE_MATTERS', true); |
13 | | } |
14 | | |
15 | | /** |
16 | | * Displays variables as text and does diffs. |
17 | | * @package SimpleTest |
18 | | * @subpackage UnitTester |
19 | | */ |
20 | | class SimpleDumper { |
21 | | |
22 | | /** |
23 | | * Renders a variable in a shorter form than print_r(). |
24 | | * @param mixed $value Variable to render as a string. |
25 | | * @return string Human readable string form. |
26 | | * @access public |
27 | | */ |
28 | | function describeValue($value) { |
29 | 1 | $type = $this->getType($value); |
30 | | switch($type) { |
31 | 1 | case "Null": |
32 | | return "NULL"; |
33 | 1 | case "Boolean": |
34 | 1 | return "Boolean: " . ($value ? "true" : "false"); |
35 | 1 | case "Array": |
36 | | return "Array: " . count($value) . " items"; |
37 | 1 | case "Object": |
38 | 1 | return "Object: of " . get_class($value); |
39 | 1 | case "String": |
40 | 1 | return "String: " . $this->clipString($value, 200); |
41 | 1 | default: |
42 | 1 | return "$type: $value"; |
43 | | } |
44 | | return "Unknown"; |
45 | | } |
46 | | |
47 | | /** |
48 | | * Gets the string representation of a type. |
49 | | * @param mixed $value Variable to check against. |
50 | | * @return string Type. |
51 | | * @access public |
52 | | */ |
53 | | function getType($value) { |
54 | 1 | if (! isset($value)) { |
55 | | return "Null"; |
56 | 1 | } elseif (is_bool($value)) { |
57 | 1 | return "Boolean"; |
58 | 1 | } elseif (is_string($value)) { |
59 | 1 | return "String"; |
60 | 1 | } elseif (is_integer($value)) { |
61 | 1 | return "Integer"; |
62 | 1 | } elseif (is_float($value)) { |
63 | | return "Float"; |
64 | 1 | } elseif (is_array($value)) { |
65 | | return "Array"; |
66 | 1 | } elseif (is_resource($value)) { |
67 | | return "Resource"; |
68 | 1 | } elseif (is_object($value)) { |
69 | 1 | return "Object"; |
70 | | } |
71 | | return "Unknown"; |
72 | | } |
73 | |
|
74 | | /** |
75 | | * Creates a human readable description of the |
76 | | * difference between two variables. Uses a |
77 | | * dynamic call. |
78 | | * @param mixed $first First variable. |
79 | | * @param mixed $second Value to compare with. |
80 | | * @param boolean $identical If true then type anomolies count. |
81 | | * @return string Description of difference. |
82 | | * @access public |
83 | | */ |
84 | | function describeDifference($first, $second, $identical = false) { |
85 | | if ($identical) { |
86 | | if (! $this->_isTypeMatch($first, $second)) { |
87 | | return "with type mismatch as [" . $this->describeValue($first) . |
88 | | "] does not match [" . $this->describeValue($second) . "]"; |
89 | | } |
90 | | } |
91 | | $type = $this->getType($first); |
92 | | if ($type == "Unknown") { |
93 | | return "with unknown type"; |
94 | | } |
95 | | $method = '_describe' . $type . 'Difference'; |
96 | | return $this->$method($first, $second, $identical); |
97 | | } |
98 | | |
99 | | /** |
100 | | * Tests to see if types match. |
101 | | * @param mixed $first First variable. |
102 | | * @param mixed $second Value to compare with. |
103 | | * @return boolean True if matches. |
104 | | * @access private |
105 | | */ |
106 | | function _isTypeMatch($first, $second) { |
107 | | return ($this->getType($first) == $this->getType($second)); |
108 | | } |
109 | |
|
110 | | /** |
111 | | * Clips a string to a maximum length. |
112 | | * @param string $value String to truncate. |
113 | | * @param integer $size Minimum string size to show. |
114 | | * @param integer $position Centre of string section. |
115 | | * @return string Shortened version. |
116 | | * @access public |
117 | | */ |
118 | | function clipString($value, $size, $position = 0) { |
119 | 1 | $length = strlen($value); |
120 | 1 | if ($length <= $size) { |
121 | | return $value; |
122 | | } |
123 | 1 | $position = min($position, $length); |
124 | 1 | $start = ($size/2 > $position ? 0 : $position - $size/2); |
125 | 1 | if ($start + $size > $length) { |
126 | | $start = $length - $size; |
127 | | } |
128 | 1 | $value = substr($value, $start, $size); |
129 | 1 | return ($start > 0 ? "..." : "") . $value . ($start + $size < $length ? "..." : ""); |
130 | | } |
131 | | |
132 | | /** |
133 | | * Creates a human readable description of the |
134 | | * difference between two variables. The minimal |
135 | | * version. |
136 | | * @param null $first First value. |
137 | | * @param mixed $second Value to compare with. |
138 | | * @return string Human readable description. |
139 | | * @access private |
140 | | */ |
141 | | function _describeGenericDifference($first, $second) { |
142 | | return "as [" . $this->describeValue($first) . |
143 | | "] does not match [" . |
144 | | $this->describeValue($second) . "]"; |
145 | | } |
146 | | |
147 | | /** |
148 | | * Creates a human readable description of the |
149 | | * difference between a null and another variable. |
150 | | * @param null $first First null. |
151 | | * @param mixed $second Null to compare with. |
152 | | * @param boolean $identical If true then type anomolies count. |
153 | | * @return string Human readable description. |
154 | | * @access private |
155 | | */ |
156 | | function _describeNullDifference($first, $second, $identical) { |
157 | | return $this->_describeGenericDifference($first, $second); |
158 | | } |
159 | | |
160 | | /** |
161 | | * Creates a human readable description of the |
162 | | * difference between a boolean and another variable. |
163 | | * @param boolean $first First boolean. |
164 | | * @param mixed $second Boolean to compare with. |
165 | | * @param boolean $identical If true then type anomolies count. |
166 | | * @return string Human readable description. |
167 | | * @access private |
168 | | */ |
169 | | function _describeBooleanDifference($first, $second, $identical) { |
170 | | return $this->_describeGenericDifference($first, $second); |
171 | | } |
172 | | |
173 | | /** |
174 | | * Creates a human readable description of the |
175 | | * difference between a string and another variable. |
176 | | * @param string $first First string. |
177 | | * @param mixed $second String to compare with. |
178 | | * @param boolean $identical If true then type anomolies count. |
179 | | * @return string Human readable description. |
180 | | * @access private |
181 | | */ |
182 | | function _describeStringDifference($first, $second, $identical) { |
183 | | if (is_object($second) || is_array($second)) { |
184 | | return $this->_describeGenericDifference($first, $second); |
185 | | } |
186 | | $position = $this->_stringDiffersAt($first, $second); |
187 | | $message = "at character $position"; |
188 | | $message .= " with [" . |
189 | | $this->clipString($first, 200, $position) . "] and [" . |
190 | | $this->clipString($second, 200, $position) . "]"; |
191 | | return $message; |
192 | | } |
193 | | |
194 | | /** |
195 | | * Creates a human readable description of the |
196 | | * difference between an integer and another variable. |
197 | | * @param integer $first First number. |
198 | | * @param mixed $second Number to compare with. |
199 | | * @param boolean $identical If true then type anomolies count. |
200 | | * @return string Human readable description. |
201 | | * @access private |
202 | | */ |
203 | | function _describeIntegerDifference($first, $second, $identical) { |
204 | | if (is_object($second) || is_array($second)) { |
205 | | return $this->_describeGenericDifference($first, $second); |
206 | | } |
207 | | return "because [" . $this->describeValue($first) . |
208 | | "] differs from [" . |
209 | | $this->describeValue($second) . "] by " . |
210 | | abs($first - $second); |
211 | | } |
212 | | |
213 | | /** |
214 | | * Creates a human readable description of the |
215 | | * difference between two floating point numbers. |
216 | | * @param float $first First float. |
217 | | * @param mixed $second Float to compare with. |
218 | | * @param boolean $identical If true then type anomolies count. |
219 | | * @return string Human readable description. |
220 | | * @access private |
221 | | */ |
222 | | function _describeFloatDifference($first, $second, $identical) { |
223 | | if (is_object($second) || is_array($second)) { |
224 | | return $this->_describeGenericDifference($first, $second); |
225 | | } |
226 | | return "because [" . $this->describeValue($first) . |
227 | | "] differs from [" . |
228 | | $this->describeValue($second) . "] by " . |
229 | | abs($first - $second); |
230 | | } |
231 | | |
232 | | /** |
233 | | * Creates a human readable description of the |
234 | | * difference between two arrays. |
235 | | * @param array $first First array. |
236 | | * @param mixed $second Array to compare with. |
237 | | * @param boolean $identical If true then type anomolies count. |
238 | | * @return string Human readable description. |
239 | | * @access private |
240 | | */ |
241 | | function _describeArrayDifference($first, $second, $identical) { |
242 | | if (! is_array($second)) { |
243 | | return $this->_describeGenericDifference($first, $second); |
244 | | } |
245 | | if (! $this->_isMatchingKeys($first, $second, $identical)) { |
246 | | return "as key list [" . |
247 | | implode(", ", array_keys($first)) . "] does not match key list [" . |
248 | | implode(", ", array_keys($second)) . "]"; |
249 | | } |
250 | | foreach (array_keys($first) as $key) { |
251 | | if ($identical && ($first[$key] === $second[$key])) { |
252 | | continue; |
253 | | } |
254 | | if (! $identical && ($first[$key] == $second[$key])) { |
255 | | continue; |
256 | | } |
257 | | return "with member [$key] " . $this->describeDifference( |
258 | | $first[$key], |
259 | | $second[$key], |
260 | | $identical); |
261 | | } |
262 | | return ""; |
263 | | } |
264 | | |
265 | | /** |
266 | | * Compares two arrays to see if their key lists match. |
267 | | * For an identical match, the ordering and types of the keys |
268 | | * is significant. |
269 | | * @param array $first First array. |
270 | | * @param array $second Array to compare with. |
271 | | * @param boolean $identical If true then type anomolies count. |
272 | | * @return boolean True if matching. |
273 | | * @access private |
274 | | */ |
275 | | function _isMatchingKeys($first, $second, $identical) { |
276 | | $first_keys = array_keys($first); |
277 | | $second_keys = array_keys($second); |
278 | | if ($identical) { |
279 | | return ($first_keys === $second_keys); |
280 | | } |
281 | | sort($first_keys); |
282 | | sort($second_keys); |
283 | | return ($first_keys == $second_keys); |
284 | | } |
285 | | |
286 | | /** |
287 | | * Creates a human readable description of the |
288 | | * difference between a resource and another variable. |
289 | | * @param resource $first First resource. |
290 | | * @param mixed $second Resource to compare with. |
291 | | * @param boolean $identical If true then type anomolies count. |
292 | | * @return string Human readable description. |
293 | | * @access private |
294 | | */ |
295 | | function _describeResourceDifference($first, $second, $identical) { |
296 | | return $this->_describeGenericDifference($first, $second); |
297 | | } |
298 | | |
299 | | /** |
300 | | * Creates a human readable description of the |
301 | | * difference between two objects. |
302 | | * @param object $first First object. |
303 | | * @param mixed $second Object to compare with. |
304 | | * @param boolean $identical If true then type anomolies count. |
305 | | * @return string Human readable description. |
306 | | * @access private |
307 | | */ |
308 | | function _describeObjectDifference($first, $second, $identical) { |
309 | | if (! is_object($second)) { |
310 | | return $this->_describeGenericDifference($first, $second); |
311 | | } |
312 | | return $this->_describeArrayDifference( |
313 | | get_object_vars($first), |
314 | | get_object_vars($second), |
315 | | $identical); |
316 | | } |
317 | | |
318 | | /** |
319 | | * Find the first character position that differs |
320 | | * in two strings by binary chop. |
321 | | * @param string $first First string. |
322 | | * @param string $second String to compare with. |
323 | | * @return integer Position of first differing |
324 | | * character. |
325 | | * @access private |
326 | | */ |
327 | | function _stringDiffersAt($first, $second) { |
328 | | if (! $first || ! $second) { |
329 | | return 0; |
330 | | } |
331 | | if (strlen($first) < strlen($second)) { |
332 | | list($first, $second) = array($second, $first); |
333 | | } |
334 | | $position = 0; |
335 | | $step = strlen($first); |
336 | | while ($step > 1) { |
337 | | $step = (integer)(($step + 1) / 2); |
338 | | if (strncmp($first, $second, $position + $step) == 0) { |
339 | | $position += $step; |
340 | | } |
341 | | } |
342 | | return $position; |
343 | | } |
344 | | |
345 | | /** |
346 | | * Sends a formatted dump of a variable to a string. |
347 | | * @param mixed $variable Variable to display. |
348 | | * @return string Output from print_r(). |
349 | | * @access public |
350 | | * @static |
351 | | */ |
352 | | function dump($variable) { |
353 | | ob_start(); |
354 | | print_r($variable); |
355 | | $formatted = ob_get_contents(); |
356 | | ob_end_clean(); |
357 | | return $formatted; |
358 | | } |
359 | | } |
360 | | ? |