/vendor/d11wtq/boris/lib/Boris/ColoredInspector.php

https://gitlab.com/daniruizcamacho/pfcascensores · PHP · 273 lines · 185 code · 32 blank · 56 comment · 14 complexity · 8aa11018ff2f0b277dc6320e3004e2b1 MD5 · raw file

  1. <?php
  2. /* vim: set shiftwidth=2 expandtab softtabstop=2: */
  3. /**
  4. * @author Rob Morris <rob@irongaze.com>
  5. * @author Chris Corbyn <chris@w3style.co.uk>
  6. *
  7. * Copyright © 2013 Rob Morris.
  8. */
  9. namespace Boris;
  10. /**
  11. * Identifies data types in data structures and syntax highlights them.
  12. */
  13. class ColoredInspector implements Inspector {
  14. static $TERM_COLORS = array(
  15. 'black' => "\033[0;30m",
  16. 'white' => "\033[1;37m",
  17. 'none' => "\033[1;30m",
  18. 'dark_grey' => "\033[1;30m",
  19. 'light_grey' => "\033[0;37m",
  20. 'dark_red' => "\033[0;31m",
  21. 'light_red' => "\033[1;31m",
  22. 'dark_green' => "\033[0;32m",
  23. 'light_green' => "\033[1;32m",
  24. 'dark_yellow' => "\033[0;33m",
  25. 'light_yellow' => "\033[1;33m",
  26. 'dark_blue' => "\033[0;34m",
  27. 'light_blue' => "\033[1;34m",
  28. 'dark_purple' => "\033[0;35m",
  29. 'light_purple' => "\033[1;35m",
  30. 'dark_cyan' => "\033[0;36m",
  31. 'light_cyan' => "\033[1;36m",
  32. );
  33. private $_fallback;
  34. private $_colorMap = array();
  35. /**
  36. * Initialize a new ColoredInspector, using $colorMap.
  37. *
  38. * The colors should be an associative array with the keys:
  39. *
  40. * - 'integer'
  41. * - 'float'
  42. * - 'keyword'
  43. * - 'string'
  44. * - 'boolean'
  45. * - 'default'
  46. *
  47. * And the values, one of the following colors:
  48. *
  49. * - 'none'
  50. * - 'black'
  51. * - 'white'
  52. * - 'dark_grey'
  53. * - 'light_grey'
  54. * - 'dark_red'
  55. * - 'light_red'
  56. * - 'dark_green'
  57. * - 'light_green'
  58. * - 'dark_yellow'
  59. * - 'light_yellow'
  60. * - 'dark_blue'
  61. * - 'light_blue'
  62. * - 'dark_purple'
  63. * - 'light_purple'
  64. * - 'dark_cyan'
  65. * - 'light_cyan'
  66. *
  67. * An empty $colorMap array effectively means 'none' for all types.
  68. *
  69. * @param array $colorMap
  70. */
  71. public function __construct($colorMap = null) {
  72. $this->_fallback = new DumpInspector();
  73. if (isset($colorMap)) {
  74. $this->_colorMap = $colorMap;
  75. } else {
  76. $this->_colorMap = $this->_defaultColorMap();
  77. }
  78. }
  79. public function inspect($variable) {
  80. return preg_replace(
  81. '/^/m',
  82. $this->_colorize('comment', '// '),
  83. $this->_dump($variable)
  84. );
  85. }
  86. /**
  87. * Returns an associative array of an object's properties.
  88. *
  89. * This method is public so that subclasses may override it.
  90. *
  91. * @param object $value
  92. * @return array
  93. * */
  94. public function objectVars($value) {
  95. return get_object_vars($value);
  96. }
  97. // -- Private Methods
  98. public function _dump($value) {
  99. $tests = array(
  100. 'is_null' => '_dumpNull',
  101. 'is_string' => '_dumpString',
  102. 'is_bool' => '_dumpBoolean',
  103. 'is_integer' => '_dumpInteger',
  104. 'is_float' => '_dumpFloat',
  105. 'is_array' => '_dumpArray',
  106. 'is_object' => '_dumpObject'
  107. );
  108. foreach ($tests as $predicate => $outputMethod) {
  109. if (call_user_func($predicate, $value))
  110. return call_user_func(array($this, $outputMethod), $value);
  111. }
  112. return $this->_fallback->inspect($value);
  113. }
  114. private function _dumpNull($value) {
  115. return $this->_colorize('keyword', 'NULL');
  116. }
  117. private function _dumpString($value) {
  118. return $this->_colorize('string', var_export($value, true));
  119. }
  120. private function _dumpBoolean($value) {
  121. return $this->_colorize('bool', var_export($value, true));
  122. }
  123. private function _dumpInteger($value) {
  124. return $this->_colorize('integer', var_export($value, true));
  125. }
  126. private function _dumpFloat($value) {
  127. return $this->_colorize('float', var_export($value, true));
  128. }
  129. private function _dumpArray($value) {
  130. return $this->_dumpStructure('array', $value);
  131. }
  132. private function _dumpObject($value) {
  133. return $this->_dumpStructure(
  134. sprintf('object(%s)', get_class($value)),
  135. $this->objectVars($value)
  136. );
  137. }
  138. private function _dumpStructure($type, $value) {
  139. return $this->_astToString($this->_buildAst($type, $value));
  140. }
  141. public function _buildAst($type, $value, $seen = array()) {
  142. // FIXME: Improve this AST so it doesn't require access to dump() or colorize()
  143. if ($this->_isSeen($value, $seen)) {
  144. return $this->_colorize('default', '*** RECURSION ***');
  145. } else {
  146. $nextSeen = array_merge($seen, array($value));
  147. }
  148. if (is_object($value)) {
  149. $vars = $this->objectVars($value);
  150. } else {
  151. $vars = $value;
  152. }
  153. $self = $this;
  154. return array(
  155. 'name' => $this->_colorize('keyword', $type),
  156. 'children' => empty($vars) ? array() : array_combine(
  157. array_map(array($this, '_dump'), array_keys($vars)),
  158. array_map(
  159. function($v) use($self, $nextSeen) {
  160. if (is_object($v)) {
  161. return $self->_buildAst(
  162. sprintf('object(%s)', get_class($v)),
  163. $v,
  164. $nextSeen
  165. );
  166. } elseif (is_array($v)) {
  167. return $self->_buildAst('array', $v, $nextSeen);
  168. } else {
  169. return $self->_dump($v);
  170. }
  171. },
  172. array_values($vars)
  173. )
  174. )
  175. );
  176. }
  177. public function _astToString($node, $indent = 0) {
  178. $children = $node['children'];
  179. $self = $this;
  180. return implode(
  181. "\n",
  182. array(
  183. sprintf('%s(', $node['name']),
  184. implode(
  185. ",\n",
  186. array_map(
  187. function($k) use($self, $children, $indent) {
  188. if (is_array($children[$k])) {
  189. return sprintf(
  190. '%s%s => %s',
  191. str_repeat(' ', ($indent + 1) * 2),
  192. $k,
  193. $self->_astToString($children[$k], $indent + 1)
  194. );
  195. } else {
  196. return sprintf(
  197. '%s%s => %s',
  198. str_repeat(' ', ($indent + 1) * 2),
  199. $k,
  200. $children[$k]
  201. );
  202. }
  203. },
  204. array_keys($children)
  205. )
  206. ),
  207. sprintf('%s)', str_repeat(' ', $indent * 2))
  208. )
  209. );
  210. }
  211. private function _defaultColorMap() {
  212. return array(
  213. 'integer' => 'light_green',
  214. 'float' => 'light_yellow',
  215. 'string' => 'light_red',
  216. 'bool' => 'light_purple',
  217. 'keyword' => 'light_cyan',
  218. 'comment' => 'dark_grey',
  219. 'default' => 'none'
  220. );
  221. }
  222. private function _colorize($type, $value) {
  223. if (!empty($this->_colorMap[$type])) {
  224. $colorName = $this->_colorMap[$type];
  225. } else {
  226. $colorName = $this->_colorMap['default'];
  227. }
  228. return sprintf(
  229. "%s%s\033[0m",
  230. static::$TERM_COLORS[$colorName],
  231. $value
  232. );
  233. }
  234. private function _isSeen($value, $seen) {
  235. foreach ($seen as $v) {
  236. if ($v === $value)
  237. return true;
  238. }
  239. return false;
  240. }
  241. }