dumper.php 13KB

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