-
Notifications
You must be signed in to change notification settings - Fork 3.2k
#52217 - PHPStan config and fixes #853
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
Conversation
# Conflicts: # src/wp-admin/includes/class-wp-importer.php
jrfnl
left a comment
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.
While I'm not against the principle of adding more QA tools to our tooling chain, I'm not a fan of PHPStan for WordPress.
PHPStan - and Psalm as well for that matter - work best with well-typed code bases, the stricter the better.
WordPress is most definitely not such a code base, so the noise from false positives will be huge.
These are tools primarily aimed at modern PHP, not legacy codebases, and some of the results will include suggestions for modernizing code which cannot be applied to WP due to the low minimum PHP version we still have to deal with.
Also please realize that including the tooling could encourage people who are not as aware of the minimum PHP version for WP, to start sending in patches for things which cannot be applied in WP yet, causing wasted time both for the contributors who created the patches as well as for other maintainers having to explain - time and again - why the patch cannot be accepted.
I do think it's a good idea to do intermittent, ad-hoc runs with tools like PHPStan, Psalm, Exakat and other tools, but adding it as a dependency is a no-go, if for no other reason than the conflicting minimum PHP requirements.
I'm actually surprised the CI runs aren't breaking on this as it is, but haven't looked into that.
| */ | ||
| global $post_type; | ||
|
|
||
| /** @var WP_Terms_List_Table $wp_list_table */ |
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.
What value do these type of comments add (other than to satisfy PHPstan) ?
(here and everywhere else in this patch)
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.
Our list tables aren't LSP compatible, so any code editor or IDE that provides intellisense (in addition to PHPStan) raises errors further down when accessing methods or properties that only exist on certain WP_List_Table sub-classes. These inline type declarations avoid those errors.
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.
Which, in my humble opinion, is doing things the wrong way around.
The LSP violations should be fixed and @hellofromtonya and me have been discussing the problem with those in our live stream sessions recently as well.
Adding comments to avoid addressing the real problem, especially comment which are only recognized by a select set of IDEs/tooling, just doesn't make any sense whatsoever to me.
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.
That is indeed the preferred and correct way to address the problem, but realistically can that be fixed? And can it be enforced in future list tables? These classes are a free-for-all due to the dynamic method names used by columns and the arbitrary methods introduced in sub-classes.
There's nothing wrong with specifying the type of a variable in a PHPDoc where it cannot be determined statically. In this case it has the same effect as directly instantiating the concrete class instead of instantiating it via the _get_list_table() wrapper (which is little more than a non-standard implementation of an autoloader).
| * @param callable $admin_image_div_callback Optional. Custom image div output callback. | ||
| */ | ||
| public function __construct( $admin_header_callback = '', $admin_image_div_callback = '' ) { | ||
| public function __construct( $admin_header_callback = null, $admin_image_div_callback = null ) { |
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 could be considered a behavioral change, especially as the class is not final and may be extended in userland plugin/theme code.
To keep the existing behaviour, the property default values would need to be set to '' instead of changing the default values of the parameters in the constructor, but considering it is supposed to be a callable I agree that is counter-intuitive.
All the same, could you explain why the choice was made for doing it the other way around ?
Also: the places where these callables are used in the class do not use proper type checking. If anything, I'd advocate for the loose type if ( $this->admin_image_div_callback ) checks to be replaced with checks against is_callable().
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 these classes can be extended, but the default value of an untyped parameter does not affect its signature, so it's safe to change this in the parent class and cause the sub-classes to diverge. Example: https://3v4l.org/8g5df
The choice to switch to a null default value is to make the parameter a nullable callable. A default value of '' means the parameter is actually callable|string and that doesn't help anybody. I agree that the loose checking could be enhanced with is_callable() checks, but that's outside the scope of the changes I want to make 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.
I understand you want to limit the scope, but the is_callable() change is actually a useful change, while this isn't.
| * @param callable $admin_image_div_callback Optional. Custom image div output callback. | ||
| */ | ||
| public function __construct( $admin_header_callback, $admin_image_div_callback = '' ) { | ||
| public function __construct( $admin_header_callback, $admin_image_div_callback = null ) { |
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.
Same remark as made for src/wp-admin/includes/class-custom-background.php applies here.
| * Undocumented variable | ||
| * | ||
| * @since ?.?.? | ||
| * @var float |
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.
Blank line comment line needed between the above two tags (same applies to the $error property docblock).
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.
Thanks! I need to finish these.
| @@ -0,0 +1,100 @@ | |||
| <?php | |||
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.
Why is this placed in the tests directory ? This has nothing to do with testing WP.
Note: I realize @aaronjorbin and my comments about this are at odds with each other. Maybe a more general discussion should be had about what to do with tooling config files.
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 where best to put this, but static analysis is testing so I don't think it's an inappropriate location. Suggestions welcome though.
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 think this belongs in the tests directory since I view static analysis as a form of testing (which seems to jive with @johnbillion since he said it just above me). I view automated testing as anything that automates a process of ensuring code quality.
| @@ -0,0 +1,100 @@ | |||
| <?php | |||
| // phpcs:ignoreFile | |||
|
|
|||
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 list looks like it will quickly go out of date and add maintenance burden. Can a more dynamic solution be found for this ?
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.
Good point but I think the maintenance burden is low. Constants are not introduced very often and this is not a complete list of all constants, just ones which are unconditionally accessed by the files that are scanned by PHPStan.
tests/phpstan/bootstrap.php
Outdated
| @@ -0,0 +1,100 @@ | |||
| <?php | |||
| // phpcs:ignoreFile | |||
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 file should be added to the phpcs.xml.dist file for ignoring instead of having an inline comment.
Problems of using PHPStan as an inline inspection tool
I agree. I'd like to echo and add to @jrfnl's concerns. PHPStan will generate a huge volume of false positives. Why is this a problem?
Where does PHPStan fit into the project?
I agree. This tool and others can serve WordPress as a periodic auditing tool. What about this PR?There are valid fixes and improvements in this PR:
By splitting out the work we can ensure these are not lost (along with the extensive code reviews) in the debate about whether to use PHPStan as an inline CI tool or not. |
|
@hellofromtonya I've addressed your main concern about the impact of introducing static analysis in the comments on https://core.trac.wordpress.org/ticket/52217, but in short I don't believe that it introduces the sort of significant burden and large number of false positives that you've seen on https://core.trac.wordpress.org/ticket/51423 . This ticket aims to start at level 1, whereas 51423 aims to tackle type related problems that are several steps ahead of where we are now. |
|
I'm going to update the description of this PR with notes about each change. I realise that it's not clear why quite a few of these changes have been made. |
…kes care of returning boolean false in this case.
Co-authored-by: Juliette <663378+jrfnl@users.noreply.github.com>
…in [1543] and [6426].
# Conflicts: # composer.json # composer.lock
# Conflicts: # src/wp-includes/class-wp-http-cookie.php # src/wp-includes/class.wp-dependencies.php # src/wp-includes/widgets.php # src/wp-includes/wp-db.php
|
This is an interesting point and seems easy to add to the project, what can we do to push it? |
Trac ticket: https://core.trac.wordpress.org/ticket/52217
This introduces config for PHPStan with plenty of exclusions so we can identify real issues that need to be fixed.
Changes:
@vartags for variables assigned the return value of_get_list_table(). This is because the concrete return value of_get_list_table()cannot be known statically, and not all sub-classes ofWP_List_Tableuse the same methods. This is essentially the same as directly instantiating the class passed to the$classparameter and means code editors as well as static analysis knows the correct class.remove_filter()callable. This makes the parameters nullable callables, instead ofcallable|string.touch()method fromWP_Filesystem_SSH2. This method should return a boolean, so removing it means thetouch()method from the parent class takes over and correctly returns boolean false.