org::pdepend::reflection - Alternative Reflection for PHP
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:Author:   Manuel Pichler
:Revision: $Revision$
:Date:     $Date$

Design Description
==================

Purpose of Alternative Reflection package
-----------------------------------------

The purpose of the reflection package is to provide a reflection
implementation for PHP that is compatible with PHP's internal reflection
api, but does not require any runtime information about a reflected source
artifact. This allows to analyse a class or interface without loading it
into the applications class scope.

Design
======

The component provides a simple single point of entry interface that can
be used to as a replacement for direct ``ReflectionClass`` instantiations
with productive code. This single point of entry forms the facade class
``ReflectionSession``.

Default configurations
----------------------

The ``ReflectionSession`` will provide some factory methods that return
instances with common configurations of the session class. This solution
is error save and makes adaption easier. Currently we have have identified
the following three configurations.

- *createStaticSession*: Creates a complete static setup, that always
  relies on the information extracted from the source. All unknown
  classes and/or interfaces will be represented by a NULL reflection
  instance that acts as a placeholder.
- *createInternalSession*: Creates a session instance that is just a
  simple wrapper around PHP's internal reflection api.
- *createDefaultSession*: Creates a mix of the static and internal
  reflection implementation. All known classes will be represented by
  an instance of PHP's ``ReflectionClass``, while all unknown classes
  with a source representation are handled by the static reflection
  api.

Factory method signatures
`````````````````````````

- ReflectionSession::createDefaultSession( SourceResolver $resolver )
- ReflectionSession::createStaticSession( SourceResolver $resolver )
- ReflectionSession::createInternalSession()

Switching the reflection strategy
---------------------------------

To allow an easy exchange of the used reflection strategy this component
uses a registry class for the concrete facade used within the application.
This registry can be configured in the application bootstrap file and
then all parts of the application can access the reflection component
through the registry. The name of the used registry class is
``ReflectionSessionInstance``.

The following example shows a simple setup of the reflection component. ::

  <?php
  use org\pdepend\reflection\ReflectionSession;
  use org\pdepend\reflection\resolvers\PearNamingResolver;
  use org\pdepend\reflection\factories\StaticReflectionClassFactory;

  $factory = new new StaticReflectionClassFactory( new PearNamingResolver() );

  $session = new ReflectionSession();
  $session->addClassFactory( $factory );

  ReflectionSessionInstance::set( $session );

Other parts of the application can now access the ``ReflectionSession``
instance through the registry. ::

  <?php
  $session = ReflectionSessionInstance::get();

  $class = $session->getClass( 'PHP_Depend' );

This design makes it really easy to exchange the used reflection strategy,
because only the bootstrap file must be changed.

How to use
==========

Retrieving known class by name
------------------------------

The following code fragment shows how to retrieve a class by its name: The
use case example uses one of the buildin path resolvers to find the source
file for the searched class. ::

  <?php
  use org\pdepend\reflection\ReflectionSession;
  use org\pdepend\reflection\resolvers\PearNamingResolver;
  use org\pdepend\reflection\factories\StaticReflectionClassFactory;

  $factory = new new StaticReflectionClassFactory( new PearNamingResolver() );

  $session = new ReflectionSession();
  $session->addClassFactory( $factory );

  $class = $session->getClass( 'PHP_Depend_Parser' );


Retrieving an internal class by name
------------------------------------

The following example shows how to retrieve a reflection class instance of
an internal PHP class/interface. ::

  <?php
  use org\pdepend\reflection\ReflectionSession;

  $session = ReflectionSession::createRuntimeSession();

  $class = $session->getClass( '\Iterator' );


Retrieving all classes within a file
------------------------------------

The following example shows howto use the reflection class to retrieve
reflection class instances for all classes/interfaces declared within a
single file. ::

  <?php
  use org\pdepend\reflection\ReflectionSession;

  $session = new ReflectionSession();

  $query = $session->createFileQuery();
  foreach ( $query->find( '/home/mapi/projects/pdepend/PHP/Depend.php' ) as $class )
  {
      echo $class->getName(), PHP_EOL;
  }


Retrieving all classes within a directory
-----------------------------------------

The following example shows how to use a the reflection session to retrieve
reflection class instances for all classes/interface declared within the
specified source directory. ::

  <?php
  use org\pdepend\reflection\ReflectionSession;

  $session = new ReflectionSession();

  $query = $session->createDirectoryQuery();
  foreach ( $query->find( '/home/mapi/projects/pdepend/PHP/Depend' ) as $class )
  {
      echo $class->getName(), PHP_EOL;
  }

Retrieving a class by name through the query api
------------------------------------------------

The following example shows how to use the query api of the static
reflection component to retrieve a class by its name. Additionally
this example illustrates the usage of one of session factory methods
that create a common session setup. ::

  <?php
  use org\pdepend\reflection\ReflectionSession;
  use org\pdepend\reflection\resolvers\AutoloadArrayResolver;

  $session = new ReflectionSession::createDefaultSession(
      new AutoloadArrayResolver( $autoload )
  );

  $query = $session->createClassQuery();
  $class = $query->find( '\org\pdepend\reflection\resolver\PearNamingResolver' );

  echo $class->getName(), PHP_EOL;

