class Injector implements ContainerInterface (View source)

A simple injection manager that manages creating objects and injecting dependencies between them. It borrows quite a lot from ideas taken from Spring's configuration, but is adapted to the stateless PHP way of doing things.

In its simplest form, the dependency injector can be used as a mechanism to instantiate objects. Simply call

Injector::inst()->get('ClassName')

and a new instance of ClassName will be created and returned to you.

Classes can have specific configuration defined for them to indicate dependencies that should be injected. This takes the form of a static variable $dependencies defined in the class (or configuration), which indicates the name of a property that should be set.

eg

class MyController extends Controller {

     public $permissions;
     public $defaultText;

     static $dependencies = array(
         'defaultText'       => 'Override in configuration',
         'permissions'       => '%$PermissionService',
     );
}

will result in an object of type MyController having the defaultText property set to 'Override in configuration', and an object identified as PermissionService set into the property called 'permissions'. The %$ syntax tells the injector to look the provided name up as an item to be created by the Injector itself.

A key concept of the injector is whether to manage the object as

  • A pseudo-singleton, in that only one item will be created for a particular identifier (but the same class could be used for multiple identifiers)
  • A prototype, where the same configuration is used, but a new object is created each time
  • unmanaged, in which case a new object is created and injected, but no information about its state is managed.

Additional configuration of items managed by the injector can be done by providing configuration for the types, either by manually loading in an array describing the configuration, or by specifying the configuration for a type via SilverStripe's configuration mechanism.

Specify a configuration array of the format

array(
     array(
         'id'            => 'BeanId',                    // the name to be used if diff from the filename
         'priority'      => 1,                           // priority. If another bean is defined with the same ID,
                                                         // but has a lower priority, it is NOT overridden
         'class'         => 'ClassName',                 // the name of the PHP class
         'src'           => '/path/to/file'              // the location of the class
         'type'          => 'singleton|prototype'        // if you want prototype object generation, set it as the
                                                         // type
                                                         // By default, singleton is assumed

         'factory' => 'FactoryService'                   // A factory service to use to create instances.
         'construct'     => array(                       // properties to set at construction
             'scalar',
             '%$BeanId',
         )
         'properties'    => array(
             'name' => 'value'                           // scalar value
             'name' => '%$BeanId',                       // a reference to another bean
             'name' => array(
                 'scalar',
                 '%$BeanId'
             )
         )
     )
     // alternatively
     'MyBean'        => array(
         'class'         => 'ClassName',
     )
     // or simply
     'OtherBean'     => 'SomeClass',
)

In addition to specifying the bindings directly in the configuration, you can simply create a publicly accessible property on the target class which will automatically be injected if the autoScanProperties option is set to true. This means a class defined as

class MyController extends Controller {

     private $permissionService;

     public setPermissionService($p) {
         $this->permissionService = $p;
     }
}

will have setPermissionService called if

  • Injector::inst()->setAutoScanProperties(true) is called and
  • A service named 'PermissionService' has been configured

Constants

SINGLETON

Specify a service type singleton

PROTOTYPE

Specify a service type prototype

Properties

protected Factory $objectCreator

The default factory used to create new instances.

protected ServiceConfigurationLocator $configLocator

Locator for determining Config properties for services

protected Injector $nestedFrom

The injector instance this one was copied from when Injector::nest() was called.

Methods

public
__construct(array $config = null)

Create a new injector.

public static 
inst()

No description

public static 
nest()

Make the newly active Injector be a copy of the current active Injector instance.

public static 
unnest()

Change the active Injector back to the Injector instance the current active Injector object was copied from.

public
setAutoScanProperties(bool $val)

Indicate whether we auto scan injected objects for properties to set.

public
setObjectCreator(Factory $obj)

Sets the default factory to use for creating new objects.

public
getObjectCreator()

No description

public
setConfigLocator(ServiceConfigurationLocator $configLocator)

Set the configuration locator

public
getConfigLocator()

Retrieve the configuration locator

public
setInjectMapping(string $class, string $property, string $toInject, string $injectVia = 'property')

Add in a specific mapping that should be catered for on a type.

public
$this
addAutoProperty(string $property, object $object)

Add an object that should be automatically set on managed objects

public
$this
load(array $config = [])

Load services using the passed in configuration for those services

public
updateSpec(string $id, string $property, mixed $value, bool $append = true)

Update the configuration of an already defined service

protected
updateSpecConstructor(array $spec)

Update a class specification to convert constructor configuration information if needed

public
array|mixed|string
convertServiceProperty(string $value)

Recursively convert a value into its proper representation with service references resolved to actual objects

protected
object
instantiate(array $spec, string $id = null, string $type = null)

Instantiate a managed object

public
inject(object $object, string $asType = null)

