-
Notifications
You must be signed in to change notification settings - Fork 133
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using generators to get a list of reflections #1476
base: 6.52.x
Are you sure you want to change the base?
Using generators to get a list of reflections #1476
Conversation
*/ | ||
public function reflectAllClasses(): iterable | ||
public function reflectAllClasses(): Generator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to change the native type here: iterable
is a supertype of Generator
, and works fine
@@ -43,11 +44,11 @@ public function reflectClass(string $identifierName): ReflectionClass | |||
/** | |||
* Get all the classes available in the scope specified by the SourceLocator. | |||
* | |||
* @return list<ReflectionClass> | |||
* @return Generator<ReflectionClass> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should roll back to iterable<int, ReflectionClass>
here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is the actual BC break, since list<T>
is obviously an extremely small type
*/ | ||
public function reflectAllFunctions(): iterable | ||
public function reflectAllFunctions(): Generator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as comment above: the native type can stay iterable
, and the return type can be iterable<int, ReflectionFunction>
* @return Generator<ReflectionConstant> | ||
*/ | ||
public function reflectAllConstants(): iterable | ||
public function reflectAllConstants(): Generator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as comment above: the native type can stay iterable
, and the return type can be iterable<int, ReflectionConstant>
* @return list<ReflectionClass> | ||
* @return Generator<ReflectionClass> | ||
*/ | ||
public function reflectAllClasses(): iterable; | ||
public function reflectAllClasses(): Generator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This interface should be rolled back, and the @return
types should switch from list
to iterable
*/ | ||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array | ||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): Generator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of this class can be rolled back, except for the return type being iterable
* {@inheritDoc} | ||
*/ | ||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array | ||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): Generator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of this class can be rolled back, except for the return type being iterable
@@ -83,8 +84,8 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier): | |||
* | |||
* @throws InvalidFileLocation | |||
*/ | |||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array | |||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): Generator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The implementation of this class can be rolled back, except for the return type being iterable
$items = []; | ||
foreach ($this->wrappedSourceLocator->locateIdentifiersByType($reflector, $identifierType) as $item) { | ||
yield $items[] = $item; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original implementation caches items before returning them: the new implementation caches items after returning them.
I'm unsure about approach here, but it is a subtle change that can lead to uncached results if the consumer of this iterator crashes
* @return Generator<Reflection> | ||
*/ | ||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array; | ||
public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): Generator; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should move to iterable
rather than Generator
Reasonable change yes; any impact to our own projects we can handle but definitely keen for @kukulich to check here; depending how phpstan consumes these APIs, may or may not be impactful |
@ondrejmirtes will this change be a problem for PHPStan? |
@kukulich Yes, it's a BC break. For example I have custom source locator wrappers which do this: public function locateIdentifiersByType(Reflector $reflector, IdentifierType $identifierType): array
{
return $this->sourceLocator->locateIdentifiersByType($reflector, $identifierType);
} If these changes really lead to better performance (so that BR does not do work that would be thrown away), it might be a better idea to introduce new methods or interfaces that return generators, and keep the old classes and interfaces there. After that we can keep the old methods that will just do Unfortunately if these changes go through and BetterReflection releases a new major, I could not upgrade to it in PHPStan with a clear conscience until 3.0 because these source locators are part of public PHPStan API. I know that for example Rector depends on them and also creates its own implementations. |
@Ocramius @asgrim @kukulich Given all the complexities, let me go back to the first implementation, creating new methods (e.g. |
@shcherbanich let it rest a bit before jumping at it: as you can see, discussion is underway, at least :D
This is a real bummer: stuff like source locators in BetterReflection are marked internal for good reason (their API is squishy), so this is unfortunate. That said, I fully understand the problem, and will think about it today/tomorrow, before we decide whether/how to proceed. |
Are they really internal? I'm also implementing my own and I'd say it's often useful for projects to write their own. So it might be better to un-internal them. |
Part of PR #1475 related to using generators instead of arrays to get a list of reflections
What has been done?
locateIdentifiersByType
now returns a generator to process each individual class sequentiallyreflectAllClasses
/reflectAllFunctions
/reflectAllConstants
methods ofDefaultReflector
class now return generators instead of arraysFindReflectionOnLine
now takes reflections one by one using generators