First release of the staticReflection component.
Today I have released the first version of the staticReflection component. This component parses the source files of a project to provide reflection information identical to that provided by PHP's build in API, without loading the class declaration into the PHP runtime context. Due to the API compatibility the staticReflection component can simply be used as a drop-in replacement for the reflection extension.
A few weeks ago I started just another script that utilized the tokenizer extension to extract some information from source code files. At that point I thought that the time had come to realize a project that was on my todo for a very long time. And here is the result of the first iteration, a userland reflection implementation that is api compatible with PHP's internal reflection extension. Beside the source parser and the reflection ast this component provides a unified interface to both reflection versions, which makes it easy to switch between different implementations.
As a first use case for this component I have choosen autoload files, as they are used by the eZ Components. The generation of those files is really easy, simply parse a directory with source files and dump the result into a file.
<?php
use org\pdepend\reflection\Autoloader;
use org\pdepend\reflection\ReflectionSession;
// Include the bundled autoloader
include_once 'staticReflection/Autoloader.php';
// Register the autoload function
spl_autoload_register( array( new Autoloader(), 'autoload' ) );
// Create a new session
$session = new ReflectionSession();
// Create a directory query
$query = $session->createDirectoryQuery( );
$autoload = array();
foreach ( $query->find( __DIR__ . '/../../source/' ) as $class )
{
$autoload[$class->getName()] = $class->getFileName();
}
var_export( $autoload );
You can also use the static reflection implementation to analyze different versions of the same class in the same process, which is not possible with the build-in reflection API, because you cannot load multiple classes with the same name into the current runtime context.
Beside parsing of a given directory or file the staticReflection component also supports direct access to a concrete class or interface through the name. Therefor it uses so called source resolvers, that perform a mapping between class names and the associated source files. The current release has two build-in resolvers, one using autoload arrays as they are used by the eZ Components and the other one uses the PEAR naming conventions and the configured include_paths to determine the source file for a given class name. The following example illustrates the usage of the PEAR source resolver.
<?php
use org\pdepend\reflection\Autoloader;
use org\pdepend\reflection\ReflectionSession;
use org\pdepend\reflection\factories\StaticReflectionClassFactory;
use org\pdepend\reflection\resolvers\PearNamingResolver;
include_once 'staticReflection/Autoloader.php';
spl_autoload_register( array( new Autoloader(), 'autoload' ) );
$session = ReflectionSession::createStaticSession(
new PearNamingResolver()
);
$class = $session->getClass( 'PEAR_Frontend' );
echo '- ', $class->getName(), PHP_EOL,
' ', $class->getFileName(), PHP_EOL;
This concept makes the component extremly flexible, because you can write your own source resolver that fulfills the requirements for your application.
Beside the source resolver concept the ReflectionSession can also be configured with a custom stack of ReflectionClassFactory objects that are used to retrieve a reflection class instance for a given class/interface name. To minimize the configuration overhead for common use cases the ReflectionSession
class provides three build-in factory methods that create default session configurations for you:
ReflectionSession::createDefaultSession( SourceResolver )
: This session configuration uses three different backends. First it asks the native backend for a reflection class. When this backend cannot handle the request the static reflection factory is asked for a matching class. Finally this configuration uses the null backend, which always returns an empty placeholder reflection class.ReflectionSession::createStaticSession( SourceResolver )
: This session setup first asks the static reflection implementation for a matching reflection class and falls back to the null backend when no matching class exists.ReflectionSession::createInternalSession()
: This factory method creates a session setup that is a simple wrapper around PHP's internal reflection api.
But you can always build your own session configuration with a custom factory stack, by calling the [ReflectionSession::addClassFactory()](https://tracker.pdepend.org/static_reflection/browse_code/view/source/ReflectionSession.php#line160)
method on the session instance.
<?php
use org\pdepend\reflection\Autoloader;
use org\pdepend\reflection\ReflectionSession;
include_once 'staticReflection/Autoloader.php';
spl_autoload_register( array( new Autoloader(), 'autoload' ) );
$session = new ReflectionSession();
$session->addClassFactory( new MyFooFactory() );
$session->addClassFactory( new MyBarFactory() );
So how can you use this cool component in your application? This is really simple, just replace all ReflectionClass
instantiations with the following code:
<?php
// ...
// Previous instantiation
// $ref = new ReflectionClass( 'Foo_Bar_Baz' );
// New cool solution
$ref = ReflectionSessionInstance::get()->getClass( 'Foo_Bar_Baz' );
And add the following code to your bootstrap file:
<?php
// ...
ReflectionSessionInstance::set(
ReflectionSession::createInternalSession()
);
Finally some words to the requirements and the installation of this component. This component requires PHP in a version greater or equal 5.3.0. For installation you can use PHP_Depend's PEAR channel:
mapi@arwen ~ $ pear channel-discover pear.pdepend.org
mapi@arwen ~ $ pear install pdepend/staticReflection-alpha
or you can download the latest version from the staticReflection svn respository:
mapi@arwen ~ $ svn co http://svn.reflection.pdepend.org/trunk \
staticReflection
Feel free to test this component and file bug-reports and/or feature-requests in the project issue tracker.