@@ -35,9 +35,12 @@ class AutoloadSourceLocator implements SourceLocator
3535
3636 private FileNodesFetcher $ fileNodesFetcher ;
3737
38- /** @var array<string, FetchedNode<\PhpParser\Node\Stmt\ClassLike>> */
38+ /** @var array<string, array< FetchedNode<\PhpParser\Node\Stmt\ClassLike> >> */
3939 private array $ classNodes = [];
4040
41+ /** @var array<string, Reflection|null> */
42+ private array $ classReflections = [];
43+
4144 /** @var array<string, FetchedNode<\PhpParser\Node\Stmt\Function_>> */
4245 private array $ functionNodes = [];
4346
@@ -82,7 +85,7 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier):
8285 return null ;
8386 }
8487
85- return $ this ->findReflection ($ reflector , $ reflectionFileName , $ identifier );
88+ return $ this ->findReflection ($ reflector , $ reflectionFileName , $ identifier, null );
8689 }
8790
8891 if ($ identifier ->isConstant ()) {
@@ -155,32 +158,28 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier):
155158 }
156159
157160 $ loweredClassName = strtolower ($ identifier ->getName ());
158- if (array_key_exists ($ loweredClassName , $ this ->classNodes )) {
159- $ nodeToReflection = new NodeToReflection ();
160- return $ nodeToReflection ->__invoke (
161- $ reflector ,
162- $ this ->classNodes [$ loweredClassName ]->getNode (),
163- $ this ->locatedSourcesByFile [$ this ->classNodes [$ loweredClassName ]->getFileName ()],
164- $ this ->classNodes [$ loweredClassName ]->getNamespace ()
165- );
161+ if (array_key_exists ($ loweredClassName , $ this ->classReflections )) {
162+ return $ this ->classReflections [$ loweredClassName ];
166163 }
167164
168165 $ locateResult = $ this ->locateClassByName ($ identifier ->getName ());
169166 if ($ locateResult === null ) {
170167 return null ;
171168 }
172- [$ potentiallyLocatedFile , $ className ] = $ locateResult ;
169+ [$ potentiallyLocatedFile , $ className, $ startLine ] = $ locateResult ;
173170
174- return $ this ->findReflection ($ reflector , $ potentiallyLocatedFile , new Identifier ($ className , $ identifier ->getType ()));
171+ return $ this ->findReflection ($ reflector , $ potentiallyLocatedFile , new Identifier ($ className , $ identifier ->getType ()), $ startLine );
175172 }
176173
177- private function findReflection (Reflector $ reflector , string $ file , Identifier $ identifier ): ?Reflection
174+ private function findReflection (Reflector $ reflector , string $ file , Identifier $ identifier, ? int $ startLine ): ?Reflection
178175 {
179176 if (!array_key_exists ($ file , $ this ->locatedSourcesByFile )) {
180177 $ result = $ this ->fileNodesFetcher ->fetchNodes ($ file );
181178 $ this ->locatedSourcesByFile [$ file ] = $ result ->getLocatedSource ();
182- foreach ($ result ->getClassNodes () as $ className => $ fetchedClassNode ) {
183- $ this ->classNodes [$ className ] = $ fetchedClassNode ;
179+ foreach ($ result ->getClassNodes () as $ className => $ fetchedClassNodes ) {
180+ foreach ($ fetchedClassNodes as $ fetchedClassNode ) {
181+ $ this ->classNodes [$ className ][] = $ fetchedClassNode ;
182+ }
184183 }
185184 foreach ($ result ->getFunctionNodes () as $ functionName => $ fetchedFunctionNode ) {
186185 $ this ->functionNodes [$ functionName ] = $ fetchedFunctionNode ;
@@ -196,16 +195,27 @@ private function findReflection(Reflector $reflector, string $file, Identifier $
196195 $ nodeToReflection = new NodeToReflection ();
197196 if ($ identifier ->isClass ()) {
198197 $ identifierName = strtolower ($ identifier ->getName ());
198+ if (array_key_exists ($ identifierName , $ this ->classReflections )) {
199+ return $ this ->classReflections [$ identifierName ];
200+ }
199201 if (!array_key_exists ($ identifierName , $ this ->classNodes )) {
200202 return null ;
201203 }
202204
203- return $ nodeToReflection ->__invoke (
204- $ reflector ,
205- $ this ->classNodes [$ identifierName ]->getNode (),
206- $ locatedSource ,
207- $ this ->classNodes [$ identifierName ]->getNamespace ()
208- );
205+ foreach ($ this ->classNodes [$ identifierName ] as $ classNode ) {
206+ if ($ startLine !== null && $ startLine !== $ classNode ->getNode ()->getStartLine ()) {
207+ continue ;
208+ }
209+
210+ return $ this ->classReflections [$ identifierName ] = $ nodeToReflection ->__invoke (
211+ $ reflector ,
212+ $ classNode ->getNode (),
213+ $ locatedSource ,
214+ $ classNode ->getNamespace ()
215+ );
216+ }
217+
218+ return null ;
209219 }
210220 if ($ identifier ->isFunction ()) {
211221 $ identifierName = strtolower ($ identifier ->getName ());
@@ -243,7 +253,7 @@ public function locateIdentifiersByType(Reflector $reflector, IdentifierType $id
243253 * error handler temporarily.
244254 *
245255 * @throws ReflectionException
246- * @return array{string, string}|null
256+ * @return array{string, string, int|null }|null
247257 */
248258 private function locateClassByName (string $ className ): ?array
249259 {
@@ -259,13 +269,13 @@ private function locateClassByName(string $className): ?array
259269 return null ;
260270 }
261271
262- return [$ filename , $ reflection ->getName ()];
272+ return [$ filename , $ reflection ->getName (), $ reflection -> getStartLine () !== false ? $ reflection -> getStartLine () : null ];
263273 }
264274
265275 $ this ->silenceErrors ();
266276
267277 try {
268- /** @var array{string, string}|null */
278+ /** @var array{string, string, null }|null */
269279 return FileReadTrapStreamWrapper::withStreamWrapperOverride (
270280 static function () use ($ className ): ?array {
271281 $ functions = spl_autoload_functions ();
@@ -283,7 +293,7 @@ static function () use ($className): ?array {
283293 * This will not be `null` when the autoloader tried to read a file.
284294 */
285295 if (FileReadTrapStreamWrapper::$ autoloadLocatedFile !== null ) {
286- return [FileReadTrapStreamWrapper::$ autoloadLocatedFile , $ className ];
296+ return [FileReadTrapStreamWrapper::$ autoloadLocatedFile , $ className, null ];
287297 }
288298 }
289299
0 commit comments