Class.php 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. <?php
  2. /**
  3. * Class documentation generator.
  4. *
  5. * @package Kohana/Userguide
  6. * @category Base
  7. * @author Kohana Team
  8. * @copyright (c) Kohana Team
  9. * @license https://koseven.ga/LICENSE.md
  10. */
  11. class Kohana_Kodoc_Class extends Kodoc {
  12. /**
  13. * @var ReflectionClass The ReflectionClass for this class
  14. */
  15. public $class;
  16. /**
  17. * @var string modifiers like abstract, final
  18. */
  19. public $modifiers;
  20. /**
  21. * @var string description of the class from the comment
  22. */
  23. public $description;
  24. /**
  25. * @var array array of tags, retrieved from the comment
  26. */
  27. public $tags = [];
  28. /**
  29. * @var array array of this classes constants
  30. */
  31. public $constants = [];
  32. /**
  33. * @var array Parent classes/interfaces of this class/interface
  34. */
  35. public $parents = [];
  36. /**
  37. * Loads a class and uses [reflection](http://php.net/reflection) to parse
  38. * the class. Reads the class modifiers, constants and comment. Parses the
  39. * comment to find the description and tags.
  40. *
  41. * @param string Class name
  42. * @return void
  43. */
  44. public function __construct($class)
  45. {
  46. $this->class = new ReflectionClass($class);
  47. if ($modifiers = $this->class->getModifiers())
  48. {
  49. $this->modifiers = '<small>'.implode(' ', Reflection::getModifierNames($modifiers)).'</small> ';
  50. }
  51. $this->constants = $this->class->getConstants();
  52. // If ReflectionClass::getParentClass() won't work if the class in
  53. // question is an interface
  54. if ($this->class->isInterface())
  55. {
  56. $this->parents = $this->class->getInterfaces();
  57. }
  58. else
  59. {
  60. $parent = $this->class;
  61. while ($parent = $parent->getParentClass())
  62. {
  63. $this->parents[] = $parent;
  64. }
  65. }
  66. if ( ! $comment = $this->class->getDocComment())
  67. {
  68. foreach ($this->parents as $parent)
  69. {
  70. if ($comment = $parent->getDocComment())
  71. {
  72. // Found a description for this class
  73. break;
  74. }
  75. }
  76. }
  77. list($this->description, $this->tags) = Kodoc::parse($comment, FALSE);
  78. }
  79. /**
  80. * Gets the constants of this class as HTML.
  81. *
  82. * @return array
  83. */
  84. public function constants()
  85. {
  86. $result = [];
  87. foreach ($this->constants as $name => $value)
  88. {
  89. $result[$name] = Debug::vars($value);
  90. }
  91. return $result;
  92. }
  93. /**
  94. * Get the description of this class as HTML. Includes a warning when the
  95. * class or one of its parents could not be found.
  96. *
  97. * @return string HTML
  98. */
  99. public function description()
  100. {
  101. $result = $this->description;
  102. // If this class extends Kodoc_Missing, add a warning about possible
  103. // incomplete documentation
  104. foreach ($this->parents as $parent)
  105. {
  106. if ($parent->name == 'Kodoc_Missing')
  107. {
  108. $result .= "[!!] **This class, or a class parent, could not be
  109. found or loaded. This could be caused by a missing
  110. module or other dependancy. The documentation for
  111. class may not be complete!**";
  112. }
  113. }
  114. return Kodoc_Markdown::markdown($result);
  115. }
  116. /**
  117. * Gets a list of the class properties as [Kodoc_Property] objects.
  118. *
  119. * @return array
  120. */
  121. public function properties()
  122. {
  123. $props = $this->class->getProperties();
  124. $defaults = $this->class->getDefaultProperties();
  125. usort($props, [$this,'_prop_sort']);
  126. foreach ($props as $key => $property)
  127. {
  128. // Create Kodoc Properties for each property
  129. $props[$key] = new Kodoc_Property($this->class->name, $property->name, Arr::get($defaults, $property->name));
  130. }
  131. return $props;
  132. }
  133. protected function _prop_sort($a, $b)
  134. {
  135. // If one property is public, and the other is not, it goes on top
  136. if ($a->isPublic() AND ( ! $b->isPublic()))
  137. return -1;
  138. if ($b->isPublic() AND ( ! $a->isPublic()))
  139. return 1;
  140. // If one property is protected and the other is private, it goes on top
  141. if ($a->isProtected() AND $b->isPrivate())
  142. return -1;
  143. if ($b->isProtected() AND $a->isPrivate())
  144. return 1;
  145. // Otherwise just do alphabetical
  146. return strcmp($a->name, $b->name);
  147. }
  148. /**
  149. * Gets a list of the class properties as [Kodoc_Method] objects.
  150. *
  151. * @return array
  152. */
  153. public function methods()
  154. {
  155. $methods = $this->class->getMethods();
  156. usort($methods, [$this,'_method_sort']);
  157. foreach ($methods as $key => $method)
  158. {
  159. $methods[$key] = new Kodoc_Method($this->class->name, $method->name);
  160. }
  161. return $methods;
  162. }
  163. /**
  164. * Sort methods based on their visibility and declaring class based on:
  165. *
  166. * * methods will be sorted public, protected, then private.
  167. * * methods that are declared by an ancestor will be after classes
  168. * declared by the current class
  169. * * lastly, they will be sorted alphabetically
  170. *
  171. */
  172. protected function _method_sort($a, $b)
  173. {
  174. // If one method is public, and the other is not, it goes on top
  175. if ($a->isPublic() AND ( ! $b->isPublic()))
  176. return -1;
  177. if ($b->isPublic() AND ( ! $a->isPublic()))
  178. return 1;
  179. // If one method is protected and the other is private, it goes on top
  180. if ($a->isProtected() AND $b->isPrivate())
  181. return -1;
  182. if ($b->isProtected() AND $a->isPrivate())
  183. return 1;
  184. // The methods have the same visibility, so check the declaring class depth:
  185. /*
  186. echo Debug::vars('a is '.$a->class.'::'.$a->name,'b is '.$b->class.'::'.$b->name,
  187. 'are the classes the same?', $a->class == $b->class,'if they are, the result is:',strcmp($a->name, $b->name),
  188. 'is a this class?', $a->name == $this->class->name,-1,
  189. 'is b this class?', $b->name == $this->class->name,1,
  190. 'otherwise, the result is:',strcmp($a->class, $b->class)
  191. );
  192. */
  193. // If both methods are defined in the same class, just compare the method names
  194. if ($a->class == $b->class)
  195. return strcmp($a->name, $b->name);
  196. // If one of them was declared by this class, it needs to be on top
  197. if ($a->name == $this->class->name)
  198. return -1;
  199. if ($b->name == $this->class->name)
  200. return 1;
  201. // Otherwise, get the parents of each methods declaring class, then compare which function has more "ancestors"
  202. $adepth = 0;
  203. $bdepth = 0;
  204. $parent = $a->getDeclaringClass();
  205. do
  206. {
  207. $adepth++;
  208. }
  209. while ($parent = $parent->getParentClass());
  210. $parent = $b->getDeclaringClass();
  211. do
  212. {
  213. $bdepth++;
  214. }
  215. while ($parent = $parent->getParentClass());
  216. return $bdepth - $adepth;
  217. }
  218. /**
  219. * Get the tags of this class as HTML.
  220. *
  221. * @return array
  222. */
  223. public function tags()
  224. {
  225. $result = [];
  226. foreach ($this->tags as $name => $set)
  227. {
  228. foreach ($set as $text)
  229. {
  230. $result[$name][] = Kodoc::format_tag($name, $text);
  231. }
  232. }
  233. return $result;
  234. }
  235. } // End Kodoc_Class