Attributes: Discover without loading the class/file? ("static reflection")
@SerafimArts is already working on this.
Since Sep 30, 2021.
- Dominant language
- PHP
- Stars
- 2.1k
- Forks
- 92
- Avg merge
- 14h 57m
- Merged PRs (30d)
- 4
Description
Motivation
One feature of some other annotation discovery tools is to do the discovery without actually loading the source files.
Perhaps we might even want to delay the loading of the actual annotation or attribute classes.
One benefit of this is to "survive" classes that depend on optional 3rd party dependencies, without fatal error.
E.g. if one of your packages has a class that implements a 3rd party interface, but that interface belongs to an optional package that is currently not present, then loading that file would cause a 'Fatal error: Uncaught Error: Interface "I" not found'. See https://3v4l.org/ANDlX. A solution based on a "static reflection parser" can determine that the base class or interface is missing and safely skip the result.
Another benefit might be memory use for php opcode, although I am not really sure if that is a valid concern. Surely the parsing also consumes memory, just a different type of it. And for performance, I would think anything that uses a userland parser must be slower than native loading.
Current situation in spiral/attributes
The metadata reader in spiral/attributes requires reflection classes.
So we could use the adapter layer from roave/BetterReflection to get "fake" reflection classes and functions, and send those to the spiral reader.
But would this not mean that the php file has to be parsed twice? Once for the reflection, and a second time to get the attributes? Or would caching make this irrelevant?
Also, do we want projects to need a dependency to BetterReflection if they want this?
We might get into a bizarre situation where the latest version of BetterReflection already supports attributes reading (but only works for PHP 8), and projects that want attributes in PHP 7 would use an older version of BetterReflection in combination with spiral/attributes.
Perhaps that's all not so bad, but..
Question / request
I am wondering if spiral wants to support attributes discovery without loading the classes, or what should be the recommended way to achieve this.
One option, as mentioned, would be BetterReflection.
Another option would be to redesign the system a little, so that it would no longer require native \Reflector objects (\ReflectionClass, \ReflectionFunction etc). Instead it could rely on string names of a class, function etc, or on some kind of light-weight handle object, that uniquely identifies the symbol (class, function, parameter etc), without mimicking the full reflection API.
A handle object would also allow to simplify the interface, now we would only need 1 or 2 methods instead of 5 or 10 methods. On the other hand, we would get some switch() or if/else within some of the methods. Of course for BC this would have to be an alternative interface, we cannot just remove the existing ReaderInterface.
SymbolHandle ideas
Before I discovered spiral/reflection, I was experimenting with a custom solution.
Part of this was a SymbolHandle that identifies a class, method, parameter, etc.
Basically I ended up with a value object that stores the class name of the reflector class that would be used (e.g. "ReflectionClass", "ReflectionMethod", etc), and the arguments that would be sent to the constructor.
Perhaps this deserves a separate issue.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.