Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Closed
malarzm wants to merge 2 commits into phpstan:1.5.x from malarzm:friend-functions-v2
Closed

Conversation

@malarzm
Copy link
Contributor

@malarzm malarzm commented Jul 5, 2020
edited
Loading

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 @friend tag 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 call Category::addProduct from anywhere but the Product::addCategory. Also being friends is not inherited like showcased in the test.

Open issues that come to my mind:

  • There's one issue reported by PHPStan I'm not sure how to approach
  • Should FriendTag creation be hardened somehow?
  • I'm not fond of filtering FriendTags that contain TypeWithClassName in the rule class. Do you see a better place or is it ok?
  • Implement a rule for validating @friend annotations

mvorisek and canvural reacted with thumbs up emoji
@malarzm malarzm force-pushed the friend-functions-v2 branch 2 times, most recently from d32a628 to 57ec0b7 Compare July 5, 2020 14:59
Copy link
Contributor Author

@malarzm malarzm Jul 5, 2020

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?

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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.

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020

Choose a reason for hiding this comment

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

Makes sense :)

Copy link
Member

@ondrejmirtes ondrejmirtes left a 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).

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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.

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020

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

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020

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 :)

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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.

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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.

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020

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 👍

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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.

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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?

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020

Choose a reason for hiding this comment

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

Will be :)

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 5, 2020

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.

Copy link
Member

Nice job! 👍 It's really encouraging when someone that can find their way around PHPStan internals really fast shows up :)

malarzm reacted with heart emoji

Copy link
Member

Additionally, we could implement a separate rule that validates @friend above a method:

  1. That the mentioned class exists (with ReflectionProvider injected through constructor)
  2. That the frient method exists.

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020

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

Copy link
Contributor Author

@malarzm malarzm Jul 6, 2020
edited
Loading

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ondrejmirtes any hint please?

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 10, 2020

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).

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 10, 2020

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 :)

Copy link
Member

@ondrejmirtes ondrejmirtes Jul 10, 2020

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.)

Copy link
Member

Alternatively what I'd like:

  1. 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).
  2. Make another PR that makes MethodReflection::getDocComment() return inherited PHPDoc as well, because that's a separate feature.
  3. Make a PR that adds the tests that will now be green from 1).

Copy link
Contributor Author

malarzm commented Jul 12, 2020

@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

Copy link
Contributor Author

malarzm commented Jun 23, 2022

Closing as there's an external package providing the functionality: https://github.com/DaveLiddament/php-language-extensions#friend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@ondrejmirtes ondrejmirtes ondrejmirtes requested changes

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Friend functions

AltStyle によって変換されたページ (->オリジナル) /