Docblock.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\analysis;
  9. /**
  10. * A source code doc block parser.
  11. *
  12. * This parser may be used as the basis for a variety of secondary tools, including
  13. * a reflection-based API generator, a code metrics analyzer, and various other code or structural
  14. * analysis tools.
  15. */
  16. class Docblock extends \lithium\core\StaticObject {
  17. /**
  18. * List of supported docblock tags.
  19. *
  20. * @var array
  21. */
  22. public static $tags = array(
  23. 'todo', 'discuss', 'fix', 'important', 'var',
  24. 'param', 'return', 'throws', 'see', 'link',
  25. 'task', 'dependencies', 'filter'
  26. );
  27. /**
  28. * Parses a doc block into its major components of `description`, `text` and `tags`.
  29. *
  30. * @param string $comment The doc block string to be parsed
  31. * @return array An associative array of the parsed comment, whose keys are `description`,
  32. * `text` and `tags`.
  33. */
  34. public static function comment($comment) {
  35. $text = null;
  36. $tags = array();
  37. $description = null;
  38. $comment = trim(preg_replace('/^(\s*\/\*\*|\s*\*{1,2}\/|\s*\* ?)/m', '', $comment));
  39. $comment = str_replace("\r\n", "\n", $comment);
  40. if ($items = preg_split('/\n@/ms', $comment, 2)) {
  41. list($description, $tags) = $items + array('', '');
  42. $tags = $tags ? static::tags("@{$tags}") : array();
  43. }
  44. if (strpos($description, "\n\n")) {
  45. list($description, $text) = explode("\n\n", $description, 2);
  46. }
  47. $text = trim($text);
  48. $description = trim($description);
  49. return compact('description', 'text', 'tags');
  50. }
  51. /**
  52. * Parses `@<tagname>` docblock tags and their descriptions from a docblock.
  53. *
  54. * See the `$tags` property for the list of supported tags.
  55. *
  56. * @param string $string The string to be parsed for tags
  57. * @return array Returns an array where each docblock tag is a key name, and the corresponding
  58. * values are either strings (if one of each tag), or arrays (if multiple of the same
  59. * tag).
  60. */
  61. public static function tags($string) {
  62. $regex = '/\n@(?P<type>' . join('|', static::$tags) . ")/msi";
  63. $string = trim($string);
  64. $result = preg_split($regex, "\n$string", -1, PREG_SPLIT_DELIM_CAPTURE);
  65. $tags = array();
  66. for ($i = 1; $i < count($result) - 1; $i += 2) {
  67. $type = trim(strtolower($result[$i]));
  68. $text = trim($result[$i + 1]);
  69. if (isset($tags[$type])) {
  70. $tags[$type] = is_array($tags[$type]) ? $tags[$type] : (array) $tags[$type];
  71. $tags[$type][] = $text;
  72. } else {
  73. $tags[$type] = $text;
  74. }
  75. }
  76. if (isset($tags['param'])) {
  77. $params = $tags['param'];
  78. $tags['params'] = static::_params((array) $tags['param']);
  79. unset($tags['param']);
  80. }
  81. return $tags;
  82. }
  83. /**
  84. * Parses `@param` docblock tags to separate out the parameter type from the description.
  85. *
  86. * @param array $params An array of `@param` tags, as parsed from the `tags()` method.
  87. * @return array Returns an array where each key is a parameter name, and each value is an
  88. * associative array containing `'type'` and `'text'` keys.
  89. */
  90. protected static function _params(array $params) {
  91. $result = array();
  92. foreach ($params as $param) {
  93. $param = explode(' ', $param, 3);
  94. $type = $name = $text = null;
  95. foreach (array('type', 'name', 'text') as $i => $key) {
  96. if (!isset($param[$i])) {
  97. break;
  98. }
  99. ${$key} = $param[$i];
  100. }
  101. if ($name) {
  102. $result[$name] = compact('type', 'text');
  103. }
  104. }
  105. return $result;
  106. }
  107. }
  108. ?>