Reflection API: Add ::getFullName() method.

php.internals

Andreas Hennings

8 years ago
I propose a new method ::getFullName() for all methods that implement \Reflector. (I would add it to the \Reflector interface, but this would be a BC break.) The full name would be, depending on the type: function: "str_replace()", "Acme\foo()". class: "Acme\Animal\Cat", "stdClass". method: "Acme\Animal\Cat::meow()". property: "Acme\Animal\Cat::$color". etc. I don't know if we can cover all reflection API classes in a meaningful way. E.g. for ReflectionObject, the full name would be the same as for the class, otherwise it would get complicated. Currently the ::__toString() and ::export() return something else, which is not really useful. The goal is to have something that is different for different items. E.g. a class and a function with the same name need to have a different "full name", hence the added "()" for functions and methods. As a rule of thumb, the "full name" is what one would put after a @see tag in phpDoc, but without the leading "\\". For consistency with the rest of PHP and reflection API, we should use QN and not FQN as return value. Related: I started another thread proposing a ::getHash() method. I originally though to propose the two things in the same thread, but I now think they should be discussed independently.

Marco Pivetta

8 years ago
If you really want to expose a symbol's FQN, I suggest exposing the internal name as per `(array)` cast semantics. namespace A { class B { public $c; private $d; private $e; } } That would be: "A\B#\$c" "A\B#\0*\0\$d" "A\B#\0A\\B\0\$e" Obviously, the `\0` is horrible and can probably be improved: depends on whether the API is intended for human or machine consumption. If it is machine consumption, strings are the wrong approach anyway. I'd also add that this would be (fucking finally!) a good way to fix PHP's documentation horrible usage of `::` for both instance and static members. On 11 Dec 2017 04:00, "Andreas Hennings" <andreas@dqxtech.net> wrote: I propose a new method ::getFullName() for all methods that implement \Reflector. (I would add it to the \Reflector interface, but this would be a BC break.) The full name would be, depending on the type: function: "str_replace()", "Acme\foo()". class: "Acme\Animal\Cat", "stdClass". method: "Acme\Animal\Cat::meow()". property: "Acme\Animal\Cat::$color". etc. I don't know if we can cover all reflection API classes in a meaningful way. E.g. for ReflectionObject, the full name would be the same as for the class, otherwise it would get complicated. Currently the ::__toString() and ::export() return something else, which is not really useful. The goal is to have something that is different for different items. E.g. a class and a function with the same name need to have a different "full name", hence the added "()" for functions and methods. As a rule of thumb, the "full name" is what one would put after a @see tag in phpDoc, but without the leading "\\". For consistency with the rest of PHP and reflection API, we should use QN and not FQN as return value. Related: I started another thread proposing a ::getHash() method. I originally though to propose the two things in the same thread, but I now think they should be discussed independently.
-- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php

Andreas Hennings

8 years ago
On 11 December 2017 at 09:16, Marco Pivetta <ocramius@gmail.com> wrote:
> If you really want to expose a symbol's FQN,
Just to clarify: For me, "FQN" means "fully-qualified name", which begins with "\\". This is specifically not what I propose here. I want the name without the leading namespace separator. So maybe "getFullName()" is misleading.
> I suggest exposing the internal > name as per `(array)` cast semantics.
This distinction is not needed here. The semantics for array keys in array-to-object casting are to distinguish overshadowed private properties from parent classes. This is because values for these properties can coexist within one object. E.g. class B { private $x = 'b'; } class C extends B { private $x = 'c'; } var_export((array)(new C)); Output: https://3v4l.org/0QE3s array ( '' . "\0" . 'C' . "\0" . 'x' => 'c', '' . "\0" . 'B' . "\0" . 'x' => 'b', ) For ReflectionClass->getProperties() and ->getProperty($name) only gives us the version of each property that is visible on the top level. https://3v4l.org/LWWSf E.g. $obj = new (new \ReflectionClass(C::class)->getProperty('x')
> > namespace A { > class B { > public $c; > private $d; > private $e; > } > } > > That would be: > > "A\B#\$c" > "A\B#\0*\0\$d" > "A\B#\0A\\B\0\$e" > > Obviously, the `\0` is horrible and can probably be improved: depends on > whether the API is intended for human or machine consumption. If it is > machine consumption, strings are the wrong approach anyway.
Machine or human? One goal is that these names can be used as array keys or unique identifiers whenever we deal with a collection of reflectors of mixed type. At the same time, the name is designed to be very close to what is printed in exception messages, @see doc comment, etc. In this case, I don't see a conflict between human-readable and machine-readable. Maybe when you say "machine consumption" you are thinking of something else?
> > I'd also add that this would be (fucking finally!) a good way to fix PHP's > documentation horrible usage of `::` for both instance and static members.
Ok, tbh, so far I thought of using the same "::" for both :) So for all properties it would be Cat::$color. Maybe instead we could do Cat->color for instance members?

Marco Pivetta