Inject $object with available objects from the service cache

protected
setObjectProperty(object $object, string $name, mixed $value)

Helper to set a property's value

public
bool
has(string $name)

Does the given service exist?

public
string|null
getServiceName(string $name)

Does the given service exist, and if so, what's the stored name for it?

public
$this
registerService(object $service, string $replace = null)

Register a service object with an optional name to register it as the service for

public
$this
unregisterNamedObject(string $name)

Removes a named object from the cached list of objects managed by the inject

public
$this
unregisterObjects(array|string $types)

Clear out objects of one or more types that are managed by the injetor.

public
T|mixed
get(T>|string $name, bool $asSingleton = true, array $constructorArgs = [])

Get a named managed object

protected
T|mixed
getNamedService(T>|string $name, bool $asSingleton = true, array $constructorArgs = [])

Returns the service, or null if it doesnt' exist. See get() for main usage.

protected
array
normaliseArguments(string $name, array $args = [])

Detect service references with constructor arguments included.

protected
array
getServiceNamedSpec(string $name, array $constructorArgs = [])

Get or build a named service and specification

public
mixed|object
getServiceSpec(string $name, bool $inherit = true)

Search for spec, lazy-loading in from config locator.

public
T|mixed
__get(T>|string $name)

Magic method to return an item directly

public
T|mixed
create(T>|string $name, mixed $argument = null)

Similar to get() but always returns a new object of the given type

public
T|mixed
createWithArgs(T>|string $name, array $constructorArgs)

Creates an object with the supplied argument array

Details

__construct(array $config = null)

Create a new injector.

Parameters

array $config

Service configuration

static Injector inst()

No description

Return Value

Injector

static Injector nest()

Make the newly active Injector be a copy of the current active Injector instance.

You can then make changes to the injector with methods such as Injector::inst()->registerService() which will be discarded upon a subsequent call to Injector::unnest()

Return Value

Injector

Reference to new active Injector instance

static Injector unnest()

Change the active Injector back to the Injector instance the current active Injector object was copied from.

Return Value

Injector

Reference to restored active Injector instance

setAutoScanProperties(bool $val)

Indicate whether we auto scan injected objects for properties to set.

Parameters

bool $val

setObjectCreator(Factory $obj)

Sets the default factory to use for creating new objects.

Parameters

Factory $obj

Factory getObjectCreator()

No description

Return Value

Factory

setConfigLocator(ServiceConfigurationLocator $configLocator)

Set the configuration locator

Parameters

ServiceConfigurationLocator $configLocator

ServiceConfigurationLocator getConfigLocator()

Retrieve the configuration locator

setInjectMapping(string $class, string $property, string $toInject, string $injectVia = 'property')

Add in a specific mapping that should be catered for on a type.

This allows configuration of what should occur when an object of a particular type is injected, and what items should be injected for those properties / methods.

Parameters

string $class

The class to set a mapping for

string $property

The property to set the mapping for

string $toInject

The registered type that will be injected

string $injectVia

Whether to inject by setting a property or calling a setter

$this addAutoProperty(string $property, object $object)

Add an object that should be automatically set on managed objects

This allows you to specify, for example, that EVERY managed object will be automatically inject with a log object by the following

$injector->addAutoProperty('log', new Logger());

Parameters

string $property

the name of the property

object $object

the object to be set

Return Value

$this

$this load(array $config = [])

Load services using the passed in configuration for those services

Parameters

array $config

Return Value

$this

updateSpec(string $id, string $property, mixed $value, bool $append = true)

Update the configuration of an already defined service

Use this if you don't want to register a complete new config, just append to an existing configuration. Helpful to avoid overwriting someone else's changes

updateSpec('RequestProcessor', 'filters', '%$MyFilter')

Parameters

string $id

The name of the service to update the definition for

string $property

The name of the property to update.

mixed $value

The value to set

bool $append

Whether to append (the default) when the property is an array

protected updateSpecConstructor(array $spec)

Update a class specification to convert constructor configuration information if needed

We do this as a separate process to avoid unneeded calls to convertServiceProperty

Parameters

array $spec

The class specification to update

array|mixed|string convertServiceProperty(string $value)

Recursively convert a value into its proper representation with service references resolved to actual objects

Parameters

string $value

Return Value

array|mixed|string

protected object instantiate(array $spec, string $id = null, string $type = null)

Instantiate a managed object

Given a specification of the form

array( 'class' => 'ClassName', 'properties' => array('property' => 'scalar', 'other' => '%$BeanRef') 'id' => 'ServiceId', 'type' => 'singleton|prototype' )

will create a new object, store it in the service registry, and set any relevant properties

Optionally, you can pass a class name directly for creation

