From a44572676ac096a8b50ae9c786876a7d040eef3d Mon Sep 17 00:00:00 2001 From: Thach Nguyen Date: Sat, 27 Jan 2018 03:27:07 +0700 Subject: [PATCH] Improve `Method` class to reduce generated filesize, and correct FQN types of phpDoc, and support case-insensitive `@inheritdoc` --- src/Method.php | 632 ++++++++++++++++++++------------------- src/views/ide-helper.php | 85 +++--- 2 files changed, 367 insertions(+), 350 deletions(-) diff --git a/src/Method.php b/src/Method.php index be343e2..d6af1a3 100644 --- a/src/Method.php +++ b/src/Method.php @@ -1,311 +1,321 @@ - - * @copyright 2014 Barry vd. Heuvel / Fruitcake Studio (http://www.fruitcakestudio.nl) - * @license http://www.opensource.org/licenses/mit-license.php MIT - * @link https://github.com/barryvdh/laravel-ide-helper - */ - -namespace Barryvdh\LaravelIdeHelper; - -use Barryvdh\Reflection\DocBlock; -use Barryvdh\Reflection\DocBlock\Context; -use Barryvdh\Reflection\DocBlock\Tag; -use Barryvdh\Reflection\DocBlock\Tag\ReturnTag; -use Barryvdh\Reflection\DocBlock\Tag\ParamTag; -use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; - -class Method -{ - /** @var \Barryvdh\Reflection\DocBlock */ - protected $phpdoc; - - /** @var \ReflectionMethod */ - protected $method; - - protected $output = ''; - protected $name; - protected $namespace; - protected $params = array(); - protected $params_with_default = array(); - protected $interfaces = array(); - protected $return = null; - - /** - * @param \ReflectionMethod $method - * @param string $alias - * @param string $class - * @param string|null $methodName - * @param array $interfaces - */ - public function __construct(\ReflectionMethod $method, $alias, $class, $methodName = null, $interfaces = array()) - { - $this->method = $method; - $this->interfaces = $interfaces; - $this->name = $methodName ?: $method->name; - $this->namespace = $method->getDeclaringClass()->getNamespaceName(); - - //Create a DocBlock and serializer instance - $this->phpdoc = new DocBlock($method, new Context($this->namespace)); - - //Normalize the description and inherit the docs from parents/interfaces - try { - $this->normalizeParams($this->phpdoc); - $this->normalizeReturn($this->phpdoc); - $this->normalizeDescription($this->phpdoc); - } catch (\Exception $e) {} - - //Get the parameters, including formatted default values - $this->getParameters($method); - - //Make the method static - $this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc)); - - //Reference the 'real' function in the declaringclass - $declaringClass = $method->getDeclaringClass(); - $this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\'); - $this->root = '\\' . ltrim($class->getName(), '\\'); - } - - /** - * Get the class wherein the function resides - * - * @return string - */ - public function getDeclaringClass() - { - return $this->declaringClassName; - } - - /** - * Return the class from which this function would be called - * - * @return string - */ - public function getRoot() - { - return $this->root; - } - - /** - * Get the docblock for this method - * - * @param string $prefix - * @return mixed - */ - public function getDocComment($prefix = "\t\t") - { - $serializer = new DocBlockSerializer(1, $prefix); - return $serializer->getDocComment($this->phpdoc); - } - - /** - * Get the method name - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Get the parameters for this method - * - * @param bool $implode Wether to implode the array or not - * @return string - */ - public function getParams($implode = true) - { - return $implode ? implode(', ', $this->params) : $this->params; - } - - /** - * Get the parameters for this method including default values - * - * @param bool $implode Wether to implode the array or not - * @return string - */ - public function getParamsWithDefault($implode = true) - { - return $implode ? implode(', ', $this->params_with_default) : $this->params_with_default; - } - - /** - * Get the description and get the inherited docs. - * - * @param DocBlock $phpdoc - */ - protected function normalizeDescription(DocBlock $phpdoc) - { - //Get the short + long description from the DocBlock - $description = $phpdoc->getText(); - - //Loop through parents/interfaces, to fill in {@inheritdoc} - if (strpos($description, '{@inheritdoc}') !== false) { - $inheritdoc = $this->getInheritDoc($this->method); - $inheritDescription = $inheritdoc->getText(); - - $description = str_replace('{@inheritdoc}', $inheritDescription, $description); - $phpdoc->setText($description); - - $this->normalizeParams($inheritdoc); - $this->normalizeReturn($inheritdoc); - - //Add the tags that are inherited - $inheritTags = $inheritdoc->getTags(); - if ($inheritTags) { - /** @var Tag $tag */ - foreach ($inheritTags as $tag) { - $tag->setDocBlock(); - $phpdoc->appendTag($tag); - } - } - } - } - - /** - * Normalize the parameters - * - * @param DocBlock $phpdoc - */ - protected function normalizeParams(DocBlock $phpdoc) - { - //Get the return type and adjust them for beter autocomplete - $paramTags = $phpdoc->getTagsByName('param'); - if ($paramTags) { - /** @var ParamTag $tag */ - foreach($paramTags as $tag){ - // Convert the keywords - $content = $this->convertKeywords($tag->getContent()); - $tag->setContent($content); - - // Get the expanded type and re-set the content - $content = $tag->getType() . ' ' . $tag->getVariableName() . ' ' . $tag->getDescription(); - $tag->setContent(trim($content)); - } - } - } - - /** - * Normalize the return tag (make full namespace, replace interfaces) - * - * @param DocBlock $phpdoc - */ - protected function normalizeReturn(DocBlock $phpdoc) - { - //Get the return type and adjust them for beter autocomplete - $returnTags = $phpdoc->getTagsByName('return'); - if ($returnTags) { - /** @var ReturnTag $tag */ - $tag = reset($returnTags); - // Get the expanded type - $returnValue = $tag->getType(); - - // Replace the interfaces - foreach($this->interfaces as $interface => $real){ - $returnValue = str_replace($interface, $real, $returnValue); - } - - // Set the changed content - $tag->setContent($returnValue . ' ' . $tag->getDescription()); - $this->return = $returnValue; - }else{ - $this->return = null; - } - } - - /** - * Convert keywwords that are incorrect. - * - * @param string $string - * @return string - */ - protected function convertKeywords($string) - { - $string = str_replace('\Closure', 'Closure', $string); - $string = str_replace('Closure', '\Closure', $string); - $string = str_replace('dynamic', 'mixed', $string); - - return $string; - } - - /** - * Should the function return a value? - * - * @return bool - */ - public function shouldReturn() - { - if($this->return !== "void" && $this->method->name !== "__construct"){ - return true; - } - - return false; - } - - /** - * Get the parameters and format them correctly - * - * @param $method - * @return array - */ - public function getParameters($method) - { - //Loop through the default values for paremeters, and make the correct output string - $params = array(); - $paramsWithDefault = array(); - foreach ($method->getParameters() as $param) { - $paramStr = '$' . $param->getName(); - $params[] = $paramStr; - if ($param->isOptional()) { - $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; - if (is_bool($default)) { - $default = $default ? 'true' : 'false'; - } elseif (is_array($default)) { - $default = 'array()'; - } elseif (is_null($default)) { - $default = 'null'; - } elseif (is_int($default)) { - //$default = $default; - } else { - $default = "'" . trim($default) . "'"; - } - $paramStr .= " = $default"; - } - $paramsWithDefault[] = $paramStr; - } - - $this->params = $params; - $this->params_with_default = $paramsWithDefault; - } - - /** - * @param \ReflectionMethod $reflectionMethod - * @return DocBlock - */ - protected function getInheritDoc($reflectionMethod) - { - $parentClass = $reflectionMethod->getDeclaringClass()->getParentClass(); - - //Get either a parent or the interface - if ($parentClass) { - $method = $parentClass->getMethod($reflectionMethod->getName()); - } else { - $method = $reflectionMethod->getPrototype(); - } - if ($method) { - $namespace = $method->getDeclaringClass()->getNamespaceName(); - $phpdoc = new DocBlock($method, new Context($namespace)); - - if (strpos($phpdoc->getText(), '{@inheritdoc}') !== false) { - //Not at the end yet, try another parent/interface.. - return $this->getInheritDoc($method); - } else { - return $phpdoc; - } - } - } -} + + * @copyright 2014 Barry vd. Heuvel / Fruitcake Studio (http://www.fruitcakestudio.nl) + * @license http://www.opensource.org/licenses/mit-license.php MIT + * @link https://github.com/barryvdh/laravel-ide-helper + */ + +namespace Barryvdh\LaravelIdeHelper; + +use Barryvdh\Reflection\DocBlock; +use Barryvdh\Reflection\DocBlock\Context; +use Barryvdh\Reflection\DocBlock\Tag; +use Barryvdh\Reflection\DocBlock\Tag\ReturnTag; +use Barryvdh\Reflection\DocBlock\Tag\ParamTag; +use Barryvdh\Reflection\DocBlock\Serializer as DocBlockSerializer; +use Kdyby\ParseUseStatements\UseStatements; + +class Method +{ + /** @var \Barryvdh\Reflection\DocBlock */ + protected $phpdoc; + + /** @var \ReflectionMethod */ + protected $method; + + protected $output = ''; + protected $name; + protected $namespace; + protected $params = array(); + protected $params_with_default = array(); + protected $interfaces = array(); + protected $return = null; + + /** + * @param \ReflectionMethod $method + * @param string $alias + * @param \ReflectionClass $class + * @param string|null $methodName + * @param array $interfaces + */ + public function __construct(\ReflectionMethod $method, $alias, $class, $methodName = null, $interfaces = array()) + { + $this->method = $method; + $this->interfaces = $interfaces; + $this->name = $methodName ?: $method->name; + $declaringClass = $method->getDeclaringClass(); + $this->namespace = $declaringClass->getNamespaceName(); + + //Create a DocBlock and serializer instance + $this->phpdoc = new DocBlock($method, new Context($this->namespace, static::getUseStatements($declaringClass))); + + //Normalize the description and inherit the docs from parents/interfaces + try { + $this->normalizeReturnTags($this->phpdoc); + $this->normalizeDescription($this->phpdoc); + } catch (\Exception $e) {} + + //Get the parameters, including formatted default values + $this->getParameters($method); + + //Make the method static + //$this->phpdoc->appendTag(Tag::createInstance('@static', $this->phpdoc)); + + //Reference the 'real' function in the declaringClass + $this->declaringClassName = '\\' . ltrim($declaringClass->name, '\\'); + $this->root = '\\' . ltrim($class->getName(), '\\'); + } + + /** + * Get the class wherein the function resides + * + * @return string + */ + public function getDeclaringClass() + { + return $this->declaringClassName; + } + + /** + * Return the class from which this function would be called + * + * @return string + */ + public function getRoot() + { + return $this->root; + } + + /** + * Get the docblock for this method + * + * @param string $prefix + * @param bool $trim + * @return string + */ + public function getDocComment($prefix = "\t\t", $trim = false) + { + $serializer = new DocBlockSerializer(1, $prefix); + $str = $serializer->getDocComment($this->phpdoc); + if ($trim) { + $str = preg_replace(array('/\s+$/m', '#^(\s*/\*\*[\r\n])(?:\s*\*[\r\n])+#u', '#(?:[\r\n]\s*\*)+([\r\n]\s*\*/)$#u'), array('', '$1', '$1'), $str); + } + return $str; + } + + /** + * Get the method name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Checks whether the method is deprecated + * + * @return bool + */ + public function isDeprecated() + { + return $this->phpdoc->hasTag('deprecated'); + } + + /** + * Get the declared parameters for this method + * + * @return array + */ + public function getDocParams() + { + return $this->phpdoc->getTagsByName('param'); + } + + /** + * Get the parameters for this method + * + * @param bool $implode Whether to implode the array or not + * @return string|array + */ + public function getParams($implode = true) + { + return $implode ? implode(', ', $this->params) : $this->params; + } + + /** + * Get the parameters for this method including default values + * + * @param bool $implode Whether to implode the array or not + * @return string|array + */ + public function getParamsWithDefault($implode = true) + { + return $implode ? implode(', ', $this->params_with_default) : $this->params_with_default; + } + + /** + * Get the description and get the inherited docs. + * + * @param DocBlock $phpdoc + */ + protected function normalizeDescription(DocBlock $phpdoc) + { + //Get the short + long description from the DocBlock + $description = $phpdoc->getText(); + + //Loop through parents/interfaces, to fill in {@inheritdoc} + if (stripos($description, '{@inheritdoc}') !== false && ($inheritdoc = $this->getInheritDoc($this->method))) { + $inheritDescription = $inheritdoc->getText(); + + $description = str_ireplace('{@inheritdoc}', $inheritDescription, $description); + $phpdoc->setText($description); + + $this->normalizeReturnTags($inheritdoc); + + //Add the tags that are inherited + foreach ($inheritdoc->getTags() as $tag) { + $tag->setDocBlock(); + $phpdoc->appendTag($tag); + } + } + } + + /** + * Normalize the return tag (make full namespace, replace interfaces) + * + * @param DocBlock $phpdoc + */ + protected function normalizeReturnTags(DocBlock $phpdoc) + { + $this->return = null; + + //Get the return type and adjust them for better autocomplete + foreach ($phpdoc->getTags() as $tag) { + if ($tag instanceof ReturnTag) { + // Convert the keywords + $typeValue = static::convertKeywords($tag->getType(false)); + $tag->setType($typeValue); + + // Get the expanded type + $typeValue = $tag->getType(); + + // Replace the interfaces + if (get_class($tag) === ReturnTag::class) { + foreach ($this->interfaces as $interface => $real) { + $typeValue = preg_replace('/(^|\|)' . preg_quote($interface, '/') . '\b/', $real, $typeValue); + } + $this->return = $typeValue; + } + + // Re-set the type + $tag->setType($typeValue); + } + } + } + + /** + * Convert keywords that are incorrect. + * + * @param string $string + * @return string + */ + protected static function convertKeywords($string) + { + return preg_replace(array('/(^|\|)Closure(\||$)/', '/(^|\|)dynamic(\||$)/'), array('$1\Closure$2', '$1mixed$2'), $string); + } + + /** + * Should the function return a value? + * + * @return bool|int + */ + public function shouldReturn() + { + if ($this->return !== 'void' && $this->method->name !== '__construct') { + return isset($this->return) ? true : 1; + } + + return false; + } + + /** + * Get the parameters and format them correctly + * + * @param \ReflectionMethod $method + * @return void + */ + public function getParameters($method) + { + //Loop through the default values for parameters, and make the correct output string + $params = array(); + $paramsWithDefault = array(); + + foreach ($method->getParameters() as $param) { + $paramStr = '$' . $param->getName(); + $params[] = $paramStr; + + if ($param->isOptional()) { + $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; + if (is_bool($default)) { + $default = $default ? 'true' : 'false'; + } elseif (is_array($default)) { + $default = 'array()'; + } elseif (is_null($default)) { + $default = 'null'; + } elseif (is_int($default)) { + //$default = $default; + } else { + $default = "'" . trim($default) . "'"; + } + $paramStr .= " = $default"; + } + + $paramsWithDefault[] = $paramStr; + } + + $this->params = $params; + $this->params_with_default = $paramsWithDefault; + } + + /** + * @param \ReflectionMethod $reflectionMethod + * @return DocBlock|null + */ + protected function getInheritDoc($reflectionMethod) + { + $parentClass = $reflectionMethod->getDeclaringClass()->getParentClass(); + + //Get either a parent or the interface + if ($parentClass) { + $method = $parentClass->getMethod($reflectionMethod->getName()); + } else { + $method = $reflectionMethod->getPrototype(); + } + if ($method) { + $namespace = $method->getDeclaringClass()->getNamespaceName(); + $phpdoc = new DocBlock($method, new Context($namespace, static::getUseStatements($method->getDeclaringClass()))); + + if (stripos($phpdoc->getText(), '{@inheritdoc}') !== false) { + //Not at the end yet, try another parent/interface.. + return $this->getInheritDoc($method); + } else { + return $phpdoc; + } + } + return null; + } + + protected static function getUseStatements(\ReflectionClass $class) + { + try { + return UseStatements::getUseStatements($class); + } catch (\Exception $e) { + return array(); + } + } +} diff --git a/src/views/ide-helper.php b/src/views/ide-helper.php index 473dc71..bde4f7d 100644 --- a/src/views/ide-helper.php +++ b/src/views/ide-helper.php @@ -1,39 +1,46 @@ - - -/** - * An helper file for Laravel 4, to provide autocomplete information to your IDE - * Generated for Laravel on . - * - * @author Barry vd. Heuvel - * @see https://github.com/barryvdh/laravel-ide-helper - */ - - $aliases): ?> -namespace { - - exit("This file should not be included, only analyzed by your IDE"); - - - - - getClassType() ?> getShortName() ?> getExtends() ? 'extends ' . $alias->getExtends() : '' ?>{ - getMethods() as $method): ?> - - getDocComment(' ')) ?> - - public static function getName() ?>(getParamsWithDefault() ?>){getDeclaringClass() !== $method->getRoot()): ?> - - //Method inherited from getDeclaringClass() ?> - - - shouldReturn() ? 'return ': '' ?>getRoot() ?>::getName() ?>(getParams() ?>); - } - - - } - - - -} - - + + +/** + * An helper file for Laravel 4, to provide autocomplete information to your IDE + * Generated for Laravel on . + * + * @author Barry vd. Heuvel + * @see https://github.com/barryvdh/laravel-ide-helper + */ + + $aliases/* @var \Barryvdh\LaravelIdeHelper\Alias[] $aliases */): ?> +namespace { + + exit('This file should not be included, only analyzed by your IDE'); + + + + +getExtends())) != $alias->getExtends() && $cBase != $alias->getShortName()): ?> + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection */ + + getClassType() ?> getShortName() ?> getExtends() ? 'extends ' . $alias->getExtends() : '' ?>{ +getMethods() as $method): ?> + +getDocParams())) > count($mParams = $method->getParamsWithDefault(false))): ?> + /** @noinspection PhpDocSignatureInspection */ + +getDocComment("\t\t", true)))): ?> + + + + public static function getName() ?>(getParamsWithDefault() ?>){ +getDeclaringClass() !== $method->getRoot()): ?> + //Method inherited from getDeclaringClass() ?> + + + /** @noinspection PhpUnnecessaryFullyQualifiedNameInspection,PhpDynamicAsStaticMethodCallInspectionshouldReturn() === 1 ? ',PhpVoidFunctionResultUsedInspection' : '') . ($method->isDeprecated() ? ',PhpDeprecationInspection' : '') ?> */ + shouldReturn() ? 'return ' : '' ?>getRoot() ?>::getName() ?>(getParams() ?>); + } + + + } + + +} +