tig12.net
Site personnel

Admin
Rubriques proches
PHP

Nombre de visites : 23605
Mise en ligne : 05/2008
Dernière modif : 03/2009

 Notes on PHP Reflection API

Here is a list of missing features or bugs I met while using Reflection API (with PHP Version 5.2.3-1ubuntu6.3) ;

Missing a ReflectionConstant class

It's possible to get information about many things, but constants have been forgotten.
For non-object constants, the only available function I know is get_defined_constants().
For class constants, the only method I know is ReflectionClass::getConstants(), which just gives an array of constant names with their values.
So in both cases, there is no way to retrieve the doc comment, the filename or the line where the constant is defined.

Missing methods in ReflectionProperty class

- getStartLine() is missing
- getFilename() is also missing, but it's possible to get the information through getDeclaringClass()->getFilename().

No doc comments for internal php classes or functions

This feature would permit to generate an API documentation of PHP built-in functions and classes, like Sun does to document java with javadoc.

Problem with interfaces' parents

I was unable to retrieve the direct parents of an interface with the reflection API.
For example :
interface i1{}
interface i2{}
interface i3 extends i1{}
interface i4 extends i1{}
interface i5 extends i4, i2{}
I needed a way to get the direct parents :
for i1 : nothing
for i1 : nothing
for i3 : i1
for i4 : i1
for i5 : i4 and i2

I couldn't deal with the fact that an interface can have several direct parents (multiple inheritance), mixed with the fact that getInterfaces() returns also the indirect ancestors.
I tried also with ReflectionClass::isSubclassOf(), but it returns true for both direct and indirect ancestors.
To solve that problem, I found no other way to parse the file containing the interface definition.

Confusing getParentClass() and getInterfaces()

There is something not logical in ReflectionClass::getParentClass(), because it doesn't act the same way with class and interface.
- For a class, it returns the direct parent.
- For an interface, it returns nothing.
So two things expressed the same way in the code (the clause extends) can't be retrieved by the same method.

The parents of an interface can be obtained through ReflectionClass::getInterfaces() (on this point, documentation is missing in the php manual).
But here is an other incoherence :
- For a class, it returns the implemented interfaces and their ancestors.
- For an interface, it returns the direct parents and the indirect ancestors (grand-parents etc.).
So the same method returns things that are expressed differently in the code (clause implements for a class, and clause extends for an interface).

Bug in ReflectionClass::getDocComment() and ReflectionMethod::getDocComment()

If the doc comment doesn't start exactly by /**, it is not retrieved by the reflection API.
The following code works :
/**
Doc comment for class1
@license  GPL
@author Author of this code
*/
class class1{}
//
$class1 = new ReflectionClass('class1');
$doc1 = $class1->getDocComment();
echo "<pre>"; print_r($doc1); echo "</pre>";
The result is :
/**
Doc comment for class1
@license  GPL
@author Author of this code
*/
But the following code echoes an empty string :
/******************************
Doc comment for class1
@license  GPL
@author Author of this code
******************************/
class class1{}
//
$class1 = new ReflectionClass('class1');
$doc1 = $class1->getDocComment();
echo "<pre>"; print_r($doc1); echo "</pre>";
This happens as soon as the comments starts with more than 2 asterisks.
The same problem occurs with class methods.

Other manifestation of this bug :
/** A constant defined in Class1.php, outside of a class */
define('constant1', 'value of const1'); 

/******************************
Doc comment for class1
@license  GPL
@author Author of this code
******************************/
class class1{}
//
$class1 = new ReflectionClass('class1');
$doc1 = $class1->getDocComment();
echo "<pre>"; print_r($doc1); echo "</pre>";
This echoes :
/** A constant defined in Class1.php, outside of a class */

Fix : this can be patched with a regular expression containing a "not preceeded by" :
 '/\/\*{2,}\s*(?P<comment>(?:[^\/]|(?<!\*)\/)*?)\s*\*+\/\s*/s'
This regex strips the comment, removes the leading /** and trailing */, removes also eventual asterisks after /** or before */, but does not remove the decorative asterisks sometimes found at beginning of lines in doc comments.

Declaring instruction

I wanted to retrieve the exact instruction used to declare an element (class, method etc.), and couldn't achieve this with Reflection API. I tried with getModifiers() and Reflection::getModifierNames(), but didn't suceed.
This code :
class Class1{
  public static function method1(){}
  static public function method2(){}
  static public static public public function method3(){} // yes, this stange syntax is legal...
}
$class1 = new ReflectionClass('Class1');
$method1 = $class1->getMethod('method1');
$method2 = $class1->getMethod('method2');
$method3 = $class1->getMethod('method3');
echo "<br/>method1 : "; print_r(Reflection::getModifierNames($method1->getModifiers()));
echo "<br/>method2 : "; print_r(Reflection::getModifierNames($method2->getModifiers()));
echo "<br/>method3 : "; print_r(Reflection::getModifierNames($method3->getModifiers()));
echoes :
method1 : Array ( [0] => public [1] => static )
method2 : Array ( [0] => public [1] => static )
method3 : Array ( [0] => public [1] => static )
I didn't find a way to retrieve the declaring instruction as it is in the code.
But maybe the need to retrieve the exact declaring instruction of a php element is out of the scope of php reflection API.


--Site écrit avec SPIP--Licence du contenu publié sur ce site--