8 years ago
On Mon, Dec 11, 2017 at 10:03 AM, Andreas Hennings <andreas@dqxtech.net> wrote:
> On 11 December 2017 at 09:16, Marco Pivetta <ocramius@gmail.com> wrote: > > If you really want to expose a symbol's FQN, > > Just to clarify: For me, "FQN" means "fully-qualified name", which > begins with "\\". > This is specifically not what I propose here. I want the name without > the leading namespace separator. > So maybe "getFullName()" is misleading. >
A FQN does not start with `\`. In strings, you always use the FQN
> > > I suggest exposing the internal > > name as per `(array)` cast semantics. > > This distinction is not needed here. > The semantics for array keys in array-to-object casting are to > distinguish overshadowed private properties from parent classes. > This is because values for these properties can coexist within one object. > > E.g. > > class B { > private $x = 'b'; > } > > class C extends B { > private $x = 'c'; > } > > var_export((array)(new C)); > > > Output: https://3v4l.org/0QE3s > > array ( > '' . "\0" . 'C' . "\0" . 'x' => 'c', > '' . "\0" . 'B' . "\0" . 'x' => 'b', > ) > > > For ReflectionClass->getProperties() and ->getProperty($name) only > gives us the version of each property that is visible on the top > level. > > https://3v4l.org/LWWSf > > E.g. > > $obj = new > > (new \ReflectionClass(C::class)->getProperty('x') >
That still makes merging property definitions extremely messy - as a heavy reflection user, I don't see the value in such an API then, besides display (var_dump()) purposes...
> > > namespace A { > > class B { > > public $c; > > private $d; > > private $e; > > } > > } > > > > That would be: > > > > "A\B#\$c" > > "A\B#\0*\0\$d" > > "A\B#\0A\\B\0\$e" > > > > Obviously, the `\0` is horrible and can probably be improved: depends on > > whether the API is intended for human or machine consumption. If it is > > machine consumption, strings are the wrong approach anyway. > > Machine or human? > One goal is that these names can be used as array keys or unique > identifiers whenever we deal with a collection of reflectors of mixed > type. > At the same time, the name is designed to be very close to what is > printed in exception messages, @see doc comment, etc. > In this case, I don't see a conflict between human-readable and > machine-readable. > > Maybe when you say "machine consumption" you are thinking of something > else? >
Machine consumption would be VOs, not strings ;-)
> > > I'd also add that this would be (fucking finally!) a good way to fix > PHP's > > documentation horrible usage of `::` for both instance and static > members. > > Ok, tbh, so far I thought of using the same "::" for both :) > So for all properties it would be Cat::$color. > > Maybe instead we could do Cat->color for instance members? >
I have been using `#` for a while, but I can adapt as long as the problem is being fixed at some point in time :P Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

Andreas Hennings

8 years ago
On 11 December 2017 at 10:16, Marco Pivetta <ocramius@gmail.com> wrote:
> On Mon, Dec 11, 2017 at 10:03 AM, Andreas Hennings <andreas@dqxtech.net> > wrote: >> >> On 11 December 2017 at 09:16, Marco Pivetta <ocramius@gmail.com> wrote: >> > If you really want to expose a symbol's FQN, >> >> Just to clarify: For me, "FQN" means "fully-qualified name", which >> begins with "\\". >> This is specifically not what I propose here. I want the name without >> the leading namespace separator. >> So maybe "getFullName()" is misleading. > > > A FQN does not start with `\`. In strings, you always use the FQN
I was following the FQN definition from php-fig group like here, https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md Maybe this is wrong?

Marco Pivetta

8 years ago
Weird, that looks wrong to me, so I may be wrong here. When receiving a string containing a symbol, the only sensible approach is to consider it a FQN, as no context is provided with the string. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/ On Mon, Dec 11, 2017 at 10:23 AM, Andreas Hennings <andreas@dqxtech.net> wrote:

Andreas Hennings

8 years ago
See http://php.net/manual/en/language.namespaces.rules.php What you mean is a "qualified name" so it would be a QN. On 11 December 2017 at 10:28, Marco Pivetta <ocramius@gmail.com> wrote:

Andreas Hennings

8 years ago
>> > >> > Obviously, the `\0` is horrible and can probably be improved: depends on >> > whether the API is intended for human or machine consumption. If it is >> > machine consumption, strings are the wrong approach anyway. >> >> Machine or human? >> One goal is that these names can be used as array keys or unique >> identifiers whenever we deal with a collection of reflectors of mixed >> type. >> At the same time, the name is designed to be very close to what is >> printed in exception messages, @see doc comment, etc. >> In this case, I don't see a conflict between human-readable and >> machine-readable. >> >> Maybe when you say "machine consumption" you are thinking of something >> else? > > > Machine consumption would be VOs, not strings ;-)
One purpose of such names would be that they can be saved in a file or database, and read in another process. If you want a value object, then why not use the reflector object directly? Ok, because "side effects" - I agree. If we want a value object, it should be named like "ReflectorHandle", and then "ClassHandle", "FunctionHandle" etc. These would provide the name of a class, but not any information about it. But this should be in a separate method, e.g. ReflectionClass->getHandle(), and it would be a separate feature for a separate thread.