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

Command icon 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

mondrake created an issue. See original summary.

mondrake’s picture

Issue tags: +Needs tests

Needs 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-added to some methods of ImageInterface, PHPStan identifies that the implementing methods on the concrete Image class need to get the return type.

mondrake’s picture

Status: Active » Needs review
mondrake’s picture

Assigned: mondrake » Unassigned
Issue tags: -Needs tests

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

nod_’s picture

Issue tags: +no-needs-review-bot

this makes the bot crash, i don't have 10G or ram on it

smustgrave’s picture

Status: Needs review » Needs work

Wonder 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!

mondrake’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: +Needs change record

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

mondrake’s picture

BTW I am not even sure this is for core or rather for mglaman/phpstan-drupal.

smustgrave’s picture

Probably phpstan-drupal right?

oily made their first commit to this issue’s fork.

oily’s picture

Rebased.

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.

cmlara’s picture

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

PHPStan scans your whole codebase and looks for both obvious & tricky bugs. Even in those rarely executed if statements that certainly aren't covered by tests.

-- 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?

smustgrave’s picture

smustgrave’s picture

Status: Needs review » Postponed

Going to go on a limb and say this may be worth waiting for #14 to be decided.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

mondrake’s picture

Status: Postponed » Needs review

We have a main branch open now, so maybe this can be reassessed?

longwave’s picture

Could we extend DebugClassLoader to work around the same-namespace limitation? Might have a play with this.

mondrake’s picture

#18 mean forking Symfony's component or contributing upstream?

longwave’s picture

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

mondrake’s picture

Aha good one

longwave’s picture

@mondrake unit tests are now passing, wondering what you think of this approach before I continue either fixing or ignoring more deprecations?

mondrake changed the visibility of the branch 3486376-introduce-a-return-type-will-be-added to hidden.

mondrake’s picture

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

longwave’s picture

Title: Introduce a @return-type-will-be-added annotation to indicate return type addition in next major; enforce with a PHPStan rule » Extend Symfony DebugClassLoader to report missing cross-module @return types
Issue summary: View changes
longwave’s picture

It'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?

mondrake’s picture

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

longwave’s picture

Status: Needs review » Needs work
longwave’s picture

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

catch’s picture

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

longwave’s picture

Status: Needs work » Needs review

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

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Great step forward, thanks! I tried running pipelines for the other dbms but it looks like I cannot. Would be good running them.

longwave’s picture

Status: Reviewed & tested by the community » Needs work

Good call, looks like we might need a bit more work for the other database drivers.

longwave’s picture

Status: Needs work » Needs review

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

longwave’s picture

Added an initial change record: https://www.drupal.org/node/3579056

mondrake’s picture

Status: Needs review » Reviewed & tested by the community

Looks great.

Mind triggering the test for other databases anyways? I cannot. Just to see the results.

godotislate’s picture

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

mondrake’s picture

fwiw, 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 void to methods that currently have no return type even in the docblock (e.g. setters).

longwave’s picture

Addressed #38, leaving as RTBC.

  • godotislate committed 90c0add2 on main
    test: #3486376 Extend Symfony DebugClassLoader to report missing cross-...
godotislate’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: -Needs change record

Committed 90c0add and pushed to main. Thanks!

Reviewed and published the CR.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.