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') {
|
||||
$this->usedMethods = ['decrement', 'increment'];
|
||||
$this->usedMethods = ['decrement' => true, 'increment' => true];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ class Alias
|
||||
$method = new \ReflectionMethod($className, $name);
|
||||
$class = new ReflectionClass($className);
|
||||
|
||||
if (!in_array($magic, $this->usedMethods)) {
|
||||
if (!isset($this->usedMethods[$magic])) {
|
||||
if ($class !== $this->root) {
|
||||
$this->methods[] = new Method(
|
||||
$method,
|
||||
@@ -393,7 +393,7 @@ class Alias
|
||||
$this->getTemplateNames()
|
||||
);
|
||||
}
|
||||
$this->usedMethods[] = $magic;
|
||||
$this->usedMethods[$magic] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,7 +410,7 @@ class Alias
|
||||
$methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
|
||||
if ($methods) {
|
||||
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.
|
||||
// And don't add the __*() methods
|
||||
if ($this->extends !== $class && substr($method->name, 0, 2) !== '__') {
|
||||
@@ -424,7 +424,7 @@ class Alias
|
||||
$this->getTemplateNames(),
|
||||
);
|
||||
}
|
||||
$this->usedMethods[] = $method->name;
|
||||
$this->usedMethods[$method->name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,7 +435,7 @@ class Alias
|
||||
$properties = $reflection->getStaticProperties();
|
||||
$macros = isset($properties['macros']) ? $properties['macros'] : [];
|
||||
foreach ($macros as $macro_name => $macro_func) {
|
||||
if (!in_array($macro_name, $this->usedMethods)) {
|
||||
if (!isset($this->usedMethods[$macro_name])) {
|
||||
try {
|
||||
$method = $this->getMacroFunction($macro_func);
|
||||
} catch (Throwable $e) {
|
||||
@@ -451,7 +451,7 @@ class Alias
|
||||
$this->classAliases,
|
||||
$this->getReturnTypeNormalizers($reflection)
|
||||
);
|
||||
$this->usedMethods[] = $macro_name;
|
||||
$this->usedMethods[$macro_name] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -589,12 +589,13 @@ class Alias
|
||||
*/
|
||||
protected function removeDuplicateMethodsFromPhpDoc()
|
||||
{
|
||||
$methodNames = array_map(function (Method $method) {
|
||||
return $method->getName();
|
||||
}, $this->getMethods());
|
||||
$methodNames = [];
|
||||
foreach ($this->getMethods() as $method) {
|
||||
$methodNames[$method->getName()] = true;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,14 @@ class ModelsCommand extends Command
|
||||
protected $reset;
|
||||
protected $phpstorm_noinspections;
|
||||
protected $write_model_external_builder_methods;
|
||||
/**
|
||||
* @var array<string, \SplFileObject>
|
||||
*/
|
||||
protected $fileCache = [];
|
||||
/**
|
||||
* @var array<string, Context>
|
||||
*/
|
||||
protected $contextCache = [];
|
||||
/**
|
||||
* @var array<string, true>
|
||||
*/
|
||||
@@ -721,14 +729,19 @@ class ModelsCommand extends Command
|
||||
$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);
|
||||
|
||||
$code = '';
|
||||
$lines = [];
|
||||
while ($file->key() < $reflection->getEndLine()) {
|
||||
$code .= $file->current();
|
||||
$lines[] = $file->current();
|
||||
$file->next();
|
||||
}
|
||||
$code = implode('', $lines);
|
||||
$code = trim(preg_replace('/\s\s+/', '', $code));
|
||||
$begin = strpos($code, 'function(');
|
||||
$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
|
||||
*/
|
||||
protected function getRelationTypes(): array
|
||||
{
|
||||
$configuredRelations = $this->laravel['config']->get('ide-helper.additional_relation_types', []);
|
||||
return array_merge(self::RELATION_TYPES, $configuredRelations);
|
||||
return $this->cachedRelationTypes ??= array_merge(
|
||||
self::RELATION_TYPES,
|
||||
$this->laravel['config']->get('ide-helper.additional_relation_types', [])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1289,7 +1307,7 @@ class ModelsCommand extends Command
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$phpDocContext = (new ContextFactory())->createFromReflector($reflection);
|
||||
$context = new Context(
|
||||
$phpDocContext->getNamespace(),
|
||||
$phpDocContext->getNamespaceAliases()
|
||||
);
|
||||
$context = $this->getDocBlockContext($reflection);
|
||||
$comment = '';
|
||||
$phpdoc = new DocBlock($reflection, $context);
|
||||
|
||||
@@ -1389,11 +1403,7 @@ class ModelsCommand extends Command
|
||||
*/
|
||||
protected function getReturnTypeFromDocBlock(\ReflectionMethod $reflection, ?\Reflector $reflectorForContext = null)
|
||||
{
|
||||
$phpDocContext = (new ContextFactory())->createFromReflector($reflectorForContext ?? $reflection);
|
||||
$context = new Context(
|
||||
$phpDocContext->getNamespace(),
|
||||
$phpDocContext->getNamespaceAliases()
|
||||
);
|
||||
$context = $this->getDocBlockContext($reflectorForContext ?? $reflection);
|
||||
$type = null;
|
||||
$phpdoc = new DocBlock($reflection, $context);
|
||||
|
||||
@@ -1411,6 +1421,31 @@ class ModelsCommand extends Command
|
||||
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
|
||||
{
|
||||
$returnType = $reflection->getReturnType();
|
||||
@@ -1616,9 +1651,10 @@ class ModelsCommand extends Command
|
||||
*/
|
||||
protected function getUsedClassNames(ReflectionClass $reflection): array
|
||||
{
|
||||
$context = $this->getDocBlockContext($reflection);
|
||||
$namespaceAliases = array_flip(array_map(function ($alias) {
|
||||
return ltrim($alias, '\\');
|
||||
}, (new ContextFactory())->createFromReflector($reflection)->getNamespaceAliases()));
|
||||
}, $context->getNamespaceAliases()));
|
||||
$namespaceAliases[$reflection->getName()] = $reflection->getShortName();
|
||||
|
||||
return $namespaceAliases;
|
||||
|
||||
Reference in New Issue
Block a user