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

allow @var phpdocs before return statements #5109

Conversation

bendavies
Copy link
Contributor

This PR stops phpdocs before return statements from being converted to comments, if they are a @var definition.

This is a common requirement with SA tooling to assist the tool with the return type.
e.g:
https://psalm.dev/r/0de99e28de

<?php

interface EncoderInterface
{
    /**
     * @return bool|float|int|string
     */
    public function encode(array $data);
}

function returnsString(EncoderInterface $encoder): string
{
    /** @var string */
    return $encoder->encode(
        ['invoice_number' => 1],
    );
}

We don't want /** @var string */ converted to // @var string in this instance.

Thanks.

@bendavies bendavies changed the base branch from 2.16 to 2.15 August 11, 2020 14:26
@julienfalque
Copy link
Member

Alternative proposal related to this: #4649.

@ostrolucky
Copy link
Contributor

ostrolucky commented Aug 11, 2020

Similar was rejected before #3611

@bendavies
Copy link
Contributor Author

seems like a slightly different use case?
no 3rd party annotations here.

@ostrolucky
Copy link
Contributor

It's not a problem of 3rd party annotations, but interpretation of phpDocumentor specs. In linked ticket, it was interpreted that not specifying structural element in inline phpDoc, it's not conforming with phpDocumentor specs. In case of @var, this is even more strictly prohibitted. From https://docs.phpdoc.org/latest/references/phpdoc/tags/var.html

Syntax

@var [“Type”] [$element_name] [<description>]

The @var tag MUST contain the name of the element it documents.

@bendavies
Copy link
Contributor Author

bendavies commented Aug 11, 2020 via email

@bendavies
Copy link
Contributor Author

bendavies commented Aug 14, 2020

I would just point that that phpstorm, phpstan and psalm all support this syntax.

@GrahamCampbell
Copy link
Contributor

I think this fixer should just be turned off tbh, if you want that. This fixer was designed to enforce PSR-5 doc positioning. If you want to document types for static analyzers, then you probably don't want this fixer. I no longer use it, myself.

@fluffycondor
Copy link

fluffycondor commented Aug 20, 2020

In case of @var, this is even more strictly prohibitted. https://docs.phpdoc.org/latest/references/phpdoc/tags/var.html
The @var tag MUST contain the name of the element it documents.

But on the next line there is following:

An exception to this is when property declarations only refer to a single property. In this case the name of the property MAY be omitted.

A return statement operating only single property at once, so there is no need in name.

@GrahamCampbell
Copy link
Contributor

A return statement is not a single property. A single property is this:

class Foo
{
    /** @var string */
    public $foo; // <- i am a single property
}

The phpdocumentor spec does not allow documentation above return statements.

@GrahamCampbell
Copy link
Contributor

As I said before, in a different issue, at length, we have to decide if we want to follow phpdocumentor or static analyzers. phpdocumentor will never support stuff that makes the code easier to analyzem because its job is to document the public interface of stuff, not the internals. phpdocumentor says phpdoc can only appear before structural elements.

@mfn
Copy link

mfn commented Aug 20, 2020

You could argue that static analyzers started to miss-use phpdoc for this, but there's really no alternative and that's how "it evolved".

The practical choice would be to go separate paths, but what about interop then? Competitors alternatives to php-cs-fixer might come up with different ideas/approaches and then the fragmentation gets worse.

PS: I'm leaning towards being practical, but…

@muglug
Copy link

muglug commented Aug 20, 2020

I think PHP-CS-Fixer should follow the fairly-widely-adopted community standard.

But I also think it's a shame that @var was chosen for inline things – something like

function returnsString(EncoderInterface $encoder): string
{
    /** @infer string */
    return $encoder->encode(
        ['invoice_number' => 1],
    );
}

is much more appropriate.

@ondrejmirtes
Copy link

People are used to write @var above any line of code expecting it to work or at least do something they want. In PHPStan I had to add support for @var above if statements, whiles, throws, switches, returns, echoes...

I dislike inline @vars because they shouldn't be necessary at all - the source should already have the correct type when obtaining the value. They're also used for different reasons which makes it impossible to validate them - sometimes they're used to narrow down types, but sometimes also to widen or even change the types totally in case the source's PHPDoc is wrong...

@ondrejmirtes
Copy link

They're also used to will nonexistent variables into existence when used in the global scope, typically view files. A total mess :)

@muglug
Copy link

muglug commented Aug 20, 2020

Yeah, that's why I think /** @infer string */ should be used instead as it doesn't muddy the waters (I'm happy to add support for this in an upcoming version of Psalm).

@fluffycondor
Copy link

I dislike inline @vars because they shouldn't be necessary at all - the source should already have the correct type when obtaining the value

If there is typehinted a parent class as return value in a parent method's signature, how would I tell to PHPStan that I 100% sure that in the subclass I will get a subclass of return value?
It is widely used in Repository pattern.

// find() is overwritten above to ignore soft-deleted entities
public function findDeleted($id, $lockMode = null, $lockVersion = null): ?Project
{
    // it returns object|null by default,
    // I will get "should return Project|null but returns object|null" from PHPStan
    return parent::find($id, $lockMode, $lockVersion);
}

@ondrejmirtes
Copy link

@fluffycondor You have many tools at your disposal:

All of them are better than copying @var over your codebase and them becoming inconsistent over time...

Copy link
Contributor

@kubawerlos kubawerlos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR changes the behaviour for a fixer, not fixing an issue, for many people the "fix" that this PR disables may be very much expected.

I would suggest adding an option ignore_before_return (defaults to false to keep backward compatibility) for anyone wanting changes from this PR.

@keradus keradus changed the base branch from 2.15 to 2.16 November 20, 2020 15:22
@keradus keradus changed the base branch from 2.16 to master December 17, 2020 13:37
Copy link
Member

@julienfalque julienfalque left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO this is a de facto standard so we should support it. But I agree with @kubawerlos, we should add an option for this behavior change.

@@ -190,6 +190,10 @@ private function isStructuralElement(Token $token)
*/
private function isValidControl(Tokens $tokens, Token $docsToken, $controlIndex)
{
if ($tokens[$controlIndex]->isGivenKind(T_RETURN) && false !== stripos($docsToken->getContent(), '@var')) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This condition will be true for any tag that contains @var, e.g. @variable. Please add such tag as a new test case to make sure it is still changed.

@SpacePossum
Copy link
Contributor

I agree this is a de facto standard so we should support it, I see little value in having it behind some option as I consider this a bug fix.

@GrahamCampbell
Copy link
Contributor

I agree now, too. Disregard my earlier comments, or consider them in the context of 2020. ;)

@Wirone Wirone added the status/to verify issue needs to be confirmed or analysed to continue label Jun 6, 2023
@Wirone Wirone marked this pull request as draft July 2, 2023 20:21
@Wirone Wirone removed the status/to verify issue needs to be confirmed or analysed to continue label Jul 2, 2023
@Wirone Wirone added the status/rebase required PR is outdated and required synchronisation with main branch label Jul 2, 2023
@keradus
Copy link
Member

keradus commented Dec 24, 2023

closing due to merge of #7402

@keradus keradus closed this Dec 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status/rebase required PR is outdated and required synchronisation with main branch
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet