Skip to content
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

How to getUsesTagValues when annotating use directly? #269

Closed
distantnative opened this issue Mar 1, 2025 · 5 comments
Closed

How to getUsesTagValues when annotating use directly? #269

distantnative opened this issue Mar 1, 2025 · 5 comments

Comments

@distantnative
Copy link

Thanks for the great work. I am hitting one wall in a project currently:

How can I get the uses tag values when the docblock comment is directly annotating the use as in the documentation:

/** @template T of Foo */
class Bar
{
    /** @use Part<T> */
    use Part;
}

I can get the class docblock from the class reflection, but how could I include this use annotation as well? Thank you!

@ondrejmirtes
Copy link
Member

What are you trying to write? Are you using phpdoc-parser directly, or are you in PHPStan writing custom rule or other extension?

@distantnative
Copy link
Author

distantnative commented Mar 1, 2025

I am using phpdoc-parser directly. We are basically using it to automatically generate docs for our classes. This works really well for normal parameters, return types. We recently started to add templates/generics and I would like to support this for our automatic docs as well. I have been able to do this successfully for @template and @extends in the class docblock. However, to fully resolve all templates, I would also need to parse the @use annotation for traits. But since this isn't directly in the docblock, I was wondering if there is an (semi-)easy will to retrieve those nevertheless.

Minimal example:

class Something
{
}
/** @template T */
trait Bar
{
    /** @returns T */
    public function anything():
    {
        //…
    }
}
class Foo
{
    /** @use Bar<Something> */
    use Bar;
}

I'll need to parse @use Bar<Something> somehow - so I can include it in my own resolving logic to display our docs as Foo::anything(): Something. I know phpdoc-parser doesn't do the resolving/interpretation part, I am just wondering about parsing/retrieving the use tag.

@ondrejmirtes
Copy link
Member

I have some suggestions for you.

  1. Have you looked at ApiGen? You could either replace your solution with that because it's also used for generating documentation from PHPDocs, or you could at least inspect its source code to get some inspiration, because it also uses phpstan/phpdoc-parser and supports modern features like generics etc.: https://github.com/ApiGen/ApiGen
  2. You're right, phpstan/phpdoc-parser only offers the AST. There's a lot more code involved in actually interpreting the AST which is only in PHPStan.

Links to some classes involved:

Importantly, a lot of PHPStan internals are involved in decision logic about how to interpret PHPDocs. The type system, the reflection, they all play a part. For example, if you have a type like Collection|Foo[], PHPStan needs to ask reflection whether Collection is iterable, and based on that it decides whether the type means Collection or array or Collection that iterates over Foo. This is described in the docs: https://phpstan.org/writing-php-code/phpdoc-types#iterables

All that said, I'd like to suggest you a completely different approach. For your job, you don't need to use phpstan/phpdoc-parser directly. If you decide that ApiGen does not meet your needs and you'd like to still implement this by yourself, you can use the knowledge PHPStan has implemented in order to do this.

The idea is that you'd write custom PHPStan collectors (https://phpstan.org/developing-extensions/collectors) to analyse your codebase and collect all required information. Then you could export this information into JSON and then use your own tool to generate documentation out of this JSON.

You could hook your custom collectors onto nodes like InClassNode (https://apiref.phpstan.org/2.1.x/PHPStan.Node.InClassNode.html), InTraitNode (https://apiref.phpstan.org/2.1.x/PHPStan.Node.InTraitNode.html - invoked for each trait use), InClassMethodNode (https://apiref.phpstan.org/2.1.x/PHPStan.Node.InClassMethodNode.html), InFunctionNode (https://apiref.phpstan.org/2.1.x/PHPStan.Node.InFunctionNode.html). They all offer easy access to reflection and reading the information you'd need.

Data from these collectors would be aggregated in a custom rule that hooks on CollectedDataNode and is called a single time after the analysis. Its purpose is to re-format the collected data for the custom JSON formatter. The formatter would then output the final JSON for your HTML (or whatever) generator to read.

This is a tried-and-tested approach. It's used to generate this page (https://phpstan.org/error-identifiers). Here's the source code: https://github.com/phpstan/phpstan/tree/2.1.x/identifier-extractor. Here's how it's called: https://github.com/phpstan/phpstan/blob/f87b890493472125fefcc6900765e95302c6d87c/.github/workflows/extract-identifiers.yml#L70

Another project uses this approach to generate a call map (who calls who in a project): https://gitlab.com/stella-maris/callmap

@distantnative
Copy link
Author

Thank you for the super detailed answer. I fear those other generators won't work for us as our docs are highly integrated and a generic generator won't work too well. We'd also love to avoid static JSON files as the docs are running on the same CMS they are documenting. So direct reflection has slowed us to offer a real nice experience, both for users as well as us developers. But I'll dig into the various links you provided and surely there'll be some more things to learn from them for our own code.

Copy link

github-actions bot commented Apr 3, 2025

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 3, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants