Skip to content
This repository has been archived by the owner on Jan 16, 2019. It is now read-only.

Docs IOC NamedInstances

Frank Kleine edited this page Apr 7, 2012 · 1 revision

Inversion of Control: Named instances

For the next example, you have to modify the used classes a little bit:

  1. Add a new class Mikey which implements the Person interface
  2. Add a new property $coDriver and the matching setter-method to the BMW class
#php
<?php
class BMW implements Car {
    protected $driver;
    protected $coDriver;
    protected $engine;
    protected $tire;
    // existing methods left out...
    /**
***@Inject
***/
    public function setCoDriver(Person $coDriver) {
        $this->coDriver = $coDriver;
    }
}

class Mikey implements Person {
    public function sayHello() {
        echo "My name is Frank\n";
    }
}
// existing classes left out
?>

If you now create an instance of BMW, you will get the following object structure:

object(BMW)#35 (4) {
  ["driver:protected"]=>
  object(Schst)#51 (0) {
  }
  ["coDriver:protected"]=>
  object(Schst)#51 (0) {
  }
  ["engine:protected"]=>
  object(TwoLitresEngine)#39 (0) {
  }
  ["tire:protected"]=>
  object(Goodyear)#42 (0) {
  }
}

The properties $driver and $coDriver both contain references to the instance of Schst as both setter methods require an instance that implements the Person interface. In real-life, you would probably be able to inject a different co-driver, but until now, an interface could only be bound to one implementation. This can be changed using the @Named annotation.

Again, you need to modify the BMW class a little bit:

#php
<?php
class BMW implements Car {
    protected $driver;
    protected $coDriver;
    protected $engine;
    protected $tire;
    // existing methods left out...
    /**
***@Inject
***@Named('Co-Driver')
***/
    public function setCoDriver(Person $coDriver) {
        $this->coDriver = $coDriver;
    }
}
?>

By adding the @Named('Co-Driver') annotation, you gave Stubbles the possibility to distinguish the Person instance passed to setCoDriver from all other Person instances. You may now specify a separate binding for this instance:

#php
<?php
$binder->bind('Person')->to('Schst');
$binder->bind('Person')->named('Co-Driver')->to('Mikey');
// other bindings

$injector = $binder->getInjector();
$bmw = $injector->getInstance('Car');
var_dump($bmw);
?>

Now, the $injector will return the following object structure:

object(BMW)#34 (4) {
  ["driver:protected"]=>
  object(Schst)#50 (0) {
  }
  ["coDriver:protected"]=>
  object(Mikey)#57 (0) {
  }
  ["engine:protected"]=>
  object(TwoLitresEngine)#38 (0) {
  }
  ["tire:protected"]=>
  object(Goodyear)#41 (0) {
  }
}

As desired, Stubbles created an instance of the new class Mikey and injected it using the setCoDriver() method. You may use as many named bindings for one type as you like and combine it with all other features like scoping.

Named instances work on setter and constructor injection, and can even be restricted to a certain parameter if the method expects more then one parameter:

#php
<?php
class BMW implements Car {
    protected $driver;
    protected $coDriver;
    protected $engine;
    protected $tire;
    // existing methods left out...
    /**
***@Inject
***@Named{coDriver}('Co-Driver')
***/
    public function setDrivers(Person $driver, Person $coDriver) {
        $this->driver   = $driver;
        $this->coDriver = $coDriver;
    }
}
?>

Here, the @Named annotation is restricted to the $coDriver parameter, but $driver is not restricted. The @Named annotation can be used in several ways:

  • per method, binding all parameters to this name
  • per parameter, binding only the parameter to this name
Please note that a named parameter will overwrite a named method for this parameter, but that you can not overwrite a parameter with the default non-named behaviour if the method is already bound to the name.
Clone this wiki locally