rfc:renamed_parameters
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
rfc:renamed_parameters [2020/07/24 13:51] – created carnage | rfc:renamed_parameters [2020/08/09 17:23] (current) – fix typo: "depreciation" -> "deprecation" imsop | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== PHP RFC: Renamed | + | ====== PHP RFC: Named Parameters |
- | * Version: 0.1 | + | * Version: 0.3 |
- | * Date: 2020-07-24 | + | * Date: 2020-07-24 |
* Author: Chris Riley, t.carnage@gmail.com | * Author: Chris Riley, t.carnage@gmail.com | ||
- | * Status: | + | * Status: |
* First Published at: http:// | * First Published at: http:// | ||
Line 9: | Line 9: | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | The named parameters | + | The current implementation of named parameters |
- | It is likely that the way this will shake out is that some maintainers will accept the additional overhead of including parameter names in their BC guidelines and others will not, this leaves users unsure if they can use the new feature without storing up issues in potentially minor/ | + | Consider this example |
- | + | ||
- | More pressing a point is that the current implementation breaks object polymorphism. | + | |
<code php> | <code php> | ||
Line 21: | Line 19: | ||
class RegistrationHandler implements Handler { | class RegistrationHandler implements Handler { | ||
- | public function handle($registraionCommand); | + | public function handle($registrationCommand); |
} | } | ||
Line 29: | Line 27: | ||
class MessageBus { | class MessageBus { | ||
- | //... | + | /* ... */ |
- | public function addHandler(string $message, Handler $handler) { //... } | + | public function addHandler(string $message, Handler $handler) { /* ... */ } |
- | public function getHandler(string $messageType): | + | public function getHandler(string $messageType): |
public function dispatch($message) | public function dispatch($message) | ||
{ | { | ||
Line 39: | Line 37: | ||
</ | </ | ||
- | This code breaks | + | This will raise an Error exception |
+ | parameter name. | ||
- | Proposals were made for resolutions to this issue however all of them require trade offs and could potentially break existing code. I offer a new proposal which offers some advantages. | + | The situation will be further complicated if the method that is being called has a variadic |
+ | argument as in this situation no error will be raised, | ||
+ | be silently included into the variadic array. | ||
- | ===== Proposal ===== | + | <code php> |
- | === Option 1 === | + | interface Pager |
- | My proposal to resolve these two issues is to add the ability to rename parameters with a new syntax as follows. | + | { |
+ | public function fetch($page | ||
+ | } | ||
- | <code php> | + | class DbPager implements Pager |
- | function | + | { |
- | | + | public |
+ | | ||
+ | /* ... */ | ||
+ | | ||
} | } | ||
- | $x = new Foo(); | + | $dbPager |
- | callBar(externalName: $x); | + | $dbPager-> |
</ | </ | ||
- | This allows both the above problems to be resolved, by renaming the internal parameter | + | In this situation |
+ | results page with categories 1 and 2 instead of the second page with just category | ||
+ | 2. | ||
- | === Option 2 === | + | Proposals were made for resolutions to this issue however all of them require trade offs and could potentially break existing code. |
- | The second option would be to use this syntax | + | I offer a new proposal which offers some advantages. |
+ | |||
+ | ===== Proposal ===== | ||
+ | |||
+ | The proposal is to make named parameters explicitly opt in using a new syntax | ||
<code php> | <code php> | ||
- | function callBar($:externalName) { | + | function callBar(Foo $:parameterName) { |
- | $externalName->bar(); | + | $internalName->bar(); |
} | } | ||
$x = new Foo(); | $x = new Foo(); | ||
- | callBar(externalName: $x); | + | callBar(parameterName: $x); |
</ | </ | ||
- | If a parameter | + | This will enable us to resolve the polymorphism issue by restricting changes to |
+ | parameter names in child classes, without impacting existing userland code which | ||
+ | may rely on renaming parameters already. | ||
+ | |||
+ | If a parameter | ||
<code php> | <code php> | ||
Line 80: | Line 97: | ||
$x = new Foo(); | $x = new Foo(); | ||
- | callBar(externalName: | + | callBar(externalName: |
</ | </ | ||
- | There are pros and cons to this second | + | There are pros and cons to this approach, on the one hand it reduces the usefulness of the named parameter |
- | + | syntax by requiring changes to old code to enable it (although this could probably be automated fairly | |
- | Another advantage is that with the ability to rename parameters using the opt in, we gain some flexibility to tighten up the LSP rules relating to named parameter inheritance. | + | easily) however |
+ | tighten up the LSP rules relating to named parameter inheritance. Which allows the bugs/errors from the | ||
+ | | ||
<code php> | <code php> | ||
class Foo { | class Foo { | ||
- | public function bar($: | + | public function bar($: |
- | public function baz($internal: | + | |
} | } | ||
// OK | // OK | ||
- | class Bar { | + | class Bar extends Foo { |
- | public function bar($renamed:param) { //... } | + | public function bar($: |
- | public function baz($renamed: | + | |
} | } | ||
// Compile time error cannot rename named parameter $:param (renamed to $: | // Compile time error cannot rename named parameter $:param (renamed to $: | ||
- | class Baz { | + | class Baz extends Foo { |
- | public function bar($: | + | public function bar($: |
} | } | ||
- | // Compile time error cannot rename | + | </code> |
- | class Baz { | + | |
- | public function | + | While this could be done with the existing |
+ | which renames a parameter | ||
+ | in to allow named parameters. | ||
+ | |||
+ | In line with the existing RFC on named parameters, named parameter opt ins should follow the same rules as for | ||
+ | calling functions using named parameters. As such: | ||
+ | |||
+ | <code php> | ||
+ | |||
+ | // OK | ||
+ | function foo($positional, | ||
+ | |||
+ | // Error: named parameters must follow positional parameters | ||
+ | function bar($:named, $positional) { /* ... */ } | ||
+ | |||
+ | </ | ||
+ | |||
+ | Extending classes using named parameters will require that the method signature matches with regard | ||
+ | parameters | ||
+ | |||
+ | <code php> | ||
+ | |||
+ | class Foo | ||
+ | { | ||
+ | public function bar($:namedParam) { /* ... */ } | ||
+ | } | ||
+ | |||
+ | //OK | ||
+ | class Bar extends Foo | ||
+ | { | ||
+ | public function | ||
+ | } | ||
+ | |||
+ | // Error: parameter $namedParam must be declared as a named parameter | ||
+ | class Baz extends Foo | ||
+ | { | ||
+ | | ||
} | } | ||
</ | </ | ||
- | While this would be technically possible with the first option (no opt in) it would break any existing code which renames | + | To aid users upgrading from previous PHP versions, there will **not** |
+ | is a PHP built in class. Instead, | ||
+ | automatically. It should be assumed by developers that the deprecation will be upgraded to an error in line | ||
+ | with user land code in PHP 9.0, however this shall be subject to a separate RFC at the time which can assess | ||
+ | how appropriate that course of action is. | ||
+ | ====== Reflection ====== | ||
- | ===== Alternative solutions ===== | + | A new method isNamedParameter would be added to the ReflectionParameter class, this would return true if |
+ | the parameter can be called by name and false otherwise. | ||
- | ==== Attributes | + | ====== PHP standard library ====== |
- | It has been suggested that some of the issues raised in this RFC could be solved by attributes an internal attribute could be | + | |
- | created to specify a parameter name alias and allow argument renaming. This would work similarly to option 1, however has the downside of splitting the definition of a parameter over two parts of the code. | + | |
- | Option 2 could also be achieved using an attribute | + | It is proposed that all PHP standard functions and methods are opted in to named parameters. This will require |
+ | that some classes have parameter names updated to match the entire hierarchy as identified in the initial | ||
+ | RFC, to which this is a proposed enhancement. | ||
+ | ====== Alternative syntax using Attributes ====== | ||
- | ==== Opt out named parameters | + | Many people have expressed a preference towards using attributes to control the behaviour of named parameters, |
- | The comparison | + | this is not mutually exclusive |
- | named parameter syntax by using the special argument reference _ we could adopt something similar as a middle ground between option 1 and option 2. An example might be | + | instead of the new $: syntax choice. Attributes may in fact provide a better solution since they could be used |
+ | to opt in entire functions, methods or classes in one go eg | ||
<code php> | <code php> | ||
- | function | + | class Foo { |
+ | public | ||
+ | } | ||
- | foo(bar: ' | + | |
+ | class Bar { | ||
+ | @@NamedParameters | ||
+ | public function bar($param, $param2, $param3 ... $paramN) { /* ... */ } | ||
+ | } | ||
+ | |||
+ | @@NamedParameters | ||
+ | class Baz { | ||
+ | public function | ||
+ | public function | ||
+ | public function baz($param, $param2, $param3 | ||
+ | } | ||
</ | </ | ||
- | This wouldn' | + | All the other examples in this RFC would work in the same way, this would just simplify opting in to named |
+ | parameters for userland code. This will be offered as a voting choice against my proposed $: syntax. | ||
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
- | None | + | |
+ | Userland code which extends PHP built in classes and have renamed the arguments will cause a compile time | ||
+ | error. It is expected that this will be a very small quantity of code based on the same assumptions as the | ||
+ | original RFC. | ||
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | PHP 8.0 | + | **PHP 8.0** |
+ | |||
+ | This would be a breaking change to the existing named parameters implementation if implemented in **8.1**, so if accepted must be delivered for **8.0**. | ||
+ | Due to the time constraints I have slimmed down this proposal to focus on only the breaking changes that are required for | ||
+ | PHP **8.0** If accepted, I intend to start a separate RFC to handle the previous renaming behaviour for **8.1** using | ||
+ | either the attribute or $: syntax as accepted. | ||
===== RFC Impact ===== | ===== RFC Impact ===== | ||
==== To SAPIs ==== | ==== To SAPIs ==== | ||
Line 158: | Line 241: | ||
None | None | ||
- | ===== Open Issues | + | ===== Future Scope ===== |
- | Make sure there are no open issues when the vote starts! | + | |
- | ===== Unaffected PHP Functionality ===== | + | A future RFC will bring in the ability to specify different names to be used internally to the function/ |
- | List existing areas/ | + | separate to the callable external name. This syntax would look like: |
- | This helps avoid any ambiguity, shows that you have thought deeply about the RFC's impact, and helps reduces mail list noise. | + | <code php> |
+ | function foo($internalName: | ||
+ | </ | ||
- | ===== Future Scope ===== | + | as proposed |
- | This section details areas where the feature might be improved in future, but that are not currently | + | |
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
- | Proposed two voting options: | ||
- | 1. Implement parameter renaming | + | Two votes: |
- | 2. Make parameter names opt in | + | |
+ | Straight yes/no with 2/3 majority required to require | ||
+ | |||
+ | Majority vote between the implementation options of $: or using Attributes. | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
Line 184: | Line 269: | ||
===== References ===== | ===== References ===== | ||
- | This proposal is very similar to argument labels in swift: https:// | + | This proposal is similar to argument labels in swift: https:// |
+ | |||
+ | ===== Change log ===== | ||
+ | |||
+ | 09/07/20: V0.3 | ||
+ | - Tightened up scope to focus on opt in and technical challenges | ||
+ | |||
+ | 26/07/20: V0.2 | ||
+ | - Dropped option 1 (rename without explicit opt in) due to concerns over feature freeze timing, this option would be better targeted at 8.1 if this RFC fails. | ||
+ | - Added proposed staging strategy for implementation to allay concerns over feature freeze timing | ||
+ | - Documented objections & rebuttals to RFC | ||
- | ===== Rejected Features ===== | ||
- | Keep this updated with features that were discussed on the mail lists. |
rfc/renamed_parameters.1595598701.txt.gz · Last modified: 2020/07/24 13:51 by carnage