Dear List,
I realized the other day that ReflectionFile is missing from the Reflection
API.
A search for "ReflectionFile" on Google will reveal a number of
implementations of classes with exactly that name, which suggests users are
missing this - for example:
https://github.com/rmccue/ReflectionFile/blob/master/ReflectionFile.php
I think reflecting on files used to be less important than it is now - with
the addition of namespaces, and the ability to import classes and
interfaces from other namespaces, there are some interesting and useful
aspects of files that could be exposed via Reflection.
One thing that comes to mind, is with custom annotation libraries for PHP -
some libraries (such as my own) permit you to globally set custom aliases
to make annotation-names shorter and more useful, others resort to making
you type the fully qualified class-name every time you want to apply an
annotation. Neither approach is very elegant. This is addressed by the
language, by allowing you to import classes and interfaces - annotation
libraries could discover imported annotation types this way, but that
aspect of the source code is not exposed via Reflection.
Any thoughts?
- Rasmus Schultz
Hi,
I realized the other day that ReflectionFile is missing from the Reflection
API.
As is ReflectionNamespace and some others one might think about. In the
end it boils down to the fact that we don't have structures internally
representing them as for PHP there is no need to keep the data and then
we're restrictive in adding such meta-data just for the purpose of
reflection. Mind that we'd have to keep all that in memory and opcode
caches have to copy it around etc. in the end the consensus was: the
effort needed doesn't seem worthwhile.
The alternative would be to "emulate" it, something like
class ReflectionFile {
private $filename;
private $classes = array();
private $functions = array();
private initFunctions($filename) {
foreach(get_defined_functions()['user'] as $f) {
$rf = new ReflectionFunction($f);
if ($rf->getFilename() == $filename) {
$this->functions[$rf->getName()] = $rf;
}
}
}
private initClasses($filename) { /* ... */ }
public __construct($filename) {
$this->filename = realpath($filename);
$this->initFunctions($this->filename);
/* ... */
}
public getFunctions() {
return $this->functions;
}
public getFunctionNames() {
return array_keys($this->functions);
}
/* ... */
}
But that feels more like a hack than a solution, too.
johannes
PS. Mind that the example you've given even works on files not included
by parsing files, whereas internal reflection provides information what
actually is available from engine point of view ...
Johannes Schlüter wrote:
PS. Mind that the example you've given even works on files not included
by parsing files, whereas internal reflection provides information what
actually is available from engine point of view ...
The original reason I wrote that class was for a documentation tool, so
that we could discover classes before loading the files.
When I wrote that code, I was also intending to also write extra classes
to eventually replace all of the Reflection APIs with reimplementations,
but was beaten to the punch:
https://github.com/Andrewsville/PHP-Token-Reflection
For some purposes, you need to be able to reflect files and classes
without loading them, which I think is a huge gap in the Reflection API.
That said, a proper ReflectionFile would be welcome, even if it did load
the file.
Ryan McCue
<http://ryanmccue.info/
Ryan McCue wrote:
For some purposes, you need to be able to reflect files and classes
without loading them, which I think is a huge gap in the Reflection API.
That said, a proper ReflectionFile would be welcome, even if it did load
the file.
Forgot to mention: it is also, as far as I know, impossible to get
file-level PHPDoc comments without writing a class similar to mine. (The
alternative is regex parsing, of course, but that's worse)
Ryan McCue
<http://ryanmccue.info/
Johannes Schlüter wrote:
PS. Mind that the example you've given even works on files not included
by parsing files, whereas internal reflection provides information what
actually is available from engine point of view ...The original reason I wrote that class was for a documentation tool, so
that we could discover classes before loading the files.
Right, I can see the need. But I think it is a different project from
the simple "ReflectionFile" thing, as long as that is supposed to work
with the current reflection system.
Doing a "static reflection" from inside PHP is not easy as currently the
parser is bound quite tight to the engine and our compiler, directly
affecting function and class tables. We'd have to split that out and
even if we do that there's one benefit(*) when doing it in PHP userland:
It will always be bound to valid syntax for the given PHP interpreter.
It won't work cross-version when we change the language. (so running 5.3
you couldn't analyze 5.4 code which might use traits etc.) a userland
implementation can be made version independent and updated with support
for new versions without breaking support for the old version.
Of course doing this in userland means cost of performance, but I expect
that IO on the one side and client code using the analyzed data on the
other side have a bigger impact and the difference can almost be
neglected, but that's a guess.
As a remark, there's another static reflection project:
https://github.com/manuelpichler/staticReflection maybe you can work
together? To create the best :-)
johannes
*) of course there are all those other benefits of writing userland code
like being simpler for the user to understand and debug, being simpler
to maintain, which means more potential contributors, ...
Johannes Schlüter wrote:
Right, I can see the need. But I think it is a different project from
the simple "ReflectionFile" thing, as long as that is supposed to work
with the current reflection system.
Definitely, I just thought I'd note the motivation behind that class. In
any case, a ReflectionFile would be great to be able to pick up
file-level details, like the file-level PHPDoc comment.
As a remark, there's another static reflection project:
https://github.com/manuelpichler/staticReflection maybe you can work
together? To create the best :-)
I have no need for the class any more, since I'm using a different
documentation tool instead.
--
Ryan McCue
<http://ryanmccue.info/
From my point of view, the concept of a "file" has become semantically more
important, and increasingly relevant to Reflection, with the latest PHP
features added in the past couple of years.
I can see what you mean though - it's probably not a small effort, and
there are probably more important aspects of PHP that need attention...
2012/1/29 Johannes Schlüter johannes@schlueters.de
Hi,
I realized the other day that ReflectionFile is missing from the
Reflection
API.As is ReflectionNamespace and some others one might think about. In the
end it boils down to the fact that we don't have structures internally
representing them as for PHP there is no need to keep the data and then
we're restrictive in adding such meta-data just for the purpose of
reflection. Mind that we'd have to keep all that in memory and opcode
caches have to copy it around etc. in the end the consensus was: the
effort needed doesn't seem worthwhile.The alternative would be to "emulate" it, something like
class ReflectionFile { private $filename; private $classes = array(); private $functions = array(); private initFunctions($filename) { foreach(get_defined_functions()['user'] as $f) { $rf = new ReflectionFunction($f); if ($rf->getFilename() == $filename) { $this->functions[$rf->getName()] = $rf; } } } private initClasses($filename) { /* ... */ } public __construct($filename) { $this->filename = realpath($filename); $this->initFunctions($this->filename); /* ... */ } public getFunctions() { return $this->functions; } public getFunctionNames() { return array_keys($this->functions); } /* ... */ }
But that feels more like a hack than a solution, too.
johannes
PS. Mind that the example you've given even works on files not included
by parsing files, whereas internal reflection provides information what
actually is available from engine point of view ...
From my point of view, the concept of a "file" has become semantically more
important, and increasingly relevant to Reflection, with the latest PHP
features added in the past couple of years.I can see what you mean though - it's probably not a small effort, and
there are probably more important aspects of PHP that need attention...
When at runtime do you need this? - I can see the need for doing it
"statically" when building some form of autoloading map or such.
For static analysis I (in my personal, probably narrow) opinion see
little benefit in doing it from within PHP (see other part of the
thread)
johannes
Well, my thinking was, in my annotation engine, rather than globally
registering aliases for fully-qualified annotation-type class-names, I
would support the use-statement.
This is generally how it works in other languages (such as C#) that have
built-in support for annotations.
So you'd be able to say "use VendorName\AnnotationLibrary\SomeAnnotation"
at the top of your script, and emulating the PHP name-resolution rules, you
would then be able to annotation classes/properties simply with "@some"
rather than the full class-name.
I know this is very specific to my project, but I could see this being
important to other aspects of meta-programming with PHP in general. Clearly
I'm not the first person who has needed this - there are numerous (more or
less complete) implementations around the net...
Although as said, I see your argument about time/effort vs usefulness, and
I do agree, there are probably other areas of PHP in need of more immediate
attention than this one. It is a problem that can be solved with user-code,
although, as always, that means varying APIs of varying quality, and most
likely some degree of duplication, since each library that needs these
feature is going to implement this feature in different ways...
2012/1/30 Johannes Schlüter johannes@schlueters.de
From my point of view, the concept of a "file" has become semantically
more
important, and increasingly relevant to Reflection, with the latest PHP
features added in the past couple of years.I can see what you mean though - it's probably not a small effort, and
there are probably more important aspects of PHP that need attention...When at runtime do you need this? - I can see the need for doing it
"statically" when building some form of autoloading map or such.For static analysis I (in my personal, probably narrow) opinion see
little benefit in doing it from within PHP (see other part of the
thread)johannes
Well, my thinking was, in my annotation engine, rather than globally
registering aliases for fully-qualified annotation-type class-names, I
would support the use-statement.This is generally how it works in other languages (such as C#) that
have built-in support for annotations.So you'd be able to say "use VendorName\AnnotationLibrary
\SomeAnnotation" at the top of your script, and emulating the PHP
name-resolution rules, you would then be able to annotation
classes/properties simply with "@some" rather than the full
class-name.
In C# you'd still have the compiled assembly around ... actually the
reflected part would even be part to the reflected component, similar to
what you have after doing an include() in PHP.
.. and annotations are different from PHP Reflection, there was a
(rejected) RFC on annotations recently.
I know this is very specific to my project, but I could see this being
important to other aspects of meta-programming with PHP in general.
Clearly I'm not the first person who has needed this - there are
numerous (more or less complete) implementations around the net...
No, it's not too specific. Static analysis and annotations are common
requests.
Although as said, I see your argument about time/effort vs usefulness,
and I do agree, there are probably other areas of PHP in need of more
immediate attention than this one. It is a problem that can be solved
with user-code, although, as always, that means varying APIs of
varying quality, and most likely some degree of duplication, since
each library that needs these feature is going to implement this
feature in different ways...
One might argue this in a more positive way: There's competition and the
best solution will win. One might argue in yet another way: We need a
CPAN for PHP (PEAR anybody?)
The only argument against doing stuff in userland I see is "performance"
and usually the performance issue is somewhere else already and such
things can be neglected ...
johannes
who would love to make the PHP distribution a lot smaller