-
Notifications
You must be signed in to change notification settings - Fork 545
Friend functions #268
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
Friend functions #268
Conversation
d32a628 to
57ec0b7
Compare
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.
I'm not sure how to approach that this can be false. Should it also result in an early exit?
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.
Yes, it means you're calling some internal PHP method.
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.
Makes sense :)
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 rule needs to be added to a level, I'd prefer level2 (config.level2.neon).
src/PhpDoc/PhpDocNodeResolver.php
Outdated
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.
Other tags are filtered to the correct node with array_filter., it doesn't crash on wrong behaviour
src/PhpDoc/ResolvedPhpDocBlock.php
Outdated
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 property should be mentioned in merge method too.
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.
I assume it should also read $result->friends = [] as friendship is not inherited? That's what I'm going with now
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.
Or prolly not, added some cases to the test and turns out this way it should be inherited :)
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.
Yes, it means you're calling some internal PHP method.
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.
There should be a test with something like @friend bool to see that this code really works.
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.
I'll filter these out in \PHPStan\PhpDoc\PhpDocNodeResolver::resolveFriends and make FriendTag always return TypeWithClassName. Will also add a test 👍
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.
I'd like array_values here too.
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.
Arguably these methods shouldn't be called outside of classes at all so this should be reported?
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.
Will be :)
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.
%s::%s() for consistency + . at the end.
Nice job! 👍 It's really encouraging when someone that can find their way around PHPStan internals really fast shows up :)
Additionally, we could implement a separate rule that validates @friend above a method:
- That the mentioned class exists (with ReflectionProvider injected through constructor)
- That the frient method exists.
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.
I'm having a hard time figuring out why this violation doesn't pop up. I'll try to debug some more, pushing this already for other changes
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.
$docComment = $method->getDocComment(); returns null for extended method and then rule is exiting early due to this. Is there a way to get a ResolvedPhpDocBlock for a method that would include all parents resolved?
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.
@ondrejmirtes any hint please?
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.
Sorry, didn't notice you have a question here. Try something like this:
--- a/src/Reflection/Php/PhpClassReflectionExtension.php +++ b/src/Reflection/Php/PhpClassReflectionExtension.php @@ -498,6 +498,7 @@ class PhpClassReflectionExtension $methodReflection->getName(), $positionalParameterNames ); + $docComment = $resolvedPhpDoc->getPhpDocString(); $phpDocBlockClassReflection = $declaringClass; } } else {
Although I'm not sure + I don't know why the getPhpDocString() isn't nullable, it might be returning an empty string instead (which we should change to null 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 definitely won't work, but at least I showed you the place that needs fixing :)
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.
(I'm in favor of having the inherited phpDoc be returned from a child's method getDocComment.)
8f0f4af to
c3446d8
Compare
Alternatively what I'd like:
- Make this PR green (besides the stuff that's currently failing on master, sorry about that). It won't support PHPDoc inheritance which is fine (remove tests about that).
- Make another PR that makes MethodReflection::getDocComment() return inherited PHPDoc as well, because that's a separate feature.
- Make a PR that adds the tests that will now be green from 1).
c3446d8 to
a132192
Compare
@ondrejmirtes done! I think all that fails is not my fault :) From the original plan I had in the PR description I have removed a rule for static method calls as that just turned out to be something totally different when trying to determine a callee... so if that's fine with you I'll make a separate PR for that as a step 4
f54fd5f to
eca550a
Compare
d45166a to
3526237
Compare
efd31ce to
0471f87
Compare
97c2f21 to
a03a78f
Compare
ddd20b4 to
95d480b
Compare
20539b3 to
9bb13b0
Compare
Closing as there's an external package providing the functionality: https://github.com/DaveLiddament/php-language-extensions#friend
Uh oh!
There was an error while loading. Please reload this page.
First (completed) version of friend functions, closes phpstan/phpstan#3565
As for "What if we're in the same class for example?" I took the whitelist approach - if a user specifies
@friendtag then they want to control who may access given method and it makes sense to restrict calls from same class as well. For instance from my original example, I wouldn't want anybody to callCategory::addProductfrom anywhere but theProduct::addCategory. Also being friends is not inherited like showcased in the test.Open issues that come to my mind:
FriendTagcreation be hardened somehow?FriendTags that containTypeWithClassNamein the rule class. Do you see a better place or is it ok?@friendannotations