README

Dependency Injection framework

Ray.Di was created in order to get Guice style dependency injection in PHP projects. It tries to mirror Guice's behavior and style. Guice is a Java dependency injection framework developed by Google.

Overview

The Ray.Di package provides a dependency injector
with the following features:

constructor and setter injection

automatic injection

post-construct initialization

raw PHP factory code compiler

dependency naming

injection point meta data

instance factories

annotation is optionable

AOP integration

Getting Started

Creating Object graph

With dependency injection, objects accept dependencies in their constructors. To construct an object, you first build its dependencies. But to build each dependency, you need its dependencies, and so on. So when you build an object, you really need to build an object graph.

Building object graphs by hand is labour intensive, error prone, and makes testing difficult. Instead, Ray.Di can build the object graph for you. But first, Ray.Di needs to be configured to build the graph exactly as you want it.

To illustrate, we'll start the BillingService class that accepts its dependent interfaces in its constructor: ProcessorInterface and LoggerInterface.

By building the billingService, we've constructed a small object graph using Ray.Di.

Injections

Constructor Injection

Constructor injection combines instantiation with injection. This constructor should accept class dependencies as parameters. Most constructors will then assign the parameters to properties. You do not need @Inject annotation in constructor.

publicfunction__construct(DbInterface$db) {$this->db=$db; }

Setter Injection

Ray.Di can inject methods that have the @Inject annotation. Dependencies take the form of parameters, which the injector resolves before invoking the method. Injected methods may have any number of parameters, and the method name does not impact injection.

useRay\Di\Di\Inject;

/** * @Inject*/publicfunctionsetDb(DbInterface$db) {$this->db=$db; }

Property Injection

Ray.Di does not support property injection.

Assisted Injection

It is also possible to inject dependencies directly in the invoke method parameter(s). When doing this, add the dependency to the end of the arguments and annotate the method with @Assisted with having assisted parameter(s). You need null default for that parameter.

Bindings

The injector's job is to assemble graphs of objects. You request an instance of a given type, and it figures out what to build, resolves dependencies, and wires everything together. To specify how dependencies are resolved, configure your injector with bindings.

Creating Bindings

To create bindings, extend AbstractModule and override its configure method. In the method body, call bind() to specify each binding. These methods are type checked in compile can report errors if you use the wrong types. Once you've created your modules, pass them as arguments to Injector to build an injector.

Contextual Provider Bindings

You may want to create an object using the context when binding with Provider. For example, you want to inject different connection destinations on the same DB interface. In such a case, we bind it by specifying the context (string) with toProvider ().

Untargeted Bindings

You may create bindings without specifying a target. This is most useful for concrete classes. An untargetted binding informs the injector about a type, so it may prepare dependencies eagerly. Untargetted bindings have no to clause, like so:

Binding Annotations

Occasionally you'll want multiple bindings for a same type. For example, you might want both a PayPal credit card processor and a Google Checkout processor.
To enable this, bindings support an optional binding annotation. The annotation and type together uniquely identify a binding. This pair is called a key.

Define qualifier annotation first. It needs to be annotated with @Qualifier annotation.

The provider can now use the information supplied in the qualifier annotation in order to instantiate
the most appropriate class.

@Named

The most common use of a Qualifier annotation is tagging arguments in a function with a certain label,
the label can be used in the bindings in order to select the right class to be instantiated. For those
cases, Ray.Di comes with a built-in binding annotation @Named that takes a string.

Constructor Bindings

When @Inject annotation cannot be applied to the target constructor or setter method because it is a third party class, Or you simply don't like to use annotations. Constructor Binding provide the solution to this problem. By calling your target constructor explicitly, you don't need reflection and its associated pitfalls. But there are limitations of that approach: manually constructed instances do not participate in AOP.

Aspect Oriented Programing

To compliment dependency injection, Ray.Di supports method interception. This feature enables you to write code that is executed each time a matching method is invoked. It's suited for cross cutting concerns ("aspects"), such as transactions, security and logging. Because interceptors divide a problem into aspects rather than objects, their use is called Aspect Oriented Programming (AOP).

Next, we define the interceptor by implementing the org.aopalliance.intercept.MethodInterceptor interface. When we need to call through to the underlying method, we do so by calling $invocation->proceed():