rfc:nameof
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revision | |||
rfc:nameof [2023/05/13 20:15] – apply feedback withinboredom | rfc:nameof [2024/01/14 22:49] (current) – reflect discussions withinboredom | ||
---|---|---|---|
Line 7: | Line 7: | ||
===== Introduction ===== | ===== Introduction ===== | ||
- | Currently, it is possible to inspect virtually any aspect | + | During PHP execution, it is possible to reflect on most of the code currently running. For example, it is easy to get the name of a class and using reflection utilities: names of properties, methods, and so on. However, getting |
- | '' | + | This can be used in attributes: |
- | This RFC proposes a global '' | + | <code PHP> |
+ | # | ||
+ | class Person { | ||
+ | public | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | In error messages: | ||
<code PHP> | <code PHP> | ||
- | echo nameof($variable); // variable | + | function divide(float $numerator, float $denominator): |
- | echo nameof($object-> | + | if($denominator === 0) throw new InvalidArgumentException(nameof($denominator) . ' is zero'); |
- | echo nameof(Enum::Case); // Case | + | } |
- | echo nameof(Object::Const); // Const | + | </code> |
- | echo nameof(myFunction(...)); | + | |
- | echo nameof(MY_CONSTANT); | + | In match statements: |
+ | |||
+ | <code PHP> | ||
+ | match($propertyName) { | ||
+ | nameof(MyClass-> | ||
+ | nameof(MyClass-> | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | Or anywhere a literal string can be used: | ||
+ | |||
+ | <code PHP> | ||
+ | $arr[nameof(myfunc(...))] = true; | ||
</ | </ | ||
- | As named parameters become more prevalent, providing the end user with the name of the parameter is more important, in a way that it is easy to locate when refactoring, | + | As named parameters become more prevalent, providing the end user with the name of the parameter is more important |
<code PHP> | <code PHP> | ||
Line 33: | Line 52: | ||
</ | </ | ||
- | Further, using '' | + | Here are some further examples showing how the identifier is transformed: |
<code PHP> | <code PHP> | ||
- | // evaluates to # | + | echo nameof($variable); |
- | # | + | echo nameof(MyClass-> |
- | class Operator { | + | echo nameof(MyClass:: |
- | public function handler() { | + | echo nameof(Enum::Case); // Case |
- | // implementation | + | echo nameof(Object::Const); // Const |
- | } | + | echo nameof(myFunction(...)); // myFunction |
- | } | + | echo nameof(\MyNamespace\myFunction(...)); |
+ | echo nameof(MY_CONSTANT); | ||
</ | </ | ||
Line 52: | Line 72: | ||
echo nameof($a($b)); | echo nameof($a($b)); | ||
echo nameof($$a); | echo nameof($$a); | ||
+ | echo nameof($a-> | ||
</ | </ | ||
- | All of these will generate a compile error: " | + | These will generate a compile error: " |
+ | |||
+ | Note that only the right-most part of the identifier is translated to a string. This is because this is almost always what you want. For example, in the case of '' | ||
+ | |||
+ | To continue the ''" | ||
===== Proposal ===== | ===== Proposal ===== | ||
- | The '' | + | A '' |
- | <code PHP> | + | There is a special case for objects: |
- | ${nameof($variable)} === $variable; | + | |
- | $object-> | + | 1. A ''::'' |
- | constant(Enum:: | + | 2. A '' |
- | constant(Object:: | + | 3. The left-hand side must be the type name; it can be an abstract type or an interface. |
- | (nameof(myFunction(...))() === myFunction(); | + | 4. The left-hand side cannot be a variable. |
- | constant(nameof(MY_CONSTANT)) === MY_CONSTANT; | + | |
- | </ | + | If the first two rules are broken |
There are a limited number of expressions that can resolve to a name using '' | There are a limited number of expressions that can resolve to a name using '' | ||
* variables (but not variable-variables): | * variables (but not variable-variables): | ||
- | * properties: '' | + | * properties: '' |
* first-class callables: '' | * first-class callables: '' | ||
* static properties and constants: '' | * static properties and constants: '' | ||
* constants: '' | * constants: '' | ||
- | When getting the name of constants and functions, the name will NOT be the full name, but the lexical name. This means that if the name is '' | + | The name will always |
<code PHP> | <code PHP> | ||
- | namespace | + | namespace |
- | const MY_CONST = true; | + | |
- | function namedFunction() {} | + | |
- | } | + | |
- | namespace Other { | + | class A { |
- | echo nameof(\Name\MY_CONST); // \Name\MY_CONST | + | |
- | echo nameof(\Name\namedFunction(...)); | + | |
} | } | ||
- | namespace Using { | + | function |
- | use const Name\MY_CONST as ; | + | |
- | use const Name\MY_CONST as ALIASED_CONST; | + | |
- | use function | + | |
- | | + | echo nameof(doStuff(...)); // \Example\doStuff |
- | echo nameof(\Name\MY_CONST); | + | echo nameof(A-> |
- | echo nameof(ALIASED_CONST); | + | |
- | echo nameof(namedFunction(...)); // namedFunction | + | |
- | echo nameof(\Name\namedFunction(...)); // \Name\namedFunction(...) | + | |
- | } | + | |
</ | </ | ||
- | |||
- | In other language implementations (such as C#), a full name usually isn't returned even if you pass one in. However, a 'full name' is rarely required and can often be constructed from parts, if required. However, as a convenience, | ||
Additionally, | Additionally, | ||
Line 123: | Line 135: | ||
} | } | ||
- | $a = new C(); | + | echo nameof(C-> |
- | echo nameof($a->exampleB(...)); // outputs: "exampleB" | + | echo nameof(B->example(...)); // outputs: "example" |
</ | </ | ||
- | In the example above, if we were to return the 'full name' | + | This adheres to the basic refactoring safety mentioned earlier, since refactoring |
- | + | ||
- | ===== Error Handling ===== | + | |
- | + | ||
- | There are several ways to handle errors, each one has its own merits but ultimately | + | |
- | + | ||
- | 1. No error handling | + | |
- | + | ||
- | In this case, there is no error handling. This would allow using '' | + | |
- | + | ||
- | <code PHP> | + | |
- | class MyClass { | + | |
- | public string $var; | + | |
- | } | + | |
- | nameof(MyClass:: | + | |
- | nameof($aVariable); | + | |
- | </ | + | |
- | + | ||
- | The downside is that PHP won't natively inform a developer that they' | + | |
- | + | ||
- | 2. Warnings | + | |
- | + | ||
- | In this case, PHP would output a warning: " | + | |
- | + | ||
- | Using a class name (or any other method that would normally trigger autoloading) that does not exist, will trigger autoloading and attempt to locate the class. If it is not found, a warning will be issued. If a variable does not exist in the current scope, a warning will be issued. If the referenced property/ | + | |
- | + | ||
- | Warnings can be disabled via the 'silence operator' ('' | + | |
- | + | ||
- | 3. Exceptions | + | |
- | + | ||
- | An exception model was considered, however, the author believes that it would break the concept of "using '' | + | |
- | + | ||
- | # | + | |
- | + | ||
- | which is probably undesirable and nearly impossible to handle in a graceful way. | + | |
===== Backward Incompatible Changes ===== | ===== Backward Incompatible Changes ===== | ||
Line 172: | Line 150: | ||
===== Proposed PHP Version(s) ===== | ===== Proposed PHP Version(s) ===== | ||
- | * 8.3: release | + | * 8.4: release |
- | * 8.2.x: '' | + | * 8.3.x: '' |
===== RFC Impact ===== | ===== RFC Impact ===== | ||
Line 183: | Line 161: | ||
==== To Opcache ==== | ==== To Opcache ==== | ||
- | Depends on error type vote. | ||
- | First case: compiled to a string literal. | + | a new AST node (similar to isset) will need to be handled. |
- | + | ||
- | Second and third case: a new AST node (similar to isset) will need to be handled. | + | |
==== New Constants ==== | ==== New Constants ==== | ||
Line 193: | Line 168: | ||
===== Open Issues ===== | ===== Open Issues ===== | ||
- | - Should first-class callables be allowed? It's relatively easy to get the name of a first-class callable and only included for completeness. | ||
===== Unaffected PHP Functionality ===== | ===== Unaffected PHP Functionality ===== | ||
- | PHP will largely be unaffected by this change, except that a new global function is introduced. | + | PHP will largely be unaffected by this change. |
===== Future Scope ===== | ===== Future Scope ===== | ||
Line 203: | Line 177: | ||
===== Proposed Voting Choices ===== | ===== Proposed Voting Choices ===== | ||
This is a simple yes-or-no vote to include this feature. 2/3 majority required to pass. | This is a simple yes-or-no vote to include this feature. 2/3 majority required to pass. | ||
- | |||
- | There is a subvote for the type of error checking to include. Majority wins. | ||
===== Patches and Tests ===== | ===== Patches and Tests ===== | ||
- | experimental implementation: | + | experimental implementation: |
===== Implementation ===== | ===== Implementation ===== | ||
Line 218: | Line 190: | ||
===== References ===== | ===== References ===== | ||
- | Links to external references, discussions or RFCs | + | - internals discussion: https:// |
===== Rejected Features ===== | ===== Rejected Features ===== | ||
- | Keep this updated with features that were discussed on the mail lists. | + | |
+ | Classes need not be supported by '' | ||
+ | |||
+ | There were some suggestions to use '':: | ||
+ | |||
+ | <code PHP> | ||
+ | class A { | ||
+ | public const name = ' | ||
+ | } | ||
+ | |||
+ | function example(): A { | ||
+ | return new A(); | ||
+ | } | ||
+ | |||
+ | echo example():: | ||
+ | echo A::name; | ||
+ | </ | ||
+ | |||
+ | The author believes '' | ||
+ | |||
+ | <code PHP> | ||
+ | const A = ' | ||
+ | |||
+ | class A { | ||
+ | public const name = ' | ||
+ | } | ||
+ | |||
+ | echo A::name; | ||
+ | </ | ||
+ | |||
+ | Are we getting the string " |
rfc/nameof.1684008903.txt.gz · Last modified: 2023/05/13 20:15 by withinboredom