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

Prevent reporting property.inInterface error when PHP version is 8.4 or alter #3656

Open
wants to merge 3 commits into
base: 2.0.x
Choose a base branch
from

Conversation

jakubtobiasz
Copy link

After reading Ondrej's tweet and playing with PHPStan 2.0 on PHP 8.4, I've found out it reports the property.inInterface error and it is non-ignorable. My first thought was to allow ignoring this error, but I've ended up not reporting this issue at all once the PHP version is 8.4 or later.

@jakubtobiasz jakubtobiasz force-pushed the allow-properties-in-interface-on-php-84 branch 2 times, most recently from 6ffbffd to 853a27b Compare November 23, 2024 07:47
@jakubtobiasz jakubtobiasz force-pushed the allow-properties-in-interface-on-php-84 branch from 853a27b to 5196b92 Compare November 23, 2024 07:57
@staabm
Copy link
Contributor

staabm commented Nov 23, 2024

You need a bit more research on the topic, e.g. it seems the properties on interfaces are only allowed when public

https://3v4l.org/TBaXF

and you need tests for the new cases


/**
* @implements Rule<ClassPropertyNode>
*/
final class PropertiesInInterfaceRule implements Rule
{

private const PHP_8_4_VERSION_ID = 80400;
Copy link
Contributor

Choose a reason for hiding this comment

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

PhpVersion id-checks need to go into a new method of PhpVersion class

@jakubtobiasz
Copy link
Author

jakubtobiasz commented Nov 23, 2024

Hi @staabm,

Thanks for leaving your review 🤠.

You need a bit more research on the topic, e.g. it seems the properties on interfaces are only allowed when public

Right, I knew about it but missed it here.

So in case of protected/private properties:

a) We should just report Interfaces may not include properties.
b) We should report Interfaces may include only public properties. and leave the property.inInterface
c) We should create a separate class with message Interfaces may include only public properties. and id property.nonPublicInInterface
d) anything else

I bet the option c), but I prefer to ask as it's my first time contrib to phpstan :).


At the same time, I guess we should leave this implementation as-is (so property.inInterface is never reported on PHP 8.4 and above) and just create a new rule as mentioned in c).

@ondrejmirtes
Copy link
Member

Please wait for my review before further steps 😊

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.

Please note that in PHP 8.4 not all properties in interface are allowed. Please read the Interfaces section in https://wiki.php.net/rfc/property-hooks.

  1. Only public properties can be in an interface
  2. Only properties with get or set or both hooks can be in an interface.
  3. Property hook in an interface cannot have a body.

The rule should account for all of this.

Please note that the original error message "Interfaces may not include properties." is not exactly correct on PHP 8.4 so all of these situations should have new messages.

Thanks.

src/Rules/Properties/PropertiesInInterfaceRule.php Outdated Show resolved Hide resolved
Comment on lines +24 to +26
if (PHP_VERSION_ID < 80400) {
$this->markTestSkipped('This test requires at least PHP 8.4.');
}
Copy link
Author

Choose a reason for hiding this comment

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

I'm not 100% sure about this approach. In theory it is valid; however, maybe we should mock PhpVersion or set PHP_VERSION_ID by hand.

@jakubtobiasz jakubtobiasz force-pushed the allow-properties-in-interface-on-php-84 branch 6 times, most recently from d6cad22 to a4e23d6 Compare November 23, 2024 16:14
@jakubtobiasz
Copy link
Author

@ondrejmirtes I've implemented all suggestions, and I'm ready for the next ones (if needed 😅).

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.

  1. We don't need to do this in multiple rules. It kind of makes it hard to see what situations are covered or not. A decision tree (series of if-else conditions) in a single rule would be much more readable and understandable. So please do this in a single rule. The right moment to split a rule might come later but not now.
  2. There are cases not covered by your added code. Properties can be abstract even in classes, meaning at least one of their hooks must not have a body.

@jakubtobiasz
Copy link
Author

jakubtobiasz commented Nov 23, 2024

I was focused on interfaces and fixing the issue with 2.0.x not working with PHP 8.4 while creating this PR. Of course, if you decide this PR should cover property hook as a whole, just let me know, and I'll adjust the PR.

However, from my POV, the first and second bullets are conflicted. If we want to add handling abstract classes with the logic inside the NonEmptyPropertyHookRule, I'd recommend leaving it as a separate class (as PropertyInInterface doesn't sound good in case we add abstract classes there).

In my humble opinion, we should stay with split classes as they follow SRP and new features seem to not fit the Property in Interface as we are in the property hook context.

So my suggestion is to leave the separation and cover abstract classes as a separate PR, as in such a case this PR could be merged as a bugfix for 2.0, which would be nice (at least from my perspective) once I want to use 8.4 as soon as possible.

Of course, I'm waiting for your decision 🖖🏻.

@ondrejmirtes
Copy link
Member

I don't want this PR to completely implement property hooks, that's a much bigger project. I just want it to check what I said I want it to check. So to report a wrong declaration that's detectable just by looking at it.

I don't even want this rule to check missing implementation of an abstract hook from a parent. That's a job for a different rule.

Here's a complete list of things that should be reported by this (single) rule class after this PR:

  1. On PHP before 8.4: interfaces can't have properties
  2. On PHP before 8.4: properties can't have hooks
  3. (All following items are on 8.4+). Properties in interfaces must have at least one hook, and all hooks must not have a body.
  4. Non-abstract properties in classes must only have hooks with bodies.
  5. Abstract property can only be in an abstract class.
  6. Abstract property must have at least one hook without a body.
  7. Property in an interface must be public.

I'd understand if you decide not to work on this. In that case you can close this PR.

But in my eyes this is the minimal work needed for the rule to make sense if it's supposed to understand "some properties can now be in interface" which is what you want to achieve.

@jakubtobiasz
Copy link
Author

jakubtobiasz commented Nov 23, 2024

I'd understand if you decide not to work on this. In that case you can close this PR.

Nah, that's not the case. I'll do my best to deliver this :).

I'll use the list you provided while reimplementing it. I guess around the end of the next week.


Just last thing — where should I put the code touching abstract classes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants