[RFC] Access to aliases definition by reflection

php.internals

Miloslav Hůla

11 years ago
Good afternoon, I've written an RFC which proposes to expose a namespace aliases/imports for user-land code. https://wiki.php.net/rfc/aliases_by_reflection I would like to ask you to open a discussion. Kind regards, Milo
-- Miloslav Hůla

Alexander Lissachenko

11 years ago
Hello!
> I've written an RFC which proposes to expose a namespace aliases/imports for > user-land code. > > https://wiki.php.net/rfc/aliases_by_reflection
I think that this idea is good, however it isn't correct to keep aliases per each class, because they are applied per scope. TokenReflection library uses ReflectionFileNamespace for that to define a namespace section in the file (there can be many namespaces per one file) and provides an API to fetch aliases. It also provides extended classes with link to the ReflectionFileNamespace. PHP doesn't have a Reflection for that kind of object, however it can be nice to add it to keep an information about namespace start line/end line, file name, imported aliases and defined constants. And add a getters for all other reflection classes, for example, (new ReflectionClass('SomeClass'))->getReflecitonFileNamespace()->getAliases() For PHP7 it can be extended more with AST parser information, for example, add ReflectionSource class that can parse the source code and build a reflection for that source. (new ReflectionSource($fileContent))->getReflectionFileNamespaces()[0]->getAliases(). This patch will help a lot for tools that performs static analysis of source code and provide a good API for userland extensions.

Nikita Popov

11 years ago
On Mon, Oct 13, 2014 at 3:46 PM, Alexander Lisachenko < lisachenko.it@gmail.com> wrote:
> Hello! > > > I've written an RFC which proposes to expose a namespace aliases/imports > for > > user-land code. > > > > https://wiki.php.net/rfc/aliases_by_reflection > > I think that this idea is good, however it isn't correct to keep > aliases per each class, because they are applied per scope. > TokenReflection library uses ReflectionFileNamespace for that to > define a namespace section in the file (there can be many namespaces > per one file) and provides an API to fetch aliases. It also provides > extended classes with link to the ReflectionFileNamespace. >
While good coding style dictates that namespace imports happen at the top of the file, PHP itself places no such restrictions. In particular the following is perfectly valid code: class A {} use Foo\Bar; class B {} Here the declared aliases will be different for classes A and B. This is the reason why the aliases are exposed per-class and per-function. Nikita

Dan Ackroyd

11 years ago
Hi, Wouldn't this RFC be almost instantly deprecated if the Return Type Declarations RFC ( https://wiki.php.net/rfc/returntypehinting ) is accepted? cheers Dan

Miloslav Hůla

11 years ago
Dne 13.10.2014 16:09, Dan Ackroyd napsal(a):
> Wouldn't this RFC be almost instantly deprecated if the Return Type > Declarations RFC ( https://wiki.php.net/rfc/returntypehinting ) is > accepted?
The Return Type Declarations RFC solves problem partially. Aliases expanding is needed for many other annotations. For example some various event or inject systems. Moreover, it is not only about methods, it is about properties too. Milo

Andrew Faulds

11 years ago
On 13 Oct 2014, at 13:55, Miloslav Hůla <miloslav.hula@gmail.com> wrote:
> I've written an RFC which proposes to expose a namespace aliases/imports for user-land code. > > https://wiki.php.net/rfc/aliases_by_reflection
Looks good, but: 1. I think you should also support function aliases here. Constants too would be good, but I’m not sure if they’re actually implemented as aliases (they might just be copies). 2. Shouldn’t it return fully-qualified class names beginning with a backslash?
-- Andrea Faulds http://ajf.me/

Marco Pivetta

11 years ago
On 13 October 2014 16:12, Andrea Faulds <ajf@ajf.me> wrote:
> 2. Shouldn’t it return fully-qualified class names beginning with a > backslash? >
When in string context, we are typically always talking about FQCNs, so the leading backslash is not needed and should be omitted. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

Andrew Faulds

11 years ago
On 13 Oct 2014, at 15:14, Marco Pivetta <ocramius@gmail.com> wrote:
> On 13 October 2014 16:12, Andrea Faulds <ajf@ajf.me> wrote: > 2. Shouldn’t it return fully-qualified class names beginning with a backslash? > > When in string context, we are typically always talking about FQCNs, so the leading backslash is not needed and should be omitted.
I disagree. It shouldn’t be implicitly fully-qualified. If there’s no leading backslash, then you have to add one to actually use it. If it’s a FQCN it should have a \. If and only if it is not a FQCN, it should lack a \.
-- Andrea Faulds http://ajf.me/

Nikita Popov

11 years ago
On Mon, Oct 13, 2014 at 4:21 PM, Andrea Faulds <ajf@ajf.me> wrote:
> > On 13 Oct 2014, at 15:14, Marco Pivetta <ocramius@gmail.com> wrote: > > > On 13 October 2014 16:12, Andrea Faulds <ajf@ajf.me> wrote: > > 2. Shouldn’t it return fully-qualified class names beginning with a > backslash? > > > > When in string context, we are typically always talking about FQCNs, so > the leading backslash is not needed and should be omitted. > > I disagree. It shouldn’t be implicitly fully-qualified. If there’s no > leading backslash, then you have to add one to actually use it. If it’s a > FQCN it should have a \. If and only if it is not a FQCN, it should lack a > \. >
There is nothing here to disagree over, it's not a matter of opinion. Canonical class names in PHP do not use a leading backslash. If you do Foo::class you will get back "Foo" and not "\Foo" or any such nonsense. A leading backslash is only used for literal class name references in the source code. String class names should not be used with a leading backslash (even though we usually tolerate it). Nikita

Miloslav Hůla

11 years ago
Dne 13.10.2014 16:12, Andrea Faulds napsal(a):
> 1. I think you should also support function aliases here. Constants too would be good, but I’m not sure if they’re actually implemented as aliases (they might just be copies).
The function and constant aliasing is a quite new PHP feature. I don't know any use cases which need to expand such aliases. (Sure, it doesn't mean they don't exist). I'll appreciate any example of such usage. Without use cases, it seems to me useless add such functionality. Milo

Miloslav Hůla

11 years ago
Dne 13.10.2014 14:55, Miloslav Hůla napsal(a):
> I've written an RFC which proposes to expose a namespace aliases/imports > for user-land code.
Good morning internals, it has been two weeks since I announced this RFC in this list. I hope all the questions and remarks have been answered. If so, I would like to open voting process in next week. https://wiki.php.net/rfc/aliases_by_reflection (thread of discussion http://php.markmail.org/thread/oqcifqndca4a5tj6) Thank you, Milo

Levi Morrison

11 years ago
On Thu, Oct 30, 2014 at 2:43 AM, Miloslav Hůla <miloslav.hula@gmail.com> wrote:
> Dne 13.10.2014 14:55, Miloslav Hůla napsal(a): >> >> I've written an RFC which proposes to expose a namespace aliases/imports >> for user-land code. > > > Good morning internals, > > it has been two weeks since I announced this RFC in this list. I hope all > the questions and remarks have been answered. If so, I would like to open > voting process in next week. > > https://wiki.php.net/rfc/aliases_by_reflection > > (thread of discussion http://php.markmail.org/thread/oqcifqndca4a5tj6)
I also don't think this feature is needed. In comments, simply use fully qualified names. Additionally, I really don't see how these are related to each other: use Library\Http; class C {} $rc = new ReflectionClass('c'); var_dump($rc->getDefinedAliases()); /* array(1) { ["http"] => string(12) "Library\Http" } */ How is ReflectionClass C related to `Library\HTTP` at all? Definitely a -1 from me.

Miloslav Hůla

11 years ago
Dne 30.10.2014 14:50, Levi Morrison napsal(a):
> I also don't think this feature is needed. In comments, simply use > fully qualified names.
FQN can be used in docblocks, that's true. But if you write some library which uses annotations and you want to offer a kind of comfort to your users, your hands are tied. You force them to use FQN. Personaly, I don't like any code/information duplication. Using FQN when the alias is already defined is wrong. And generally, there is no way how to get defined aliases in current PHP.
> Additionally, I really don't see how these are related to each other: > > use Library\Http; > > class C {} > > $rc = new ReflectionClass('c'); > > var_dump($rc->getDefinedAliases()); > /* > array(1) { > ["http"] => string(12) "Library\Http" > } > */ > > How is ReflectionClass C related to `Library\HTTP` at all?
This example from RFC shows scope of defined aliases only. On the beginning, I was thinking where to place the "access point" to aliases definition. When I realized, that alias can be defined anywhere except a class or function body, ReflectionClass and ReflectionFunction looks like right place. The relation is more obvious in following example: use Library\Http; class C { /** @var Http\Clients\CurlClient */ public $client; } -- Milo

Chris Wright

