-
Notifications
You must be signed in to change notification settings - Fork 1
Named instances
For the next example, we will modify the used classes a little bit:
- Add a new class
Mikey
which implements thePerson
interface - Add a new property
$coDriver
and the matching setter-method to theBMW
class
This is the new code:
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 create an instance of BMW
with this changed code, 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 can 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:
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:
$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:
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 of the method 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.