Problem/Motivation
As per #1158720-69: Improve text for parameter type hinting in function declaration this issue proposes that all new Drupal 9 code should use scalar typehints and return typehints since our minimum PHP version is 7.3.
This is only for new code to avoid BC implications. We will work out how to change existing code (probably in Drupal 10) in #3050720: [Meta] Implement strict typing in existing code.
The related Coding Standards issue explains that there is an existing policy for using strict type hints. See comment #17 for the details.
Proposed resolution
New methods and functions added in Drupal 9 should use scalar typehints and return typehints.
Example (pseudo-code):
public function checkAccess(string $permission): AccessResult {
$access_result = AccessResult::allowedIfHasPermission($this->user, $permission);
return $access_result;
}
Post something on groups.drupal.org/core
Remaining tasks
Add examples to Parameter and return typehinting
Draft and publish a change record that links that coding standards section.
User interface changes
None
API changes
None
Data model changes
None
Release notes snippet
N/a
Comments
Comment #2
larowlanI'm plus one on this, because its going to add more future work if we don't do it sooner.
Comment #3
mondrake+1, I would also suggest to declare nullability of an argument prefixing the type name with a question mark like e.g.
This was introduced in PHP 7.1 so no problem for D9.
Comment #4
xjmI'm on board with this -- my first thought was "This will make backports a pain", but of course we don't backport new code and something calling new code is going to diverge anyway.
What I am foggy on but want to solve is how to add typehints (of all flavors) in a BC way, strategically across core. We can make this decision without that, but the inconsistency will also send us to a place where the DX of what's typehinted and what's not seems random. That's a problem we need to solve, and it'd be nice if we could come up with a way that wasn't "create a duplicate of every interface and class in core" or whatever.
Comment #5
alexpottI think what Symfony did was to implement a debug class loader that uses the documentation typehints and then triggered a deprecation notice saying that in the next version of Symfony these are going to be typehinted. But doing this will require us to properly break between Drupal 9 and Drupal 10. Although that is exactly when breaks should occur in Semver - but we've rather gone down the "your module and code can work with multiple versions" path and this will be less true if we do this.
Comment #6
catchSee discussion on #3050720: [Meta] Implement strict typing in existing code. Not sure about return type hints, but for scalar typehints on interfaces there is a properly forward-compatible approach - just requires a fair bit of shuffling.
Comment #7
longwaveBumping this as #256287: Give roles a description value proposes adding two new methods to RoleInterface and I think they should be typed, because why not?
Is there a good reason *not* to adopt this policy? Existing code has its own challenges but this is fairly straightforward for new code, as far as I can see.
Comment #9
catchBumping this one - I think we should get it documented, and open a follow-up to figure out existing code. But the quicker we do this for new code the less we'll have to change later (although only a fraction of the total).
Comment #10
catchComment #11
alexpott@catch happy to add to the documentation - just unsure of where?
Comment #13
xjmPHP allows adding return typehints to child implementations even if the parent doesn't have one, so D9 contrib code can add the return typehints to their implementations (edit: so long as they are compatible with the return values and docs already present in core) and be forward-compatible with D10.
For the past year or so I've requested return typehints on basically everything new, including child implementations.
A category of thing that gets overlooked a lot is test methods, which could always have a
voidreturn typehint (a pattern we're inheriting from phpunit). Those aren't really providing new information, but OTOH they would sure provide a lot of visibility to remind people to add typehints.Comment #14
xjmAdded initial docs here:
https://www.drupal.org/docs/develop/standards/coding-standards#s-paramet...
It could probably do with some examples.
We should also draft and publish a change record that links that coding standards section.
Related: The added docs partly duplicate part of https://www.drupal.org/docs/develop/standards/object-oriented-code#hinting. That page no longer makes sense as a separate page since "object-oriented code" is no longer a useful distinction from "pretty much all our code". Much of the documentation is furthermore obsolete. We should add the relevant parts to the main coding standards documentation page, and delete the rest along with the separate page.
Comment #15
chi commentedThat needs a coding standard about whether or not to put space in front of
:in return type hint.Comment #16
joachim commentedAgreed.
Though the example so far is wrong anyway -- we'd never have a fully-qualified classname, it would be imported.
The options are:
The style I've seen used on projects I've worked on is space after, so:
though it does mean that where there are no parameters, I always see it like a sideways Homer Simpson:
Comment #17
chi commentedFor the record Drupal Core and Symfony currently use "space after" in ~99% cases. On the other hand Laminas mainly follows "space each side" rule.
With that said, "space after" is the obvious choice.
Comment #19
xjmComment #20
quietone commentedUpdating IS, mostly trying to identity the remaining steps. Updated the example based on feedback in #16.
Comment #21
joachim commentedI've just noticed this problem with the example in the IS:
> public function checkAccess(string $permission): AccessResult {
That's not a scalar typehint, surely? By 'scalar' I assume what is meant is primitive types like int, string, bool.
Comment #22
chi commented> use scalar typehints and return typehints
I think that meant scalar typehints for parameters and non-scalar typehints for return values. I guess it complies with the PHP versions that Drupal 9 is currently supported.
Anyway, I think there is no point to distinguish between scalar and non-scalar typehints nowadays.
Furhtermore, since PHP 8, it does not make sense to apply different policies for parameters, class properties and return types.
Given that Drupal 10 is close it might be better move the issue to 10.x.
Proposed issue title: All new Drupal 10 code should use appropriate typehints wherever possible.
Comment #23
catchYes let's do that.
The only thing with adding them to Drupal 10 is if we're going to backport the new code to 9.4.x/9.3.x we still have to be careful about PHP >= 7.3, but that won't be the case for the 10.1.x branch.
Do we want to include constructor property promotion here or should that be its own issue?
Comment #24
chi commented> Do we want to include constructor property promotion here or should that be its own issue?
I think it needs its own issue.
The current issue is two years old and so far no one objected. So I suppose having change record is the last step needed to move this to RTBC.
Comment #25
chi commentedOne thing that is not covered yet is what to do with PHPDoc annotations. The has become obsolete.
In the example below the property annotation is absolutely useless. Actually the whole comment makes no sense.
Comment #26
catch@chi that's got a lot to do with constructor property promotion, the entire code block can go once we do that.
Comment #27
longwaveOnce Drupal 9 is EOL and we don't have to think about backports I can foresee an issue where we convert all constructors in core to use property promotion, hopefully with the aid of a Rector rule.
Comment #28
chi commentedWell, that's actually not only about class properties. Method parameters and return types also have lots of redundant annotations.
I've recently started ommiting all doc comments for methods, properties and constants. That accelerated develpment ~20%, I guess.
Comment #29
xjmDocumentation typehints can add information that PHP typehints do not yet support, especially for array structures. It's very useful to document
string[][],mixed[], etc.Comment #30
chi commentedRight, for those cases we can keep the documentation which by the way can be written using PHPStan or
#[ArrayShape]notation.Comment #31
longwaveIs all that is left to do here to write the change record? I think in practice we are already doing this in new code, though I recently proposed the same for class properties in #3291517: [policy, no patch] Use type declarations for new class properties.
Comment #32
moshe weitzman commentedTotally agree that we should remove redundant doxygen for methods, properties and constants. It is quicker to read and write.
Comment #33
smustgrave commentedAnyone point out an example change record that doesn't have code?
Comment #34
mondrake#29 and #30 see #3309010: Support PHPDoc Types in @param @var @return annotations
Comment #35
Manoj Raj.R commentedTotally agree on the proposed solution.
New methods and functions added in Drupal 9 should use scalar typehints and return typehints.
"space after" looks more for the obvious choice
Comment #36
moshe weitzman commentedDo we really need a change record for an MR that is policy and has no code change at all? This has been sitting near the finish line for a year.
Comment #38
quietone commentedIn the list of reasons for adding a change record I don't see anything that covers this. The closest is "For Coding standard issues when the rule requires significant code changes" but that would apply to existing code, not new code. Based on that I am removing the tag.
We have been doing this for some time and the Coding Standard docs have changed. Unless I am missing something there is nothing more to do in this issue.
Comment #39
longwaveGiven this has been sitting here for two years and in practice we have been doing it already, a change record seems pointless now.
Comment #41
xjm.
Comment #42
quietone commentedChanging to latest version when this was closed.