To access this from the outside, you should call ->get('Name') to ensure the appropriate checks are made on the specific type.

Parameters

array $spec

The specification of the class to instantiate

string $id

The name of the object being created. If not supplied, then the id will be inferred from the object being created

string $type

Whether to create as a singleton or prototype object. Allows code to be explicit as to how it wants the object to be returned

Return Value

object

inject(object $object, string $asType = null)

Inject $object with available objects from the service cache

Parameters

object $object

The object to inject

string $asType

The ID this item was loaded as. This is so that the property configuration for a type is referenced correctly in case $object is no longer the same type as the loaded config specification had it as.

protected setObjectProperty(object $object, string $name, mixed $value)

Helper to set a property's value

Parameters

object $object

Set an object's property to a specific value

string $name

The name of the property to set

mixed $value

The value to set

bool has(string $name)

Does the given service exist?

We do a special check here for services that are using compound names. For example, we might want to say that a property should be injected with Log.File or Log.Memory, but have only registered a 'Log' service, we'll instead return that.

Will recursively call itself for each depth of dotting.

Parameters

string $name

Return Value

bool

string|null getServiceName(string $name)

Does the given service exist, and if so, what's the stored name for it?

We do a special check here for services that are using compound names. For example, we might want to say that a property should be injected with Log.File or Log.Memory, but have only registered a 'Log' service, we'll instead return that.

Will recursively call itself for each depth of dotting.

Parameters

string $name

Return Value

string|null

The name of the service (as it might be different from the one passed in)

$this registerService(object $service, string $replace = null)

Register a service object with an optional name to register it as the service for

Parameters

object $service

The object to register

string $replace

The name of the object to replace (if different to the class name of the object to register)

Return Value

$this

$this unregisterNamedObject(string $name)

Removes a named object from the cached list of objects managed by the inject

Parameters

string $name

The name to unregister

Return Value

$this

$this unregisterObjects(array|string $types)

Clear out objects of one or more types that are managed by the injetor.

Parameters

array|string $types

Base class of object (not service name) to remove

Return Value

$this

T|mixed get(T>|string $name, bool $asSingleton = true, array $constructorArgs = [])

Get a named managed object

Will first check to see if the item has been registered as a configured service/bean and return that if so.

Next, will check to see if there's any registered configuration for the given type and will then try and load that

Failing all of that, will just return a new instance of the specified object.

Parameters

T>|string $name

The name of the service to retrieve. If not a registered service, then a class of the given name is instantiated

bool $asSingleton

If set to false a new instance will be returned. If true a singleton will be returned unless the spec is type=prototype'

array $constructorArgs

Args to pass in to the constructor. Note: Ignored for singletons

Return Value

T|mixed

Instance of the specified object

Exceptions

NotFoundExceptionInterface

protected T|mixed getNamedService(T>|string $name, bool $asSingleton = true, array $constructorArgs = [])

Returns the service, or null if it doesnt' exist. See get() for main usage.

Parameters

T>|string $name

The name of the service to retrieve. If not a registered service, then a class of the given name is instantiated

bool $asSingleton

If set to false a new instance will be returned. If true a singleton will be returned unless the spec is type=prototype'

array $constructorArgs

Args to pass in to the constructor. Note: Ignored for singletons

Return Value

T|mixed

Instance of the specified object

protected array normaliseArguments(string $name, array $args = [])

Detect service references with constructor arguments included.

These will be split out of the service name reference and appended to the $args

Parameters

string $name
array $args

Return Value

array

Two items with name and new args

protected array getServiceNamedSpec(string $name, array $constructorArgs = [])

Get or build a named service and specification

Parameters

string $name

Service name

array $constructorArgs

Optional constructor args

Return Value

array

mixed|object getServiceSpec(string $name, bool $inherit = true)

Search for spec, lazy-loading in from config locator.

Falls back to parent service name if unloaded

Parameters

string $name
bool $inherit

Set to true to inherit from parent service if . suffixed E.g. 'Psr/Log/LoggerInterface.custom' would fail over to 'Psr/Log/LoggerInterface'

Return Value

mixed|object

T|mixed __get(T>|string $name)

Magic method to return an item directly

Parameters

T>|string $name

The named object to retrieve

Return Value

T|mixed

T|mixed create(T>|string $name, mixed $argument = null)

Similar to get() but always returns a new object of the given type

Additional parameters are passed through as

Parameters

T>|string $name
mixed $argument

arguments to pass to the constructor

Return Value

T|mixed

A new instance of the specified object

T|mixed createWithArgs(T>|string $name, array $constructorArgs)

Creates an object with the supplied argument array

Parameters

T>|string $name

Name of the class to create an object of

array $constructorArgs

Arguments to pass to the constructor

Return Value

T|mixed