暫無描述

Method.php 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <?php
  2. /**
  3. * Laravel IDE Helper Generator
  4. *
  5. * @author Barry vd. Heuvel <barryvdh@gmail.com>
  6. * @copyright 2014 Barry vd. Heuvel / Fruitcake Studio (http://www.fruitcakestudio.nl)
  7. * @license http://www.opensource.org/licenses/mit-license.php MIT
  8. * @link https://github.com/barryvdh/laravel-ide-helper
  9. */
  10. namespace Barryvdh\LaravelIdeHelper;
  11. use phpDocumentor\Reflection\DocBlock;
  12. use phpDocumentor\Reflection\DocBlock\Context;
  13. use phpDocumentor\Reflection\DocBlock\Tag;
  14. use phpDocumentor\Reflection\DocBlock\Tag\ReturnTag;
  15. use phpDocumentor\Reflection\DocBlock\Tag\ParamTag;
  16. use phpDocumentor\Reflection\DocBlock\Serializer as DocBlockSerializer;
  17. class Method
  18. {
  19. /** @var \phpDocumentor\Reflection\DocBlock */
  20. protected $phpdoc;
  21. /** @var \ReflectionMethod */
  22. protected $method;
  23. protected $output = '';
  24. protected $name;
  25. protected $namespace;
  26. protected $params = array();
  27. protected $params_with_default = array();
  28. protected $interfaces = array();
  29. protected $return = null;
  30. /**
  31. * @param \ReflectionMethod $method
  32. * @param string $alias
  33. * @param string $class
  34. * @param string|null $methodName
  35. * @param array $interfaces
  36. */
  37. public function __construct(\ReflectionMethod $method, $alias, $class, $methodName = null, $interfaces = array())
  38. {
  39. $this->method = $method;
  40. $this->interfaces = $interfaces;
  41. $this->name = $methodName ?: $method->name;
  42. $this->namespace = $method->getDeclaringClass()->getNamespaceName();
  43. //Create a DocBlock and serializer instance
  44. $this->phpdoc = new DocBlock($method, new Context($this->namespace));
  45. //Normalize the description and inherit the docs from parents/interfaces
  46. try {
  47. $this->normalizeDescription();
  48. $this->normalizeParams();
  49. $this->normalizeReturn();
  50. } catch (\Exception $e) {}
  51. //Get the parameters, including formatted default values
  52. $this->getParameters($method);
  53. //Make the method static
  54. $this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc));
  55. //Reference the 'real' function in the declaringclass
  56. $declaringClass = $method->getDeclaringClass();
  57. $this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\');
  58. $this->root = '\\' . ltrim($class->getName(), '\\');
  59. }
  60. /**
  61. * Get the class wherein the function resides
  62. *
  63. * @return string
  64. */
  65. public function getDeclaringClass()
  66. {
  67. return $this->declaringClassName;
  68. }
  69. /**
  70. * Return the class from which this function would be called
  71. *
  72. * @return string
  73. */
  74. public function getRoot()
  75. {
  76. return $this->root;
  77. }
  78. /**
  79. * Get the docblock for this method
  80. *
  81. * @param string $prefix
  82. * @return mixed
  83. */
  84. public function getDocComment($prefix = "\t\t")
  85. {
  86. $serializer = new DocBlockSerializer(1, $prefix);
  87. return $serializer->getDocComment($this->phpdoc);
  88. }
  89. /**
  90. * Get the method name
  91. *
  92. * @return string
  93. */
  94. public function getName()
  95. {
  96. return $this->name;
  97. }
  98. /**
  99. * Get the parameters for this method
  100. *
  101. * @param bool $implode Wether to implode the array or not
  102. * @return string
  103. */
  104. public function getParams($implode = true)
  105. {
  106. return $implode ? implode(', ', $this->params) : $this->params;
  107. }
  108. /**
  109. * Get the parameters for this method including default values
  110. *
  111. * @param bool $implode Wether to implode the array or not
  112. * @return string
  113. */
  114. public function getParamsWithDefault($implode = true)
  115. {
  116. return $implode ? implode(', ', $this->params_with_default) : $this->params_with_default;
  117. }
  118. /**
  119. * Get the description and get the inherited docs.
  120. *
  121. */
  122. protected function normalizeDescription()
  123. {
  124. //Get the short + long description from the DocBlock
  125. $description = $this->phpdoc->getText();
  126. //Loop through parents/interfaces, to fill in {@inheritdoc}
  127. if (strpos($description, '{@inheritdoc}') !== false) {
  128. $inheritdoc = $this->getInheritDoc($this->method);
  129. $inheritDescription = $inheritdoc->getText();
  130. $description = str_replace('{@inheritdoc}', $inheritDescription, $description);
  131. $this->phpdoc->setText($description);
  132. //Add the tags that are inherited
  133. $inheritTags = $inheritdoc->getTags();
  134. if ($inheritTags) {
  135. foreach ($inheritTags as $tag) {
  136. $tag->setDocBlock();
  137. $this->phpdoc->appendTag($tag);
  138. }
  139. }
  140. }
  141. }
  142. /**
  143. * Normalize the parameters
  144. */
  145. protected function normalizeParams()
  146. {
  147. //Get the return type and adjust them for beter autocomplete
  148. $paramTags = $this->phpdoc->getTagsByName('param');
  149. if ($paramTags) {
  150. /** @var ParamTag $tag */
  151. foreach($paramTags as $tag){
  152. // Convert the keywords
  153. $content = $this->convertKeywords($tag->getContent());
  154. $tag->setContent($content);
  155. // Get the expanded type and re-set the content
  156. $content = $tag->getType() . ' ' . $tag->getVariableName() . ' ' . $tag->getDescription();
  157. $tag->setContent(trim($content));
  158. }
  159. }
  160. }
  161. /**
  162. * Normalize the return tag (make full namespace, replace interfaces)
  163. */
  164. protected function normalizeReturn()
  165. {
  166. //Get the return type and adjust them for beter autocomplete
  167. $returnTags = $this->phpdoc->getTagsByName('return');
  168. if ($returnTags) {
  169. /** @var ReturnTag $tag */
  170. $tag = reset($returnTags);
  171. // Get the expanded type
  172. $returnValue = $tag->getType();
  173. // Replace the interfaces
  174. foreach($this->interfaces as $interface => $real){
  175. $returnValue = str_replace($interface, $real, $returnValue);
  176. }
  177. // Set the changed content
  178. $tag->setContent($returnValue . ' ' . $tag->getDescription());
  179. $this->return = $returnValue;
  180. }else{
  181. $this->return = null;
  182. }
  183. }
  184. /**
  185. * Convert keywwords that are incorrect.
  186. *
  187. * @param string $string
  188. * @return string
  189. */
  190. protected function convertKeywords($string)
  191. {
  192. $string = str_replace('\Closure', 'Closure', $string);
  193. $string = str_replace('Closure', '\Closure', $string);
  194. $string = str_replace('dynamic', 'mixed', $string);
  195. return $string;
  196. }
  197. /**
  198. * Should the function return a value?
  199. *
  200. * @return bool
  201. */
  202. public function shouldReturn()
  203. {
  204. if($this->return !== "void" && $this->method->name !== "__construct"){
  205. return true;
  206. }
  207. return false;
  208. }
  209. /**
  210. * Get the parameters and format them correctly
  211. *
  212. * @param $method
  213. * @return array
  214. */
  215. public function getParameters($method)
  216. {
  217. //Loop through the default values for paremeters, and make the correct output string
  218. $params = array();
  219. $paramsWithDefault = array();
  220. foreach ($method->getParameters() as $param) {
  221. $paramStr = '$' . $param->getName();
  222. $params[] = $paramStr;
  223. if ($param->isOptional()) {
  224. $default = $param->getDefaultValue();
  225. if (is_bool($default)) {
  226. $default = $default ? 'true' : 'false';
  227. } elseif (is_array($default)) {
  228. $default = 'array()';
  229. } elseif (is_null($default)) {
  230. $default = 'null';
  231. } elseif (is_int($default)) {
  232. //$default = $default;
  233. } else {
  234. $default = "'" . trim($default) . "'";
  235. }
  236. $paramStr .= " = $default";
  237. }
  238. $paramsWithDefault[] = $paramStr;
  239. }
  240. $this->params = $params;
  241. $this->params_with_default = $paramsWithDefault;
  242. }
  243. /**
  244. * @param \ReflectionMethod $reflectionMethod
  245. * @return string
  246. */
  247. protected function getInheritDoc($reflectionMethod)
  248. {
  249. $parentClass = $reflectionMethod->getDeclaringClass()->getParentClass();
  250. //Get either a parent or the interface
  251. if ($parentClass) {
  252. $method = $parentClass->getMethod($reflectionMethod->getName());
  253. } else {
  254. $method = $reflectionMethod->getPrototype();
  255. }
  256. if ($method) {
  257. $phpdoc = new DocBlock($method);
  258. if (strpos($phpdoc->getText(), '{@inheritdoc}') !== false) {
  259. //Not at the end yet, try another parent/interface..
  260. return $this->getInheritDoc($method);
  261. } else {
  262. return $phpdoc;
  263. }
  264. }
  265. }
  266. }