[RFC] [Discussion] nameof

php.internals

Robert Landers

3 years ago
Hello Internals, It is with much trepidation and excitement that I'd like to announce the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed quite a bit in the last couple of days, so if you haven't seen the latest draft, please check it out. Essentially, it allows using `nameof()` anywhere a string can be used, even in static contexts. From a developer's perspective, it is a string and from the engine's perspective, it is also mostly a string (depending on how deep we want to go on error checking -- see the RFC). If anything is unclear or if I missed something, please let me know. Robert Landers Software Engineer Utrecht NL

Lydia de Jongh

3 years ago
Wow! Yess please. My mail yesterday crossed yours, I guess (thanks Claude for answering) asking for almost the same: myClass::$normalProperty::name So I would like to add my thoughts to your proposal. I prefer a magic constant like `::name` instead of a function call as it can be used in a wider scope; for example as a parameter in an Attribute. My arguments from yesterday:
> 'Directly' accessing properties and methods of the class as a parameter > in an Attribute is not really possible. > You can do that for a class with: \path\to\MyClass::class, but for > properties or methods you have to use strings, without recognition in > editors. > > It would be so nice if more items in php could be accessed with a > magic constant as you can do with ::class. > With magic constant an editor could recognize it and it limits typos > etc. and it provides the developer with a list of the properties/methods in > scope. > >
Some examples from my mail yesterday for using in attributes: abstract class SaveFactoryAbstract { use ObjectBuilderTrait; #[ResetValue] protected bool $isSaved = false; #[InitObject] // tells the builder to initialize this property with the latest specs provided by (other) attributes #[ResetObject] protected ?SaveInterface $oSave = null; public function __construct(){ $this->buildMe(); // provided by the trait } } With a magic constant you could do: #[UseClass(static::$oSave::name, ImageSave::class)] // using static for normal property? #[ResetValue($this->isSaved::name, default: true)] // or using $this ?? class ImageSaveFactory extends SaveFactoryAbstract { // negative side-effect: empty classes..... } From my mail yesterday: This could also extend possibilities with/for variable variables.... Like: $this->myProp::name myClass::$staticProp::name A potential difficulty is: how to access normal properties/methods.... Maybe just as if they are static? Like parent::normalMethod() is working.... A normal property or method cannot have the same name as its static partner (sadly) so internally I hope it is not a problem. outside scope: myClass::$staticProperty::name myClass::$normalProperty::name myClass::normalMethod::name inside scope: static::$normalProperty::name self::$normalProperty::name // I do not know if 'self::' adds anything for this purpose, except for private properties/methods maybe inside class/object: $this->normalProperty::name $this->normalMethod::name $this::$staticProperty::name Greetz, Lydia P.S. I hope the spacing in de code-example is working now. Op za 13 mei 2023 om 09:27 schreef Robert Landers <landers.robert@gmail.com

Rowan Collins

3 years ago
On 13 May 2023 10:04:39 BST, Lydia de Jongh <flexjoly@gmail.com> wrote:
>I prefer a magic constant like `::name` instead of a function call as it >can be used in a wider scope; for example as a parameter in an Attribute.
Don't confuse the syntax with the implementation: "::class" isn't actually a constant, and the proposed "nameof()" isn't actually a function; both are just syntaxes understood by the compiler to generate strings according to certain rules. The RFC explicitly mentions use in attributes:
> The nameof() function is not necessarily a function in the traditional sense and can be used anywhere a string literal can be used (such as to define static constants, array keys, and attributes).
I'm lukewarm on the RFC myself - I can't think of many places I'd use it, and some of the use cases feel like they would ideally not involve strings at all. But I can't actually think of a good reason *not* to include it. The one part of the RFC that surprised me was this:
> 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 use'd, it will be that name. However, if the full name is used in the nameof(), the full name is returned.
No reason is given *why* it works this way, and expanding the namespaces on a name is one of the most useful features of "::class". Importantly, it means that the string created can be passed to other contexts, and still refer to the same thing. For instance: use function Acme\bar as foo; ... #[SomeAttribute(callback: nameof(foo(...))] ... The attribute constructor, defined in a different file, can't do anything useful with the string 'foo'; it needs to know the qualified name of the function the user referenced, 'Acme\bar'. Similarly, I'm not wholly clear why nameof(MyClass::method(...)) should evaluate to "method" rather than "MyClass::method" or indeed "Full\NamespaceOf\MyClass::method". Some more details on what exactly it evaluates to for each type, and why, would be helpful. Regards,
-- Rowan Tommins [IMSoP]

Robert Landers

3 years ago
> The one part of the RFC that surprised me was this: > > > 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 use'd, it will be that name. However, if the full name is used in the nameof(), the full name is returned. > > No reason is given *why* it works this way, and expanding the namespaces on a name is one of the most useful features of "::class". Importantly, it means that the string created can be passed to other contexts, and still refer to the same thing. For instance:
I'll update the RFC for the reasoning later tonight, but it's actually a pretty simple one. There are other languages that have something similar (C# and Scala, from personal experience) and usually, they provide an unqualified name. This can be annoying, for exactly the reason you describe: when you want to pass the value to another context. Most of the time, you want the unqualified name, but then there are times you want the qualified name, and getting it can be a complex process. By allowing developers to provide a fully qualified name, if that is what they want, developers have more control over their experience. This is especially important when using traits and aliases: trait A { public function example() {} } trait B { public function example() {} } class C { use A, B { A::example insteadof B; B::example as exampleB; } } $a = new C(); echo nameof($a->exampleB(...)); // outputs: "exampleB" The actual 'qualified name' is "example" or maybe "B::example" but that isn't very helpful if you want to call $a->B::example instead of $a->A::example later on. Or consider if you have an aliased const: namespace A { const A = 1; } namespace B { use const A\A as TEST; echo nameof(TEST); } In this case, if you want to use nameof(TEST) in an error message or something else, it would be surprising to get \A\A instead of TEST. So, for your example, we can instead call nameof(\Acme\bar(...)) instead of the aliased name when passing to another context: use function Acme\bar as foo; ... #[SomeAttribute(callback: nameof(\Acme\bar(...))] ... I hope this helps!
> Similarly, I'm not wholly clear why nameof(MyClass::method(...)) should evaluate to "method" rather than "MyClass::method" or indeed "Full\NamespaceOf\MyClass::method".
Usually, you want the name of the 'last' thing". For example, if you want the name of a property called "myProperty", using nameof($this->myProperty), you probably just want "myProperty" and not "{some_internal_instance_id}->myProperty" that you have to parse to really use. Instead, we can compse ::class and/or nameof() to achieve the same thing if we want to.

Rowan Collins

3 years ago
On 13 May 2023 16:40:27 BST, Robert Landers <landers.robert@gmail.com> wrote:
> Most of the time, you want the unqualified name > ... >This is especially important when using traits and aliases:
I don't think trait renaming is the same thing as aliasing a qualified name. In a sense, it's actually the opposite: with a trait, the compiler is inserting the code of the method under the new name, and the name from the trait can no longer be used to access it; for namespace imports, the compiler is substituting the fully-qualified name, and the *local alias* can no longer be used to access it. The "real" name of a method copied in from a trait is whatever it's called in the target class, but the "real" name of a function aliased with "use function ... as ..." is undoubtedly its fully-qualified name.
>In this case, if you want to use nameof(TEST) in an error message or >something else, it would be surprising to get \A\A instead of TEST.
Would it? As I said before, my intuition was completely the opposite, that one of the advantages of writing nameof(TEST) rather than just 'TEST' is that it would resolve namespace imports the same way ::class does. Can you give an example of such an error message that would want to expose the local alias?
>So, for your example, we can instead call nameof(\Acme\bar(...)) >instead of the aliased name when passing to another context: > >use function Acme\bar as foo; >... >#[SomeAttribute(callback: nameof(\Acme\bar(...))] >... > >I hope this helps!
Not really, I'm afraid. If I have to write out the fully-qualified name, why would I bother with nameof() rather than just using a string? The more I read in this thread, the less I understand what the point of nameof() actually is, and how it would be used. Regards,
-- Rowan Tommins [IMSoP]

Robert Landers

3 years ago
On Sun, May 14, 2023 at 11:16 AM Rowan Tommins <rowan.collins@gmail.com> wrote:
> > On 13 May 2023 16:40:27 BST, Robert Landers <landers.robert@gmail.com> wrote: > > Most of the time, you want the unqualified name > > ... > >This is especially important when using traits and aliases: > > I don't think trait renaming is the same thing as aliasing a qualified name. In a sense, it's actually the opposite: with a trait, the compiler is inserting the code of the method under the new name, and the name from the trait can no longer be used to access it; for namespace imports, the compiler is substituting the fully-qualified name, and the *local alias* can no longer be used to access it.
As someone who has had limited interaction with the engine code itself but has been using PHP, daily, for nearly 15 years, I'm not sure this technical distinction makes sense in the context of programming in PHP. When using traits, I don't think of it as 'inserting code', but rather I think of it as 'using code' -- you do use `use TraitName` after all and it is very similar to the top-level using statement.
> >In this case, if you want to use nameof(TEST) in an error message or > >something else, it would be surprising to get \A\A instead of TEST. > > Would it? As I said before, my intuition was completely the opposite, that one of the advantages of writing nameof(TEST) rather than just 'TEST' is that it would resolve namespace imports the same way ::class does. > > Can you give an example of such an error message that would want to expose the local alias?
Which error message helps in resolving the error and would be written by someone writing the code? use function \Path\To\Function\Serializer\to_json as json_serializer; // a bunch of code using json_serializer() throw new Exception('json_serializer returned invalid json'); // or throw new Exception('\Path\To\Function\Serializer\to_json returned invalid json'); The former appears more natural and helps to trace the issue. Otherwise, you end up in the file, trying to dig through usings to figure out where usages of \Path\To\Function\Serializer\to_json are in the file because, at first glance, it appears to not be there. This would also be weird in the case of constants/functions in the global space, because fully qualified names begin with a "\" which feels unnatural when reading things meant for humans (such as error messages).
> >So, for your example, we can instead call nameof(\Acme\bar(...)) > >instead of the aliased name when passing to another context: > > > >use function Acme\bar as foo; > >... > >#[SomeAttribute(callback: nameof(\Acme\bar(...))] > >... > > > >I hope this helps! > > > Not really, I'm afraid. If I have to write out the fully-qualified name, why would I bother with nameof() rather than just using a string?
If you write it in a string you really will, actually, have to write out the fully qualified name because an IDE won't know you're referencing a language construct and be able to autocomplete it for you. If you rename the function or remove it, you won't be able to use static analysis to locate these strings, you'll have to manually search-and-replace the codebase, which opens up space for human error. nameof() gives you a fighting chance of actually finding ALL the usages in one go. Personally, I've found that refactoring the names of things in PHP is one of the most dangerous coding activities one can do in PHP. They may be in a string, a database, on the wire via `serialize(),` or any number of places. Making this a safer activity is one of my personal goals.
> The more I read in this thread, the less I understand what the point of nameof() actually is, and how it would be used.
IMHO, this comment isn't constructive or helpful, how can I help you understand? I'm more than happy to answer any and all questions, but comments like this are pretty demoralizing when there are only a few people discussing the feature in a community I'm relatively new to -- are my answers not clear enough, would a call help, or should I reference other language's implementations and rationales? I don't know the unwritten rules here, and being helpful and constructive can move the conversation forward instead of reaching impasses. Personally, I've been in war and dealt with far worse than this, but someone who hasn't been through what I've been through may not be as "thick-skinned" and just walk away. Just something to keep in mind for future interactions.

Rowan Collins

3 years ago
On 14 May 2023 11:59:13 BST, Robert Landers <landers.robert@gmail.com> wrote:
>As someone who has had limited interaction with the engine code itself >but has been using PHP, daily, for nearly 15 years, I'm not sure this >technical distinction makes sense in the context of programming in >PHP. When using traits, I don't think of it as 'inserting code', but >rather I think of it as 'using code' -- you do use `use TraitName` >after all and it is very similar to the top-level using statement.
I don't think it's a technical distinction at all, it's part of the definition of traits in PHP, which are often described as "compiler assisted copy and paste". The methods from the trait are added to the definition of the class during compilation, and after that it is almost impossible to distinguish them from methods written directly in the class definition. Conversely, namespace imports are entirely local to the current file (or even a namespace{} block), and it's almost impossible for running code to see anything other than the expanded name. That doesn't mean that there aren't good reasons to have nameof() handle both things in the way proposed, I just think those reasons are probably different for the two cases.
>> Can you give an example of such an error message that would want to expose the local alias? > >Which error message helps in resolving the error and would be written >by someone writing the code?
To clear up any doubt, there was no sarcasm or aggression intended, I was genuinely requesting an example, which you have provided, so thank you.
>use function \Path\To\Function\Serializer\to_json as json_serializer; > >// a bunch of code using json_serializer() >throw new Exception('json_serializer returned invalid json'); >// or >throw new Exception('\Path\To\Function\Serializer\to_json returned >invalid json');
I can see your reasoning now, but I can think of arguments both ways round: if you're trying to find out *why* the function returned invalid JSON, you need to know where the source code for that function is, so need its fully qualified name. My gut feel is still that it's more often useful to have the expansion done for you, but maybe others have different perspectives.
>This would also be weird in the case of constants/functions in the >global space, because fully qualified names begin with a "\" which >feels unnatural when reading things meant for humans (such as error >messages).
This seems to be a common sentiment indeed - people prefer long lists of "use function" to \ prefixes. It's not something I personally find unnatural, any more than "/images/logo.png" or "/etc/hosts", but I'm willing to concede I may be in a minority there.
>> Not really, I'm afraid. If I have to write out the fully-qualified name, why would I bother with nameof() rather than just using a string? > >If you write it in a string you really will, actually, have to write >out the fully qualified name because an IDE won't know you're >referencing a language construct and be able to autocomplete it for >you. If you rename the function or remove it, you won't be able to use >static analysis to locate these strings, you'll have to manually >search-and-replace the codebase, which opens up space for human error.
This makes some sense, although static analysis tools and IDEs already do a lot with pseudo-types in docblocks to understand the expected values of strings. The biggest weakness of a generic "nameof" is that it still doesn't hint what kind of thing you want to mention.
>IMHO, this comment isn't constructive or helpful, how can I help you >understand? I'm more than happy to answer any and all questions, but >comments like this are pretty demoralizing when there are only a few >people discussing the feature in a community I'm relatively new to
I'm genuinely sorry you felt this way, and it was absolutely not my intention to criticise you. If anything, it was meant to be an admission of my own failings, that I'd come into the discussion with the wrong preconceptions, because the use cases which immediately came into my head seemed to have contrasting requirements from the ones that you intended. To put things into a more productive context, then, I think a useful improvement to the RFC would be some examples of how you would use it with the different supported types, showing why the proposed semantics are useful for those scenarios. On a different note, you've talked about how errors would be handled for nonexistent constructs, but given PHP's dynamic nature, there's also a question of *when* they would need to exist. For instance, assuming we go with Warnings, if I use nameof(Foo::bar), and class Foo is defined in a different file, there's a few things that could happen: - the resolution happens while compiling a single file, in which case it will always give a Warning, because any symbol outside the file is unknown - the resolution happens at runtime, and causes class Foo to be autoloaded - the resolution happens at runtime but doesn't trigger autoloading, so whether it gives a Warning or not depends on whether other code happens to have loaded the definition of Foo - probably other options that I haven't considered With the "no error handling" version, this becomes moot, because it's just a string manipulation exercise. That's how ::class currently works, apart from a few specific cases like static::class and $someInstance::class Regards,
-- Rowan Tommins [IMSoP]

Robert Landers

3 years ago
> Conversely, namespace imports are entirely local to the current file (or even a namespace{} block), and it's almost impossible for running code to see anything other than the expanded name. > > That doesn't mean that there aren't good reasons to have nameof() handle both things in the way proposed, I just think those reasons are probably different for the two cases.
That's a fair point. Maybe it is worth putting it up for a secondary vote? I do have a strong preference, but I'd rather have full names than no names, and doesn't change the RFC that much. If I'm understanding correctly, it would only affect first-class callables and constants.
> >> Can you give an example of such an error message that would want to expose the local alias? > > > >Which error message helps in resolving the error and would be written > >by someone writing the code? > > To clear up any doubt, there was no sarcasm or aggression intended, I was genuinely requesting an example, which you have provided, so thank you.
FWIW, I didn't see it as a sarcastic question, but I'm a very sarcastic person IRL... so maybe I did and I just ignored it. ¯\_ ()_/¯ Either way, it was a good question.
> This seems to be a common sentiment indeed - people prefer long lists of "use function" to \ prefixes. It's not something I personally find unnatural, any more than "/images/logo.png" or "/etc/hosts", but I'm willing to concede I may be in a minority there.
I've seen hundreds of lines of nothing but `use`... it's terrifying once you end up with a smattering of aliases thrown in, randomly, for good measure. I don't think you're in the minority for people who've been using PHP a long time -- or bitten by those files. As someone who's had to wade through those codebases, aliases matter a lot and I'd like to see them respected. I'm also realizing, as this discussion goes on, that there is precedent for the expansion via ::class, so maybe that is the right way to go after all? 🤔
> The biggest weakness of a generic "nameof" is that it still doesn't hint what kind of thing you want to mention.
The 'kind' of the thing doesn't really matter, we just want the name of the thing. Basically, the string before `(...)`; the string after `->`,`::`, `$`, or in the case of constants, the string itself.
> >IMHO, this comment isn't constructive or helpful, how can I help you > >understand? I'm more than happy to answer any and all questions, but > >comments like this are pretty demoralizing when there are only a few > >people discussing the feature in a community I'm relatively new to > > I'm genuinely sorry you felt this way, and it was absolutely not my intention to criticise you. If anything, it was meant to be an admission of my own failings, that I'd come into the discussion with the wrong preconceptions, because the use cases which immediately came into my head seemed to have contrasting requirements from the ones that you intended.
Thanks for explaining your intentions and no hard feelings from me. It can feel like an 'island of one' putting an RFC forward for the first time and a bit daunting when receiving negative feedback. Maybe there should be a 'buddy system' for first-time submissions that reach the discussion phase? A more experienced contributor could volunteer to help guide the person through the process, answer weird questions (like when is a secondary vote required or useful? I got some feedback that it was a bad idea to include one, but why? I'm sure there's some background there, but I'm in the dark with nobody to reach out to and ask for history lessons), give informal feedback, and someone to reach out to when you get stuck.
> To put things into a more productive context, then, I think a useful improvement to the RFC would be some examples of how you would use it with the different supported types, showing why the proposed semantics are useful for those scenarios.
I can do that for sure.
> On a different note, you've talked about how errors would be handled for nonexistent constructs, but given PHP's dynamic nature, there's also a question of *when* they would need to exist. For instance, assuming we go with Warnings, if I use nameof(Foo::bar), and class Foo is defined in a different file, there's a few things that could happen: > > - the resolution happens while compiling a single file, in which case it will always give a Warning, because any symbol outside the file is unknown > - the resolution happens at runtime, and causes class Foo to be autoloaded > - the resolution happens at runtime but doesn't trigger autoloading, so whether it gives a Warning or not depends on whether other code happens to have loaded the definition of Foo > - probably other options that I haven't considered > > With the "no error handling" version, this becomes moot, because it's just a string manipulation exercise. That's how ::class currently works, apart from a few specific cases like static::class and $someInstance::class
I actually updated the RFC late last night with that information after some feedback from Dan. ;)

Lydia de Jongh

3 years ago
(I hope it is ok that I take parts from several mails) Op za 13 mei 2023 om 12:37 schreef Rowan Tommins <rowan.collins@gmail.com>:
> On 13 May 2023 10:04:39 BST, Lydia de Jongh <flexjoly@gmail.com> wrote: > > >I prefer a magic constant like `::name` instead of a function call as it > >can be used in a wider scope; for example as a parameter in an Attribute. > > Don't confuse the syntax with the implementation: "::class" isn't actually a constant, and the proposed "nameof()" isn't actually a function; both are just syntaxes understood by the compiler to generate strings according to certain rules. The RFC explicitly mentions use in attributes:
Just got that from the php manual.... 😜 : as it is listed under the 'magic constants' (https://www.php.net/manual/en/language.constants.magic.php) But I understand your point.
> > The one part of the RFC that surprised me was this: > > > > > 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 use'd, it will be that name. However, if the full name is used in the nameof(), the full name is returned. > > > > No reason is given *why* it works this way, and expanding the namespaces on a name is one of the most useful features of "::class". Importantly, it means that the string created can be passed to other contexts, and still refer to the same thing.
Op zo 14 mei 2023 om 14:55 schreef Rowan Tommins <rowan.collins@gmail.com>:
> > On 14 May 2023 11:59:13 BST, Robert Landers <landers.robert@gmail.com> wrote: > >use function \Path\To\Function\Serializer\to_json as json_serializer; > > > >// a bunch of code using json_serializer() > >throw new Exception('json_serializer returned invalid json'); > >// or > >throw new Exception('\Path\To\Function\Serializer\to_json returned > >invalid json'); > > I can see your reasoning now, but I can think of arguments both ways round: if you're trying to find out *why* the function returned invalid JSON, you need to know where the source code for that function is, so need its fully qualified name. > > My gut feel is still that it's more often useful to have the expansion done for you, but maybe others have different perspectives. >
Op zo 14 mei 2023 om 17:45 schreef Robert Landers <landers.robert@gmail.com>:
> > > Conversely, namespace imports are entirely local to the current file (or even a namespace{} block), and it's almost impossible for running code to see anything other than the expanded name. > > > > That doesn't mean that there aren't good reasons to have nameof() handle both things in the way proposed, I just think those reasons are probably different for the two cases. > > That's a fair point. Maybe it is worth putting it up for a secondary > vote? I do have a strong preference, but I'd rather have full names > than no names, and doesn't change the RFC that much. If I'm > understanding correctly, it would only affect first-class callables > and constants. >
I totally agree with Rowan. In many (most?) cases you need the fully qualified name. Even or especially for error handling! Of course mostly the error is somewhere else. But you want to know the starting point. An unqualified name gets you nowhere. Although backtrace can help you out. And this is also consistent with how ::class or get_class() work.... it gives fully qualified names. On the other hand you could argue that 'nameof()' in itself means: 'just looking for the direct/unqualified name of something' and is an addition to ::class and get_class().... Then we still need something to get the fully qualified name/path of a variable or php-item. For a class we have: ::class, get_class() and class_exists(). And inside these function you can use: get_class(MyClass::class); For a method we only have: method_exists and it needs 2 parameters, for the methodname: only string is possible 😭 Would be nice to have, and consistent to have: - MyClass::method::method - method_exists($object->method::method) - get_method(MyClass::method::method) And the same for properties: - MyClass::property::property - method_exists($object-> property::property) - get_method(MyClass:: property::property) The downside is that we get many new 'magic constants'... What about: - for unqualified names: -- nameof(any-php-item) -- any_php_item::nameof - for fully qualified names: -- pathof(any-php-item) or fullnameof() -- any_php_item::pathof or ::fullnameof
> > To put things into a more productive context, then, I think a useful improvement to the RFC would be some examples of how you would use it with the different supported types, showing why the proposed semantics are useful for those scenarios. > > I can do that for sure.
Aside for error handling, I think it would give attributes a boost as they handle configuration and metadata, without having a proper way to address variables and other php items, except classes. #[MyAttribute(property: MyClass::myProperty::fullnameof)] Which IMHO is much better then: #[MyAttribute(property: callback(nameof(MyClass::myProperty))] and if it only gives the unqualified name: #[MyAttribute(property: MyClass::class . callback(nameof(MyClass::myProperty))] Which also shows that it is not consistent..... with the useful working of ::class
> ... > #[SomeAttribute(callback: nameof(\Acme\bar(...))] > ...
This callback to nameof()..... is really terrible 😣😣 Is this not why ::class was invented, while get_class() does the same?! Op zo 14 mei 2023 om 00:42 schreef Robert Landers <landers.robert@gmail.com>:
> I think the downside of using ::name would be: 'what if I already have > a const called "name"?' > > So, we'd have to come up with a different name. Largely, as far as the > compiler would be concerned, we've both got the same idea.
Good point. I hope my suggestions above do help. And that you consider adding them to your RFC 🙏
> > instead of > > $class = new ReflectionClass(ClassName::class); > $property = $class->getProperty('property'); > $type = $property->getType(); > var_dump($type); >
It is worse.... you need an extra if with ->hasProperty....
> Something to think about...
Greetz, Lydia

Robert Landers

3 years ago
> I totally agree with Rowan. In many (most?) cases you need the fully > qualified name. > Even or especially for error handling! Of course mostly the error is > somewhere else. But you want to know the starting point. An > unqualified name gets you nowhere. Although backtrace can help you > out. > > And this is also consistent with how ::class or get_class() work.... > it gives fully qualified names.
> On the other hand you could argue that 'nameof()' in itself means: > 'just looking for the direct/unqualified name of something' and is an > addition to ::class and get_class()....
This is exactly what I was thinking when I wrote it out, however, you can pass the full name to get the full name (an escape hatch of sorts).
> Then we still need something to get the fully qualified name/path of a > variable or php-item. > For a class we have: ::class, get_class() and class_exists(). > And inside these function you can use: > get_class(MyClass::class);
Variables don't get stored in a namespace or they exist only in the local scope (they can't have a 'qualified' name, in my experience): namespace A { $b = 'c'; } echo $b; // outputs: 'c' For callables, you can already get the fully qualified name: echo (new ReflectionFunction(strstr(...)))->getName(); You, however, cannot get the name of a constant, except through get_defined_constants() and comparing values (searching in the namespace you care about) and doesn't help you if it isn't defined. There's further evidence that an unqualified name is the right way to go: use const \NoExist\TEST; use \NoExist\Channel; echo TEST; echo Channel::class; the output is: Undefined constant "TEST" in ... Channel note that it does NOT say "\MyNamespace\TEST" is undefined nor does it output "\NoExist\Channel", so if the user wants to write: use function \AppPlugins\Config; if(!function_exists(nameof(Config(...)))) throw new Exception(nameof(Config(...)) . ' does not exist, please define it.'); It's going to output the unqualified name anyway, simply due to how PHP resolves names. Using the "escape hatch", however, we can "force" PHP to do what we expect: if(!function_exists(nameof(\AppPlugins\Config(...))) throw new Exception(nameof(Config(...)) . ' does not exist, please define it.'); I'll update the RFC to reflect this.
> The downside is that we get many new 'magic constants'...
There are no magic constants in this RFC. Robert Landers Software Engineer Utrecht NL

Rowan Collins

3 years ago
On 15 May 2023 14:07:31 BST, Lydia de Jongh <flexjoly@gmail.com> wrote:
>> ... >> #[SomeAttribute(callback: nameof(\Acme\bar(...))] >> ... > >This callback to nameof()..... is really terrible 😣😣
Just to be clear, the "callback:" in that example is existing syntax for named parameters, not part of the nameof() syntax. A positional parameter would just look like this: #[SomeAttribute(nameof(\Acme\bar(...))] That's the same number of characters as this: #[SomeAttribute(\Acme\bar(...)::nameof] The main difference is the the function-ish syntax makes it a bit clearer what you're asking for the name of, because the whole thing is in parentheses. There might even be cases where the function-ish syntax needs additional parentheses anyway, like are needed in (new Something)->doSomething() Changing "nameof" to "function", "method", etc depending on type doesn't really add anything, since the output is always a string anyway, not some type-specific thing. Regards,
-- Rowan Tommins [IMSoP]

Robert Landers

3 years ago
On Sat, May 13, 2023 at 11:05 AM Lydia de Jongh <flexjoly@gmail.com> wrote:
> > Wow! Yess please. My mail yesterday crossed yours, I guess (thanks Claude > for answering) > asking for almost the same: > > myClass::$normalProperty::name > > So I would like to add my thoughts to your proposal. > > I prefer a magic constant like `::name` instead of a function call as it > can be used in a wider scope; for example as a parameter in an Attribute. > > My arguments from yesterday: > > > 'Directly' accessing properties and methods of the class as a parameter > > in an Attribute is not really possible. > > You can do that for a class with: \path\to\MyClass::class, but for > > properties or methods you have to use strings, without recognition in > > editors. > > > > It would be so nice if more items in php could be accessed with a > > magic constant as you can do with ::class. > > With magic constant an editor could recognize it and it limits typos > > etc. and it provides the developer with a list of the properties/methods in > > scope. > > > > > Some examples from my mail yesterday for using in attributes: > > abstract class SaveFactoryAbstract { > > use ObjectBuilderTrait; > > > #[ResetValue] > > protected bool $isSaved = false; > > > #[InitObject] // tells the builder to initialize this property with the > latest specs provided by (other) attributes > > #[ResetObject] > > protected ?SaveInterface $oSave = null; > > > > public function __construct(){ > > $this->buildMe(); // provided by the trait > > } > > } > > > With a magic constant you could do: > > #[UseClass(static::$oSave::name, ImageSave::class)] // using static for > normal property? > > #[ResetValue($this->isSaved::name, default: true)] // or using $this ?? > class ImageSaveFactory extends SaveFactoryAbstract { > > // negative side-effect: empty classes..... > > } > > > From my mail yesterday: > This could also extend possibilities with/for variable variables.... > > Like: > $this->myProp::name > myClass::$staticProp::name > > A potential difficulty is: how to access normal properties/methods.... > Maybe just as if they are static? > Like parent::normalMethod() is working.... > A normal property or method cannot have the same name as its static partner > (sadly) so internally I hope it is not a problem. > > outside scope: > myClass::$staticProperty::name > myClass::$normalProperty::name > myClass::normalMethod::name > > inside scope: > static::$normalProperty::name > self::$normalProperty::name // I do not know if 'self::' adds anything for > this purpose, except for private properties/methods maybe > > inside class/object: > $this->normalProperty::name > $this->normalMethod::name > $this::$staticProperty::name > > > Greetz, Lydia > P.S. I hope the spacing in de code-example is working now. > > > Op za 13 mei 2023 om 09:27 schreef Robert Landers <landers.robert@gmail.com > >: > > > > Hello Internals, > > > > It is with much trepidation and excitement that I'd like to announce > > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed > > quite a bit in the last couple of days, so if you haven't seen the > > latest draft, please check it out. > > > > Essentially, it allows using `nameof()` anywhere a string can be used, > > even in static contexts. From a developer's perspective, it is a > > string and from the engine's perspective, it is also mostly a string > > (depending on how deep we want to go on error checking -- see the > > RFC). > > > > If anything is unclear or if I missed something, please let me know. > > > > Robert Landers > > Software Engineer > > Utrecht NL > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: https://www.php.net/unsub.php > >
Hi Lydia, Please remember to bottom-post responses. But, to respond: I think the downside of using ::name would be: 'what if I already have a const called "name"?' So, we'd have to come up with a different name. Largely, as far as the compiler would be concerned, we've both got the same idea.
> A potential difficulty is: how to access normal properties/methods.... > Maybe just as if they are static? > Like parent::normalMethod() is working.... > A normal property or method cannot have the same name as its static partner > (sadly) so internally I hope it is not a problem.
I find this particular point an interesting side discussion, as it was something that bothered me for a while. Ultimately, I ended up with two solutions: 1. Do no error checking at all with nameof. This lets the community come up with something that makes sense. Perhaps someday in the future the community will settle on something that works well and an RFC will be put forward to add proper error checking. For example, any of these could work, and all resolve to the string "normalMethod": - nameof(ClassName::normalMethod) - nameof(ClassName::normalMethod(...)) - nameof($_->normalMethod) - nameof(ClassName->normalMethod(...)) <-- I kinda like this one - nameof(normalMethod) 2. Emit a warning This is the one I suspect will be chosen (and I'm starting to like more and more, after writing out those examples). In this implementation, we'd emit a warning if you used a name that doesn't exist. However, PHP has a well-known silence operator (@) that could be used to silence the warning if you wanted to do something weird (like one of the examples above). It would still allow an RFC for referencing instanced properties/methods at a later date, if there is demand for it. Until then, there is the silence operator. If there was an RFC for referencing instanced properties or methods, it could be interesting. Right now, the only way to reference instanced properties is via reflection, and having this capability would open the door for having a generic 'declared_type()' (not to be confused with gettype() that returns the actual type of a variable and not the declared type) that could instantly return the reflected type. I can think of a number of applications for something like that... and all the code I could delete... It would be magical to write something like: var_dump(declared_type(ClassName->property)); instead of $class = new ReflectionClass(ClassName::class); $property = $class->getProperty('property'); $type = $property->getType(); var_dump($type); Something to think about...

Dan Ackroyd

3 years ago
On Sat, 13 May 2023 at 08:27, Robert Landers <landers.robert@gmail.com> wrote:
> > Hello Internals, > > It is with much trepidation and excitement that I'd like to announce > the `nameof` RFC (https://wiki.php.net/rfc/nameof).
Can you provide more details on what the error conditions are? I can see 'non-existent static variable' and 'non-existent variable', are there others?
> An exception model was considered, however, the author believes that > it would break the concept of “using nameof wherever a string could > be used” and wouldn't be practical for the engine to handle all of > those cases.
Can you put some detail in there ....I don't understand the problem, or what you mean by it not being practical to 'handle all of those cases' .
> each one has its own merits but ultimately will > be left up as a secondary vote:
One of the reasons the RFC process has served PHP pretty well is that it forces people to think through the details. I really don't think putting a few options up and hoping that people choose the best one is a good way to design a language; it allows skipping over thinking the details through. And yeah....this is one of the reason doing RFCs is annoying. People are often persnickety over details. cheers Dan Ack

Robert Landers

3 years ago
> Can you provide more details on what the error conditions are? I can > see 'non-existent static variable' and 'non-existent variable', are > there others?
Absolutely! I'll add it to the RFC later tonight, but the gist is that it would be exactly the same as if you were to call any function with something that doesn't exist.
> > An exception model was considered, however, the author believes that > > it would break the concept of “using nameof wherever a string could > > be used” and wouldn't be practical for the engine to handle all of > > those cases. > > Can you put some detail in there ....I don't understand the problem, > or what you mean by it not being practical to 'handle all of those > cases' .
I can do that, I agree it probably isn't as clear as it could be. One issue that was identified is that if this can be used anywhere a string/constant can be used, there may be edge cases where there is no way to handle an exception there because a try-catch isn't an expression. For example, in attributes, I'm not 100% sure the engine is set up to handle an exception being thrown while defining an attribute, nor how you would catch such an exception in a graceful way. I could be completely wrong, in which case I can add back that option.
> > each one has its own merits but ultimately will > > be left up as a secondary vote: > > One of the reasons the RFC process has served PHP pretty well is that > it forces people to think through the details. > > I really don't think putting a few options up and hoping that people > choose the best one is a good way to design a language; it allows > skipping over thinking the details through. > > And yeah....this is one of the reason doing RFCs is annoying. People > are often persnickety over details.
That is fair :) After some discussions with colleagues, I realized how errors are output and handled might be a contentious topic. I decided to make it a secondary vote -- and hopefully -- the discussions we're having now might inform voters on the best way to vote for how errors are handled. I don't have a personal preference (but apparently some people do), and I'd be happy with any of the solutions.

Robert Landers

3 years ago
On Sat, May 13, 2023 at 5:58 PM Robert Landers <landers.robert@gmail.com> wrote:
> > > Can you provide more details on what the error conditions are? I can > > see 'non-existent static variable' and 'non-existent variable', are > > there others? > > Absolutely! I'll add it to the RFC later tonight, but the gist is that > it would be exactly the same as if you were to call any function with > something that doesn't exist.
After enumerating the warnings/errors that would be expressed, I realized that some of these would halt execution, which is probably undesirable. I've adjusted the RFC to simply emit a warning and further defined when that warning would be emitted.

Niels Dossche

3 years ago
On 13/05/2023 09:27, Robert Landers wrote:
> Hello Internals, > > It is with much trepidation and excitement that I'd like to announce > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed > quite a bit in the last couple of days, so if you haven't seen the > latest draft, please check it out. > > Essentially, it allows using `nameof()` anywhere a string can be used, > even in static contexts. From a developer's perspective, it is a > string and from the engine's perspective, it is also mostly a string > (depending on how deep we want to go on error checking -- see the > RFC). > > If anything is unclear or if I missed something, please let me know. > > Robert Landers > Software Engineer > Utrecht NL >
Hello Robert Thank you for doing the proposal. I can see some places where I might use this. I have an additional question that I don't think has been asked yet. About the interaction of nameof with "variable variables": What should be returned by `nameof($$variable)`, and similarly `nameof($$$variable)`, etc? Defining the semantics for this, and giving examples in the RFC text would be great :) Good luck with your RFC. Cheers Niels

Robert Landers

3 years ago
On Sat, May 13, 2023 at 5:18 PM Niels Dossche <dossche.niels@gmail.com> wrote:
> > On 13/05/2023 09:27, Robert Landers wrote: > > Hello Internals, > > > > It is with much trepidation and excitement that I'd like to announce > > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed > > quite a bit in the last couple of days, so if you haven't seen the > > latest draft, please check it out. > > > > Essentially, it allows using `nameof()` anywhere a string can be used, > > even in static contexts. From a developer's perspective, it is a > > string and from the engine's perspective, it is also mostly a string > > (depending on how deep we want to go on error checking -- see the > > RFC). > > > > If anything is unclear or if I missed something, please let me know. > > > > Robert Landers > > Software Engineer > > Utrecht NL > > > > Hello Robert > > Thank you for doing the proposal. I can see some places where I might use this. > > I have an additional question that I don't think has been asked yet. About the interaction of nameof with "variable variables": > What should be returned by `nameof($$variable)`, and similarly `nameof($$$variable)`, etc? > Defining the semantics for this, and giving examples in the RFC text would be great :) > > Good luck with your RFC. > > Cheers > Niels
That is a good question. It should be a compile error due to ambiguity. I'll update the RFC to include that. $variable would already be the name of the variable being referenced by $$variable, so if you want the name of $variable, just get the name of $variable, and if you want the name of $$variable, just get the value of $variable.

Larry Garfield

3 years ago
On Sat, May 13, 2023, at 7:27 AM, Robert Landers wrote:
> Hello Internals, > > It is with much trepidation and excitement that I'd like to announce > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed > quite a bit in the last couple of days, so if you haven't seen the > latest draft, please check it out. > > Essentially, it allows using `nameof()` anywhere a string can be used, > even in static contexts. From a developer's perspective, it is a > string and from the engine's perspective, it is also mostly a string > (depending on how deep we want to go on error checking -- see the > RFC). > > If anything is unclear or if I missed something, please let me know. > > Robert Landers > Software Engineer > Utrecht NL
Some concrete use cases that I know I run into, and would thus be what I'd hope an RFC like this would resolve: Router::addRoute('\my\space\my_action_function`); Right now that has to be a string with a full namespace. You cannot use a FCC here, because you want to use this data to compile the router somehow. So in this case we want the full namespace. (Ignore function autoloading for now.) Router::addRoute(MyClass::actionMethod); Various frameworks have different custom syntaxes for this case. It's also not clear if this refers to a static method, or a "instantiate this out of the container first and then call this method" approach. In these cases, we would want the full class name, and the method name on its own, as separate strings. In my FP library, I have code like this: function prop(string $prop): \Closure { return static fn (object $o): mixed => $o->$prop; } function method(string $method, ...$args): \Closure { return static fn (object $o): mixed => $o->$method(...$args); } Which you can then use in a pipe, like so: pipe($someObject, method('foo'), prop('bar')); Or, more realistically, you'd use method() and prop() in a map or filter call within the pipe. In this case, you want just the method/property name on its own, without a namespace, because it will be used in the context of an object to be named later. How would nameof() handle each of these cases? --Larry Garfield

Robert Landers

3 years ago
On Tue, May 16, 2023 at 11:56 PM Larry Garfield <larry@garfieldtech.com> wrote:
> > On Sat, May 13, 2023, at 7:27 AM, Robert Landers wrote: > > Hello Internals, > > > > It is with much trepidation and excitement that I'd like to announce > > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed > > quite a bit in the last couple of days, so if you haven't seen the > > latest draft, please check it out. > > > > Essentially, it allows using `nameof()` anywhere a string can be used, > > even in static contexts. From a developer's perspective, it is a > > string and from the engine's perspective, it is also mostly a string > > (depending on how deep we want to go on error checking -- see the > > RFC). > > > > If anything is unclear or if I missed something, please let me know. > > > > Robert Landers > > Software Engineer > > Utrecht NL > > Some concrete use cases that I know I run into, and would thus be what I'd hope an RFC like this would resolve: > > Router::addRoute('\my\space\my_action_function`); > > Right now that has to be a string with a full namespace. You cannot use a FCC here, because you want to use this data to compile the router somehow. So in this case we want the full namespace. (Ignore function autoloading for now.) > > Router::addRoute(MyClass::actionMethod); > > Various frameworks have different custom syntaxes for this case. It's also not clear if this refers to a static method, or a "instantiate this out of the container first and then call this method" approach. In these cases, we would want the full class name, and the method name on its own, as separate strings. > > In my FP library, I have code like this: > > function prop(string $prop): \Closure > { > return static fn (object $o): mixed => $o->$prop; > } > > function method(string $method, ...$args): \Closure > { > return static fn (object $o): mixed => $o->$method(...$args); > } > > Which you can then use in a pipe, like so: > > pipe($someObject, method('foo'), prop('bar')); > > Or, more realistically, you'd use method() and prop() in a map or filter call within the pipe. > > In this case, you want just the method/property name on its own, without a namespace, because it will be used in the context of an object to be named later. > > How would nameof() handle each of these cases? > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
Hey Larry, I did not ignore you. I somehow missed your question while researching something after reading the first half of your email last week -- I, apparently, never made it to the second half until today. I'll get to that in a sec.
> pipe($someObject, method('foo'), prop('bar')); > > Or, more realistically, you'd use method() and prop() in a map or filter call within the pipe. > > In this case, you want just the method/property name on its own, without a namespace, because it will be used in the context of an object to be named later.
So, for example, you could replace your pipe with: pipe($someObject, method(nameof($someObject->foo(...))), prop(nameof($someObject->bar))) It looks a bit wordy, but PHP differentiates between properties and methods by using a parenthesis/bracket (hence if you want to call a property that is actually a closure, you have to write ($this->prop)() otherwise it will look for a method called prop and fail to find it). At runtime, you would receive a warning on this line if $someObject is missing a method called foo or a property called bar (if the error-detecting version is chosen). This would result likely result in an actual error in your method() and prop() functions. However, it should make debugging from logs a bit easier since you'll (hopefully) notice the warning. Now, why I didn't answer you and only made it half way through your email... Much of the earlier discussion was about functions/consts being fully-qualified names. I was mostly against it, because I was offering 'both' qualified and unqualified. However, your initial examples really hit home for me and I did a bit of spelunking in various popular PHP codebases for class::name (since that is really the only similar thing) and for stringified names of things. I'm now convinced that FQL's should be returned for functions, and constants (but not methods and properties). Thus, your example: Router::addRoute('\my\space\my_action_function`); Router::addRoute(MyClass::actionMethod); could be rewritten as use function \my\space\my_action_function; Router::addRoute(nameof(my_action_function)); Router::addRoute(nameof(MyClass::actionMethod(...))); I'll have to think about how to word this in RFC, but I'll do so as soon as I figure it out. Cheers, Robert Landers

Robert Landers

3 years ago
> use function \my\space\my_action_function; > Router::addRoute(nameof(my_action_function)); > Router::addRoute(nameof(MyClass::actionMethod(...)));
My mistake, this should be:

Larry Garfield

3 years ago
On Thu, May 25, 2023, at 3:21 PM, Robert Landers wrote:
> On Tue, May 16, 2023 at 11:56 PM Larry Garfield <larry@garfieldtech.com> wrote: >> >> On Sat, May 13, 2023, at 7:27 AM, Robert Landers wrote: >> > Hello Internals, >> > >> > It is with much trepidation and excitement that I'd like to announce >> > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed >> > quite a bit in the last couple of days, so if you haven't seen the >> > latest draft, please check it out. >> > >> > Essentially, it allows using `nameof()` anywhere a string can be used, >> > even in static contexts. From a developer's perspective, it is a >> > string and from the engine's perspective, it is also mostly a string >> > (depending on how deep we want to go on error checking -- see the >> > RFC). >> > >> > If anything is unclear or if I missed something, please let me know. >> > >> > Robert Landers >> > Software Engineer >> > Utrecht NL >> >> Some concrete use cases that I know I run into, and would thus be what I'd hope an RFC like this would resolve: >> >> Router::addRoute('\my\space\my_action_function`); >> >> Right now that has to be a string with a full namespace. You cannot use a FCC here, because you want to use this data to compile the router somehow. So in this case we want the full namespace. (Ignore function autoloading for now.) >> >> Router::addRoute(MyClass::actionMethod); >> >> Various frameworks have different custom syntaxes for this case. It's also not clear if this refers to a static method, or a "instantiate this out of the container first and then call this method" approach. In these cases, we would want the full class name, and the method name on its own, as separate strings. >> >> In my FP library, I have code like this: >> >> function prop(string $prop): \Closure >> { >> return static fn (object $o): mixed => $o->$prop; >> } >> >> function method(string $method, ...$args): \Closure >> { >> return static fn (object $o): mixed => $o->$method(...$args); >> } >> >> Which you can then use in a pipe, like so: >> >> pipe($someObject, method('foo'), prop('bar')); >> >> Or, more realistically, you'd use method() and prop() in a map or filter call within the pipe. >> >> In this case, you want just the method/property name on its own, without a namespace, because it will be used in the context of an object to be named later. >> >> How would nameof() handle each of these cases? >> >> --Larry Garfield >> >> -- >> PHP Internals - PHP Runtime Development Mailing List >> To unsubscribe, visit: https://www.php.net/unsub.php >> > > Hey Larry, > > I did not ignore you. I somehow missed your question while researching > something after reading the first half of your email last week -- I, > apparently, never made it to the second half until today. I'll get to > that in a sec.
Not to worry.
>> pipe($someObject, method('foo'), prop('bar')); >> >> Or, more realistically, you'd use method() and prop() in a map or filter call within the pipe. >> >> In this case, you want just the method/property name on its own, without a namespace, because it will be used in the context of an object to be named later. > > So, for example, you could replace your pipe with: > > pipe($someObject, method(nameof($someObject->foo(...))), > prop(nameof($someObject->bar))) > > It looks a bit wordy, but PHP differentiates between properties and > methods by using a parenthesis/bracket (hence if you want to call a > property that is actually a closure, you have to write ($this->prop)() > otherwise it will look for a method called prop and fail to find it). > > At runtime, you would receive a warning on this line if $someObject is > missing a method called foo or a property called bar (if the > error-detecting version is chosen). This would result likely result in > an actual error in your method() and prop() functions. However, it > should make debugging from logs a bit easier since you'll (hopefully) > notice the warning.
I figured it would be something like that. I don't know how it would be done better, but it also makes the code notably more verbose, and clumsy with the extra ()s. So, I'm not sure if it's a net-win or not.
> Now, why I didn't answer you and only made it half way through your email... > > Much of the earlier discussion was about functions/consts being > fully-qualified names. I was mostly against it, because I was offering > 'both' qualified and unqualified. However, your initial examples > really hit home for me and I did a bit of spelunking in various > popular PHP codebases for class::name (since that is really the only > similar thing) and for stringified names of things. I'm now convinced > that FQL's should be returned for functions, and constants (but not > methods and properties).
Mission accomplished, then. :-) And yes, I agree with that conclusion.
> Thus, your example: > > Router::addRoute('\my\space\my_action_function`); > Router::addRoute(MyClass::actionMethod); > > could be rewritten as > > use function \my\space\my_action_function; > Router::addRoute(nameof(my_action_function)); > Router::addRoute(nameof(MyClass::actionMethod(...))); > > I'll have to think about how to word this in RFC, but I'll do so as > soon as I figure it out.
>> use function \my\space\my_action_function; >> Router::addRoute(nameof(my_action_function)); >> Router::addRoute(MyClass::name . '::' . nameof(MyClass::actionMethod(...))); // or something since the class name is not returned with nameof().
The function one seems reasonable. The method version, though, looks super ugly and hard to implement. I'd be much more likely to just split it into two arguments and leave the second as a string, TBH. Using a :: pseudo-constant suffix rather than a ()-based construct would help with the syntax clumsiness in both cases, but wouldn't entirely eliminate it. I don't have a really great answer here, unfortunately. I think I'd marginally prefer a ::name suffix at this point just for syntactic convenience, but I'm still undecided if the overall tradeoff is worth it. (For ::name, probably, as that would be a much lighter syntax impact for those unusual cases that it's needed.) --Larry Garfield

Robert Landers

3 years ago
> Using a :: pseudo-constant suffix rather than a ()-based construct would help with the syntax clumsiness in both cases, but wouldn't entirely eliminate it. I don't have a really great answer here, unfortunately. I think I'd marginally prefer a ::name suffix at this point just for syntactic convenience, but I'm still undecided if the overall tradeoff is worth it. (For ::name, probably, as that would be a much lighter syntax impact for those unusual cases that it's needed.)
I believe Lydia suggested something like that, and while I kinda liked the syntax (better than nameof() for wordy-looking bits), it just looked weird to me. I'm not dismissing it out of hand though. There might even be some middle ground where nameof() only works on functions/constants, while methods/properties have a ::name pseudo constant. I'll have to play with it and how it feels.

Robert Landers

2 years ago
Hello Internals, After much thought and deliberation, I've updated the nameof RFC (https://wiki.php.net/rfc/nameof) to reflect most of this discussion and refine a few edge cases regarding objects. TL;DR: there are a few rules regarding how properties of objects are addressed that I hope a few people will like (and would make it much more usable in static contexts, like attributes). I'm still not fully settled on the syntax, and this is still very much a work in progress. So, I'd love feedback in that regard. Robert Landers Software Engineer Utrecht NL

Bob Weinand

2 years ago
> Am 14.01.2024 um 23:58 schrieb Robert Landers <landers.robert@gmail.com>: > > Hello Internals, > > After much thought and deliberation, I've updated the nameof RFC > (https://wiki.php.net/rfc/nameof) to reflect most of this discussion > and refine a few edge cases regarding objects. TL;DR: there are a few > rules regarding how properties of objects are addressed that I hope a > few people will like (and would make it much more usable in static > contexts, like attributes). > > I'm still not fully settled on the syntax, and this is still very much > a work in progress. So, I'd love feedback in that regard. > > Robert Landers > Software Engineer > Utrecht NL
Hey Robert, In line with ::class, nameof() should never prepend a leading slash. The leading slash is a compile time concept to distinguish namespace relative and global addressing. At runtime everything has a canonical name, without leading slash. Also prepending a slash in code, i.e. '\\'. is much easier than substr(..., 1) to remove, if needed. On the name resolution of things which have a visibility, I wonder whether the visibility is checked or not? In e.g. C# it is. Also, the RFC says a warning will be emitted during compilation. I assume it should be rather be the first time the given line is executed at runtime as PHP doesn't necessarily have access to all identifiers yet when the code is compiled (e.g. referencing something which is included at runtime). Similarly, how often is static:: checked? On every access? Thanks to late static binding it may sometimes exist and sometimes not. I think parent:: is missing in the list of left-hand allowed exceptions. Thanks, Bob

Nick

47 minutes ago
Hey Rob, On 13.05.23 15:27, Robert Landers wrote:
> It is with much trepidation and excitement that I'd like to announce > the `nameof` RFC (https://wiki.php.net/rfc/nameof). It has changed > quite a bit in the last couple of days, so if you haven't seen the > latest draft, please check it out. > > Essentially, it allows using `nameof()` anywhere a string can be used, > even in static contexts. From a developer's perspective, it is a > string and from the engine's perspective, it is also mostly a string > (depending on how deep we want to go on error checking -- see the > RFC).
Every other month I remember this RFC. Would love to see it in 8.7! --- Cheers Nick