11 years ago
On 31 October 2014 10:27, Miloslav Hůla <miloslav.hula@gmail.com> wrote:
> Dne 30.10.2014 14:50, Levi Morrison napsal(a): > >> I also don't think this feature is needed. In comments, simply use >> fully qualified names. >> > > FQN can be used in docblocks, that's true. But if you write some library > which uses annotations and you want to offer a kind of comfort to your > users, your hands are tied. You force them to use FQN. > > Personaly, I don't like any code/information duplication. Using FQN when > the alias is already defined is wrong. > > And generally, there is no way how to get defined aliases in current PHP. > > Additionally, I really don't see how these are related to each other: >> >> use Library\Http; >> >> class C {} >> >> $rc = new ReflectionClass('c'); >> >> var_dump($rc->getDefinedAliases()); >> /* >> array(1) { >> ["http"] => string(12) "Library\Http" >> } >> */ >> >> How is ReflectionClass C related to `Library\HTTP` at all? >> > > This example from RFC shows scope of defined aliases only. > > On the beginning, I was thinking where to place the "access point" to > aliases definition. When I realized, that alias can be defined anywhere > except a class or function body, ReflectionClass and ReflectionFunction > looks like right place. > > The relation is more obvious in following example: > > use Library\Http; > > class C > { > /** @var Http\Clients\CurlClient */ > public $client; > } > > > -- Milo >
I agree with Levi, this doesn't make a lot of sense. The only thing that would make sense in terms of supporting aliases for me would be this: <?php use Library\Http\Clients\CurlClient as HttpClient; $rc = new \ReflectionClass('HttpClient'); var_dump($rc->getName()); // string(31) "Library\Http\Clients\CurlClient" I cannot see the value in being able to inspect the compile time constructs at run time, but I can see the value in being able to *use* them in strings at run time. However, even support for this doesn't make a lot of sense without also supporting them everywhere else that strings can be used in place of a class name literal, for example both of these cases would need to work as well: $className = "HttpClient"; $obj = new $className; var_dump($obj instanceof $className); There may be others as well, these are just two that immediately sprang to mind. The getDefinedAliases() code depicted above doesn't really belong on a ReflectionClass, or any of the other classes that currently exist, as the aliases aren't associated with the class/function itself but the environment in which it was defined. Thanks, Chris

Miloslav Hůla

11 years ago
Dne 31.10.2014 12:00, Chris Wright napsal(a):
> I agree with Levi, this doesn't make a lot of sense. The only thing that > would make sense in terms of supporting aliases for me would be this: > > <?php > > use Library\Http\Clients\CurlClient as HttpClient; > > $rc = new \ReflectionClass('HttpClient'); > var_dump($rc->getName()); // string(31) "Library\Http\Clients\CurlClient"
Alias support is not needed here, HttpClient::CLASS can be used for expansion.
> I cannot see the value in being able to inspect the compile time > constructs at run time, but I can see the value in being able to *use* > them in strings at run time.
It starts to make sense, when you use kind of "code analysis". For following techniques, getDefinedAliases() has an added value: <?php use Library\Http\Clients\CurlClient as HttpClient; # Dependency Injection (public property injection) class Downloader { /** * @var HttpClient * @inject */ public $httpClient; } # Factory class HttpClientFactory { /** @return HttpClient */ public function create() { } } This code is analysed in other file. For example in some dependency injection container. In this container, you must care what string 'HttpClient' in annotations really means. What it means in context of classes Downloader and HttpClientFactory. I agree with Levi, that using FQN in annotations works. And I wrote reasons why it is wrong. Moreover, IDEs works with aliases in annotations well. The only missing fragment is, that you cannot access aliases definitions in run-time. That's the reason for the RFC.
> The getDefinedAliases() code depicted above doesn't really belong on a > ReflectionClass, or any of the other classes that currently exist, as > the aliases aren't associated with the class/function itself but the > environment in which it was defined.
An alias can be defined (almost) anywhere. Following is valid PHP code: <?php use Library\One; class C {} use Library\Two; class D {} Alias 'One' exists for class C and D. But alias 'Two' exists only for class D. If you want to resolve an alias to FQN, you must choose a context. But where to get the context in run-time? Class or function reflection seems right. Thank you, Milo

Pierre Joye

11 years ago
On Oct 31, 2014 11:48 PM, "Miloslav Hůla" <miloslav.hula@gmail.com> wrote:
> I agree with Levi, that using FQN in annotations works. And I wrote
reasons why it is wrong. Moreover, IDEs works with aliases in annotations well. The only missing fragment is, that you cannot access aliases definitions in run-time. That's the reason for the RFC. Or add annotations support to php, finally.