Skip to content

Commit

Permalink
[docs] Update deprecation policy for named argument support
Browse files Browse the repository at this point in the history
This is to solve issues identified and raised in MDLSITE-7358
  • Loading branch information
andrewnicols committed Sep 13, 2023
1 parent c1c874b commit 592718d
Showing 1 changed file with 93 additions and 13 deletions.
106 changes: 93 additions & 13 deletions general/development/policies/deprecation.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ tags:

## Why is deprecation needed?

import { ValidExample, InvalidExample, TabItem, Tabs } from '@site/src/components';

In an open source project, the end use of the codebase varies. People may have customisations and plugins that depend on a function that has been targeted for deprecation. Rather than simply removing a function, we must gracefully deprecate the function over a period covered by a number of released versions.

## What is Moodle's deprecation policy?
Expand Down Expand Up @@ -93,29 +95,107 @@ Longer deprecation periods can be considered for functions that are widely used.

## Parameters deprecation

- The deprecated parameter should be renamed to `$unused` and it's default value changed to `null`.
- The respective parameter phpDoc should be updated stating the parameter has been deprecated since version X.X and should not be used any more.
Whilst it is possible to deprecate individual method parameters, care must be taken in doing so.

```
@param null $unused This parameter has been deprecated since 4.0 and should not be used anymore.
```
If a method is overridden then changes to arguments are often not possible at all. This includes changing any type hint, or adding a new default value. Additionally, adding a default value to any argument is only possible if all remaining arguments are optional too.

:::note
:::tip

Remember the phpDoc parameter type should also be updated to `null`.
It is strongly advised to deprecate an entire method, rather than deprecating a single parameter.

:::

- Show a debugging message if that parameter is being provided in the function call:
- Deprecated parameters **MUST** be retained, and **MUST NOT** be renamed
- The respective parameter phpDoc should be updated stating the parameter has been deprecated since version X.X and should not be used any more
- Update all calls to the affected function and either:
- converting to use named parameters, removing the deprecated parameter; or
- removing if at the end of a list of optional parameters.
- Add a mention to corresponding `upgrade.txt` documenting the deprecated parameter should not be used any more
- _Where possible_:
- If a type was previously specified it should be altered to be made nullable
- The default value should be updated to `null`
- If a null value was not previously the default, and a non-null value is provided, a debugging notice should be emitted
- Where it is not possible to make the the type nullable, consider deprecating the method and creating a new one with the updated arguments

:::caution Changes to default values and types

The [Covariance and Contravariance rules for PHP](https://www.php.net/manual/en/language.oop5.variance.php) prevent changes to argument types and defaults when a class is extended and that method overridden.

When deprecating a method which is _likely_ to be extended, you should strongly consider deprecating the entire method and creating a replacement method with the updated arguments instead.

:::

<ValidExample>
<Tabs>
<TabItem value="before" label="Before">

```php
/**
* Greet a user for an example of a deprecated parameter.
*
* @param string $name The name of the individual
* @param int $age The age of the individaul
* @param string[]|null $pets A list of pets that the individual has
* @return The greeting
*/
public function greet_person(
string $name,
int $age,
null|array $pets = [],
}: string {
return sprintf(
"A big, warm, welcome to %s who, at the grand old age of %d, has %d pets!",
$name,
$age,
count($pets),
);
}
```
if ($unused !== null) {
debugging('Deprecated argument passed to ' . __FUNCTION__, DEBUG_DEVELOPER);
}

</TabItem>
<TabItem value="after" label="After" default>

```php
/**
* Greet a user for an example of a deprecated parameter.
*
* @param string $name The name of the individual
* @param null|int $age This parameter has been deprecated since 4.0 and should not be used anymore.
* @param string[]|null $pets A list of pets that the individual has
*/
public function greet_person(
string $name,
null|int $age = null,
null|array $pets = [],
}: void {
if ($age !== null) {
debugging(
'The age argument has been deprecated. Please remove it from your method calls.',
DEBUG_DEVELOPER,
);
}

return sprintf(
"A big, warm, welcome to %s who has %d pets!",
$name,
count($pets),
);
}
```

- Update all calls to the affected function removing the deprecated parameter.
- Add a mention to corresponding `upgrade.txt` documenting the deprecated parameter should not be used any more.
</TabItem>
</Tabs>
</ValidExample>

:::note Previous approach

The deprecation policy for parameter argument deprecation stated that deprecated parameters must be renamed.

This has been changed to no longer allow renaming of arguments because it can lead to fatal errors if the calling code makes use of named parameter arguments.

Named parameter arguments are available from PHP 8.0 onwards.

:::

## See also...

Expand Down

0 comments on commit 592718d

Please sign in to comment.