Improve Method class to reduce generated filesize, and correct FQN types of phpDoc, and support case-insensitive @inheritdoc

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