Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/boxuk/boxuk-di

Dependency Injection and Reflection Library
https://github.com/boxuk/boxuk-di

Last synced: 5 days ago
JSON representation

Dependency Injection and Reflection Library

Awesome Lists containing this project

README

        

# Unmaintained

# Box UK - Dependency Injection, Reflection and Annotations

The BoxUK-DI library enables you to easily handle dependency injection between components using annotations and type-hinting, similar to Guice and Spring.

## Dependencies

* PHP 5.3+
* Addendum 0.4.0+

## Including the Library

To include the library just include the bootstrap file in your application.


include '../path/to/boxuk-di/lib/bootstrap.php';

## The Standard Injector

The main part of the library is the DI container, a simple example to fetch a class...


$libraryLoader = $injector->getClass( 'LibraryLoader' );

By default, the injector will create a new class each time it's asked for it. Its constructor parameters will be analysed to check types so that any dependencies can be injected into the new object (if these dependencies don't exist they will be created). It's methods will also be checked on creation for any that have been annotated for method injection (see below)

## Scopes

By default, new objects will be instantiated for each requested class. To use objects in a different scope, singleton for example, just annotate them as so:


/**
* @ScopeSingleton
*/
class LibraryLoader {
}

### Available Scopes

#### Singleton

The singleton scope is defined by the annotation @ScopeSingleton, and lasts for the lifetime of a request. Objects annotated as singletons will only be created once by the injector, and then the same object is returned on each subsequent request.


/**
* @ScopeSingleton
*/
class MyClass {}

#### Session

The session scope will store objects in the users session, and these will be available for the lifetime of the session. This can be used for things like a logged in user, a shopping cart, etc... To give a class session scope just annotate it as so.


/**
* @ScopeSession
*/
class MyShoppingCart {}

To use this scope you will first need to define a class that implements the _SessionHandler_ interface and bind it to this name (SessionHandler).

### Interface Binding

If your class is implementing an interface which it is type hinted for then you can specify this by the above annotation:


/**
* @ScopeSingleton(implements="SomeInterface")
*/
class MyClass implements SomeInterface, AnotherInterface {}

Then requests for that interface will return this singleton:


$oInjector->getClass( 'SomeInterface' );

### 3rd Party Singletons

To add 3rd party singletons to the injector just go through the _getScope()_ method.


$this->injector->getScope( 'singleton' )->set( $doctrineManager );

## Method Injection

You can also annotate methods to be injected:


/**
* @InjectMethod
*/
public function setClassLoader( ClassLoader $oClassLoader ) {}

*NB:* When doing method injection there is no constraint on the name of the method, or the number of parameters injected.

### Parameter Types

If your method requires tweaking the injected parameter types then you can specify these with another annotation:


/**
* @InjectMethod
* @InjectParam(variable="class", class="ModuleRegistry")
*/
public function setSomething( SomeInterface $class ) {
// will receive a ModuleRegistry
}

This can also be used for constructors.

## Property Injection

The final type of injection available is property injection. This can be used for public *and* private properties.


/**
* @InjectProperty
* @var SomeClass
*/
private $someClass;

The type of object injected is specified by the *@var* PHPDoc.

## Inheritance

### Methods

When doing method injection, the injector will ascend up the inheritance chain to also inject methods in parent classes. If you override a method in your child class though this method will only be injected (if annotated) in the child class.

### Scopes

When checking a class for scope, the injector will ascend up the inheritance chain and stop at the first scope annotation it encounters.

## Fetching New Classes

To ignore any scope annotations you can force fetching a new instance of the class you want:


$oInjector->getNewClass( 'SomeClass' );

## Constructor Patterns

The one requirement of the injector is that type hinting or _@InjectParam_ annotations need to be used to identify dependencies, so only classes can be dependencies. This makes a clean seperation between class dependencies and class configuration. For classes created with the injector you will not be able to pass in strings or arrays to the constructor. You can think of this as...

1. Objects are dependencies
2. Anything else is configuration

So you will need to remove any configuration from your constructors and injected methods, this will be moved to initialisation time for your class:


$class = $injector->getClass( 'MyClass' );
$class->initialise( $port, array( 'some', 'values' ) );

*NB:* initialise() here is just an arbitrary method on the class being created.

## Using the Injector

So, your class has been injected with all it's dependencies, but what if you want to create more objects inside your class? Well just ask for the injector as one of your dependencies:



private $injector;

public function __construct( BoxUK\Inject\Injector $injector ) {
$this->injector = $injector;
}

private function myMethod() {
$class = $this->injector->getClass( 'SomethingElse' );
}

Don't use the injector as a service locator though inside your class, always specify your dependencies to be injected at construct time.

## Inject Arbitrary Objects

The injector also provides an *inject()* method which can be used to do method injection and property injection on arbitrary objects. These objects can have been created elsewhere but the injector will scan them for dependencies to inject.


$injector->inject( $someObject );

## The Helper

The easiest way to create an injector is to use the _Helper_ class.


$helper = new BoxUK\Inject\Helper();
$injector = $helper->getInjector();

### Configuration

When you create the helper you can pass in a _Config_ object. This example shows a config object generated from an _.ini_ file.


$config = new BoxUK\Inject\Config\IniFile();
$config->initFromFile( 'path/to/file.ini' );
$helper = new BoxUK\Inject\Helper( $config );

The injector will be all set up and ready to go. There are also methods to create reflectors and caches.

## Reflection and Annotations

The second part of the library, which the injector is built on is the reflector. You can use this class to access reflection and annotation information on classes.


$reflector = $helper->getReflector();

### Caching

Reflection can be slow, so for your applications production mode it's reccomended to use the _BoxUK\Reflect\Caching_ reflector instead. You can get this through configuration.


boxuk.reflector = caching

The complete list of configuration options is as follows:


Setting
Values
Default


boxuk.reflector
standard, caching
standard


boxuk.reflector.cache
file, memcache, apc
file


boxuk.reflector.filecache.dir
(path to cache directory)
(sys_get_temp_dir())


boxuk.reflector.filecache.filename
(name of cache file)
$CLASS.cache


boxuk.reflector.memcache.host
(memcache host)
localhost


boxuk.reflector.memcache.port
(memcache port)
11211


boxuk.reflector.memcache.key
(memcache key)
$CLASS


boxuk.reflector.apc.key
(APC key)
$CLASS

_($CLASS means the fully qualified name of the class concerned)_

## Unit Testing

You can unit test these classes using:


phing test