Problem/Motivation
In #3470913: Ensure getWidth()/getHeigth always return ?int we are using the issue to try and introduce a process to signal a native return type will be added to interface methods in next major release (and in #3470951: Add return typehints for getWidth()/getHeigth in interfaces we have the follow up to actually implement the change in the next major). The concept is that the intended type is indicated to extensions, and given return type covariance allows them to implement the type in advance of the change on interface/abstract/base class, we prod contrib/custom to do the change to be ready when next major (implementing the type) is out.
More or less the same intent in #3333824: Enable existing interfaces to add return type hints with a deprecation message for implementors.
There are discussion to support this through Symfony's DebugClassLoader - see [ErrorHandler] DebugClassloader: introduce an annotation to signal definite intent to add/change the return typehint of a method and a PR [ErrorHandler] Add support for @return-type-will-change. Edit Dec 27 2024: The Symfony classloader proposed changes were closed without commit
This issue proposes to extend the DebugClassLoader to treat different Drupal namespaces separately. Currently Symfony considers the \Drupal namespace to own all Drupal code and so does not report return type issues between modules.
Remaining tasks
Review approach
Ignore existing failures in core code and modules
Fix up existing failures in test code
User interface changes
Introduced terminology
API changes
Data model changes
Release notes snippet
Issue fork drupal-3486376
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mondrakeNeeds tests for the rule and some cleanup, but I am opening it for review of the concept.
This shows how adding the
@return-type-will-be-addedto some methods ofImageInterface, PHPStan identifies that the implementing methods on the concreteImageclass need to get the return type.Comment #4
mondrakeComment #5
mondrakeReverted changes to code that were meant to showcase the rule. The example pipeline where the PHPStan output is visible is https://git.drupalcode.org/issue/drupal-3486376/-/pipelines/333846
Added PHPUnit tests for the PHPSTan rule.
Comment #6
nod_this makes the bot crash, i don't have 10G or ram on it
Comment #7
smustgrave commentedWonder if this counts as an API change?
Or least warrants a CR?
Only moving to NR for the pipeline revert as not sure it's in scope.
If can rebase too since it's kinda older (sorry took so long to look at)
If you are another contributor eager to jump in, please allow the original poster @mondrake at least 48 hours to respond to feedback first, so they have the opportunity to finish what they started!
Comment #8
mondrakeIt certainly needs a CR to explain how to use the annotation, but let's get more reviews and consensus before writing one and letting it go stale because of later changes of direction.
The path addition in CI is needed to get the rule tested (HEAD is currently checking only changes to file in the base path of Drupal's PHPStan-related stuff).
The Symfony classloader proposed changes were closed without commit; this remains the only approach currently workable to address this issue.
Comment #9
mondrakeBTW I am not even sure this is for core or rather for mglaman/phpstan-drupal.
Comment #10
smustgrave commentedProbably phpstan-drupal right?
Comment #12
oily commentedRebased.
Let's create a first version CR. It will be in draft state and by using the revision log any future edits can be tracked and logged.
Comment #13
cmlaraI have put some comments on Slack however making them more formal:
As a Contrib maintainer I do not see the value.
For me PHPStan exists to identify bugs in code, not future compatibility problems. Not having a return type when the parent method itself does not have a return type is not a bug.
-- https://phpstan.org/
Looking at a few of the projects I maintain there is a good chance there will be a different branch for D12 and my current branches will never need to implement a hard return type (although in many cases I already added strong code typing as part of implementing Level 9 PHPStan).
A 'feature' like this will just be noise to me, and distract from working on issues more pressing (security hardening, bug fixes, and features).
My opinion is that #3513474: Consider always having the next major branch open is the better method to implement, it would allow modules to opt-in to scanning against the next major core branch early to identify where they need to make changes, and reduce creating future technical debt (no need to come back in D12 to remove the type-hint warning).
As an aside. I have suggested in Slack that if this is felt to be useful it might be worth considering putting this in its own third party repository to allow it to be available to others as a way for the Drupal Community to "give back" for all it receives. If this does not make sense to be an independent project I would suggest that should be treated as a warning that indicates other methods should be preferred.
Looking at the MR itself: I note the presence of
// @phpstan-ignore phpstanApi.method, should code that uses PHPStan off-api be allowed considering the maintenance burden that could create?Comment #14
smustgrave commentedShould this be postponed on #3513474: Consider always having the next major branch open
Comment #15
smustgrave commentedGoing to go on a limb and say this may be worth waiting for #14 to be decided.
Comment #17
mondrakeWe have a
mainbranch open now, so maybe this can be reassessed?Comment #18
longwaveCould we extend DebugClassLoader to work around the same-namespace limitation? Might have a play with this.
Comment #19
mondrake#18 mean forking Symfony's component or contributing upstream?
Comment #21
longwaveMaybe upstream would accept a configuration option to handle namespace prefixes, but we can also just extend it ourselves - see MR!14882.
This MR was partially written by Claude Code.
Comment #22
mondrakeAha good one
Comment #23
longwave@mondrake unit tests are now passing, wondering what you think of this approach before I continue either fixing or ignoring more deprecations?
Comment #25
mondrakeLooks great, let's go for it. Did not think about it tbh - was first trying to change upstream, then fell back on a PHPStan alternative. But if this works it's how it should have probably been since the beginning :)
Did not do a code review, will do when you're ready.
Wondering if we could couple this with a PHPStan rule support anyway, but that could be discussed in a follow up.
Hiding MR !10111 at this point. An IS update would help.
Comment #26
longwaveComment #27
longwaveIt's getting hard to draw the line on what to fix here and what to fix in followups for test modules. Maybe we just add all test modules to the skip set and fix them in batches?
Comment #28
mondrake#27 pretty usual…
IMHO better introduce the feature with minimum change here, and fix in follow ups. It will take time to get all of that done.
Comment #29
longwaveComment #30
longwaveGiven this is going to be quite disruptive for contrib and custom code, maybe we want to commit to 12.0 or even wait for 12.1, and announce it in some way? (maybe via a core blog post)
Comment #31
catchI would probably go for 12.0 here, not many modules have updated for 12.x compatibility yet so it's something that can be tackled alongside other changes. Seems a bit too disruptive for 11.4, we'd break a lot of CI pipelines even though sites would be OK.
This unfortunately means we won't be able to actually bring in the return type hint changes everywhere until 13.0 but at least we can prepare everything for then.
Comment #32
longwaveHopefully this is green now. We can pick off the test fixes in followups, then wait for contrib to fix their deprecations, and finally add return types everywhere in the next major.
Comment #33
mondrakeGreat step forward, thanks! I tried running pipelines for the other dbms but it looks like I cannot. Would be good running them.
Comment #34
longwaveGood call, looks like we might need a bit more work for the other database drivers.
Comment #35
longwave@mondrake actually the fails in other database drivers all look like false positives.
@quietone thanks for the review, I reworded "module" to "extension" in all cases.
Comment #36
longwaveAdded an initial change record: https://www.drupal.org/node/3579056
Comment #37
mondrakeLooks great.
Mind triggering the test for other databases anyways? I cannot. Just to see the results.
Comment #38
godotislateOne question about whether any of the test subclass methods should have the
{@inheritdoc}annotation to be more representative of what code actually looks like. The detection in the loader ignores that annotation, but maybe a test case can make that clear.Comment #39
mondrakefwiw, I tried the next step in #3579258: Fix DebugClassLoader deprecations in database driver modules, fixing the database driver modules to be consistent with the lib Database classes.
One thing I wonder is whether we should review the lib classes themselves too as part of that follow-up work - for instance to introduce
@return voidto methods that currently have no return type even in the docblock (e.g. setters).Comment #40
longwaveAddressed #38, leaving as RTBC.
Comment #43
godotislateCommitted 90c0add and pushed to main. Thanks!
Reviewed and published the CR.