mirror of
https://github.com/barryvdh/laravel-ide-helper.git
synced 2026-08-17 17:47:13 +00:00
perf: reduce redundant lookups and file I/O in generation hot paths (#1757)
- Convert usedMethods from list to hash map for O(1) dedup lookups - Cache getRelationTypes() and getRelationReturnTypes() per command run - Reuse SplFileObject instances by filename instead of re-opening per method - Cache ContextFactory results per declaring class across docblock helpers Benchmarked with hyperfine (10 runs, 2 warmup): 1.37x faster (~27%).
This commit is contained in:
+12
-11
@@ -101,7 +101,7 @@ class Alias
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($facade === '\Illuminate\Database\Eloquent\Model') {
|
if ($facade === '\Illuminate\Database\Eloquent\Model') {
|
||||||
$this->usedMethods = ['decrement', 'increment'];
|
$this->usedMethods = ['decrement' => true, 'increment' => true];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,7 +381,7 @@ class Alias
|
|||||||
$method = new \ReflectionMethod($className, $name);
|
$method = new \ReflectionMethod($className, $name);
|
||||||
$class = new ReflectionClass($className);
|
$class = new ReflectionClass($className);
|
||||||
|
|
||||||
if (!in_array($magic, $this->usedMethods)) {
|
if (!isset($this->usedMethods[$magic])) {
|
||||||
if ($class !== $this->root) {
|
if ($class !== $this->root) {
|
||||||
$this->methods[] = new Method(
|
$this->methods[] = new Method(
|
||||||
$method,
|
$method,
|
||||||
@@ -393,7 +393,7 @@ class Alias
|
|||||||
$this->getTemplateNames()
|
$this->getTemplateNames()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->usedMethods[] = $magic;
|
$this->usedMethods[$magic] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -410,7 +410,7 @@ class Alias
|
|||||||
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
|
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||||
if ($methods) {
|
if ($methods) {
|
||||||
foreach ($methods as $method) {
|
foreach ($methods as $method) {
|
||||||
if (!in_array($method->name, $this->usedMethods)) {
|
if (!isset($this->usedMethods[$method->name])) {
|
||||||
// Only add the methods to the output when the root is not the same as the class.
|
// Only add the methods to the output when the root is not the same as the class.
|
||||||
// And don't add the __*() methods
|
// And don't add the __*() methods
|
||||||
if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') {
|
if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') {
|
||||||
@@ -424,7 +424,7 @@ class Alias
|
|||||||
$this->getTemplateNames(),
|
$this->getTemplateNames(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$this->usedMethods[] = $method->name;
|
$this->usedMethods[$method->name] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -435,7 +435,7 @@ class Alias
|
|||||||
$properties = $reflection->getStaticProperties();
|
$properties = $reflection->getStaticProperties();
|
||||||
$macros = isset($properties['macros']) ? $properties['macros'] : [];
|
$macros = isset($properties['macros']) ? $properties['macros'] : [];
|
||||||
foreach ($macros as $macro_name => $macro_func) {
|
foreach ($macros as $macro_name => $macro_func) {
|
||||||
if (!in_array($macro_name, $this->usedMethods)) {
|
if (!isset($this->usedMethods[$macro_name])) {
|
||||||
try {
|
try {
|
||||||
$method = $this->getMacroFunction($macro_func);
|
$method = $this->getMacroFunction($macro_func);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
@@ -451,7 +451,7 @@ class Alias
|
|||||||
$this->classAliases,
|
$this->classAliases,
|
||||||
$this->getReturnTypeNormalizers($reflection)
|
$this->getReturnTypeNormalizers($reflection)
|
||||||
);
|
);
|
||||||
$this->usedMethods[] = $macro_name;
|
$this->usedMethods[$macro_name] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -589,12 +589,13 @@ class Alias
|
|||||||
*/
|
*/
|
||||||
protected function removeDuplicateMethodsFromPhpDoc()
|
protected function removeDuplicateMethodsFromPhpDoc()
|
||||||
{
|
{
|
||||||
$methodNames = array_map(function (Method $method) {
|
$methodNames = [];
|
||||||
return $method->getName();
|
foreach ($this->getMethods() as $method) {
|
||||||
}, $this->getMethods());
|
$methodNames[$method->getName()] = true;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->phpdoc->getTags() as $tag) {
|
foreach ($this->phpdoc->getTags() as $tag) {
|
||||||
if ($tag instanceof MethodTag && in_array($tag->getMethodName(), $methodNames)) {
|
if ($tag instanceof MethodTag && isset($methodNames[$tag->getMethodName()])) {
|
||||||
$this->phpdoc->deleteTag($tag);
|
$this->phpdoc->deleteTag($tag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,6 +123,14 @@ class ModelsCommand extends Command
|
|||||||
protected $reset;
|
protected $reset;
|
||||||
protected $phpstorm_noinspections;
|
protected $phpstorm_noinspections;
|
||||||
protected $write_model_external_builder_methods;
|
protected $write_model_external_builder_methods;
|
||||||
|
/**
|
||||||
|
* @var array<string, \SplFileObject>
|
||||||
|
*/
|
||||||
|
protected $fileCache = [];
|
||||||
|
/**
|
||||||
|
* @var array<string, Context>
|
||||||
|
*/
|
||||||
|
protected $contextCache = [];
|
||||||
/**
|
/**
|
||||||
* @var array<string, true>
|
* @var array<string, true>
|
||||||
*/
|
*/
|
||||||
@@ -721,14 +729,19 @@ class ModelsCommand extends Command
|
|||||||
$type = (string)$this->getReturnTypeFromDocBlock($reflection);
|
$type = (string)$this->getReturnTypeFromDocBlock($reflection);
|
||||||
}
|
}
|
||||||
|
|
||||||
$file = new \SplFileObject($reflection->getFileName());
|
$fileName = $reflection->getFileName();
|
||||||
|
if (!isset($this->fileCache[$fileName])) {
|
||||||
|
$this->fileCache[$fileName] = new \SplFileObject($fileName);
|
||||||
|
}
|
||||||
|
$file = $this->fileCache[$fileName];
|
||||||
$file->seek($reflection->getStartLine() - 1);
|
$file->seek($reflection->getStartLine() - 1);
|
||||||
|
|
||||||
$code = '';
|
$lines = [];
|
||||||
while ($file->key() < $reflection->getEndLine()) {
|
while ($file->key() < $reflection->getEndLine()) {
|
||||||
$code .= $file->current();
|
$lines[] = $file->current();
|
||||||
$file->next();
|
$file->next();
|
||||||
}
|
}
|
||||||
|
$code = implode('', $lines);
|
||||||
$code = trim(preg_replace('/\s\s+/', '', $code));
|
$code = trim(preg_replace('/\s\s+/', '', $code));
|
||||||
$begin = strpos($code, 'function(');
|
$begin = strpos($code, 'function(');
|
||||||
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
|
$code = substr($code, $begin, strrpos($code, '}') - $begin + 1);
|
||||||
@@ -1275,13 +1288,18 @@ class ModelsCommand extends Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ?array $cachedRelationTypes = null;
|
||||||
|
protected ?array $cachedRelationReturnTypes = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the available relation types
|
* Returns the available relation types
|
||||||
*/
|
*/
|
||||||
protected function getRelationTypes(): array
|
protected function getRelationTypes(): array
|
||||||
{
|
{
|
||||||
$configuredRelations = $this->laravel['config']->get('ide-helper.additional_relation_types', []);
|
return $this->cachedRelationTypes ??= array_merge(
|
||||||
return array_merge(self::RELATION_TYPES, $configuredRelations);
|
self::RELATION_TYPES,
|
||||||
|
$this->laravel['config']->get('ide-helper.additional_relation_types', [])
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1289,7 +1307,7 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getRelationReturnTypes(): array
|
protected function getRelationReturnTypes(): array
|
||||||
{
|
{
|
||||||
return $this->laravel['config']->get('ide-helper.additional_relation_return_types', []);
|
return $this->cachedRelationReturnTypes ??= $this->laravel['config']->get('ide-helper.additional_relation_return_types', []);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1364,11 +1382,7 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getCommentFromDocBlock(\ReflectionMethod $reflection)
|
protected function getCommentFromDocBlock(\ReflectionMethod $reflection)
|
||||||
{
|
{
|
||||||
$phpDocContext = (new ContextFactory())->createFromReflector($reflection);
|
$context = $this->getDocBlockContext($reflection);
|
||||||
$context = new Context(
|
|
||||||
$phpDocContext->getNamespace(),
|
|
||||||
$phpDocContext->getNamespaceAliases()
|
|
||||||
);
|
|
||||||
$comment = '';
|
$comment = '';
|
||||||
$phpdoc = new DocBlock($reflection, $context);
|
$phpdoc = new DocBlock($reflection, $context);
|
||||||
|
|
||||||
@@ -1389,11 +1403,7 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getReturnTypeFromDocBlock(\ReflectionMethod $reflection, ?\Reflector $reflectorForContext = null)
|
protected function getReturnTypeFromDocBlock(\ReflectionMethod $reflection, ?\Reflector $reflectorForContext = null)
|
||||||
{
|
{
|
||||||
$phpDocContext = (new ContextFactory())->createFromReflector($reflectorForContext ?? $reflection);
|
$context = $this->getDocBlockContext($reflectorForContext ?? $reflection);
|
||||||
$context = new Context(
|
|
||||||
$phpDocContext->getNamespace(),
|
|
||||||
$phpDocContext->getNamespaceAliases()
|
|
||||||
);
|
|
||||||
$type = null;
|
$type = null;
|
||||||
$phpdoc = new DocBlock($reflection, $context);
|
$phpdoc = new DocBlock($reflection, $context);
|
||||||
|
|
||||||
@@ -1411,6 +1421,31 @@ class ModelsCommand extends Command
|
|||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getDocBlockContext(\Reflector $reflector): Context
|
||||||
|
{
|
||||||
|
if ($reflector instanceof \ReflectionMethod) {
|
||||||
|
$key = $reflector->getDeclaringClass()->getName();
|
||||||
|
} elseif ($reflector instanceof ReflectionClass) {
|
||||||
|
$key = $reflector->getName();
|
||||||
|
} else {
|
||||||
|
$phpDocContext = (new ContextFactory())->createFromReflector($reflector);
|
||||||
|
return new Context(
|
||||||
|
$phpDocContext->getNamespace(),
|
||||||
|
$phpDocContext->getNamespaceAliases()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->contextCache[$key])) {
|
||||||
|
$phpDocContext = (new ContextFactory())->createFromReflector($reflector);
|
||||||
|
$this->contextCache[$key] = new Context(
|
||||||
|
$phpDocContext->getNamespace(),
|
||||||
|
$phpDocContext->getNamespaceAliases()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->contextCache[$key];
|
||||||
|
}
|
||||||
|
|
||||||
protected function getReturnTypeFromReflection(\ReflectionMethod $reflection): ?string
|
protected function getReturnTypeFromReflection(\ReflectionMethod $reflection): ?string
|
||||||
{
|
{
|
||||||
$returnType = $reflection->getReturnType();
|
$returnType = $reflection->getReturnType();
|
||||||
@@ -1616,9 +1651,10 @@ class ModelsCommand extends Command
|
|||||||
*/
|
*/
|
||||||
protected function getUsedClassNames(ReflectionClass $reflection): array
|
protected function getUsedClassNames(ReflectionClass $reflection): array
|
||||||
{
|
{
|
||||||
|
$context = $this->getDocBlockContext($reflection);
|
||||||
$namespaceAliases = array_flip(array_map(function ($alias) {
|
$namespaceAliases = array_flip(array_map(function ($alias) {
|
||||||
return ltrim($alias, '\\');
|
return ltrim($alias, '\\');
|
||||||
}, (new ContextFactory())->createFromReflector($reflection)->getNamespaceAliases()));
|
}, $context->getNamespaceAliases()));
|
||||||
$namespaceAliases[$reflection->getName()] = $reflection->getShortName();
|
$namespaceAliases[$reflection->getName()] = $reflection->getShortName();
|
||||||
|
|
||||||
return $namespaceAliases;
|
return $namespaceAliases;
|
||||||
|
|||||||
Reference in New Issue
Block a user