Skip to content

Instantly share code, notes, and snippets.

@titpetric
Created July 5, 2013 11:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save titpetric/5933966 to your computer and use it in GitHub Desktop.
Save titpetric/5933966 to your computer and use it in GitHub Desktop.
Dependency Injection with Traits (PHP 5.4+)
<?php
namespace AnimalDependencies;
trait Dog {
private $dog = false;
function setDog(\Animals\Dog $dog) {
$this->dog = $dog;
}
function getDog() {
if ($this->dog === false) {
throw new \Exception("I don't have any more 'dog' for you.");
}
return $this->dog;
}
}
trait Cat {
private $cat = false;
function setCat(\Animals\Cat $cat) {
$this->cat = $cat;
}
function getCat() {
if ($this->cat === false) {
throw new \Exception("I don't have any more 'cat' for you.");
}
return $this->cat;
}
}
trait Snake {
private $snake = false;
function setSnake(\Animals\Snake $snake) {
$this->snake = $snake;
}
function getSnake() {
if ($this->snake === false) {
throw new \Exception("I don't have any more 'snake' for you.");
}
return $this->snake;
}
}
trait Turtle {
private $turtle = false;
function setTurtle(\Animals\Turtle $turtle) {
$this->turtle = $turtle;
}
function getTurtle() {
if ($this->turtle === false) {
throw new \Exception("I don't have any more 'turtle' for you.");
}
return $this->turtle;
}
}
<?php
namespace Animals;
class Dog {
public $name = "doggy";
}
class Cat {
public $name = "kitten";
}
class Turtle {
public $name = "raphael";
}
class Snake {
public $name = "trouser";
}
<?php
include("Animals.php");
include("AnimalDependencies.php");
class Petstore
{
use AnimalDependencies\Dog, AnimalDependencies\Cat;
function getInventory()
{
$dog = $this->getDog();
$cat = $this->getCat();
echo "I have a cat named '" . $cat->name . "' and a dog named '" . $dog->name . "'\n";
}
}
class BiggerPetstore extends Petstore
{
use AnimalDependencies\Turtle, AnimalDependencies\Snake;
function getInventory()
{
$turtle = $this->getTurtle();
$snake = $this->getSnake();
parent::getInventory();
echo "I also have a turtle named '".$turtle->name."' and a snake named '".$snake->name."'\n";
}
}
/** This would be the automatic trait/dependency resolver */
class Factory
{
public $registry = array();
public function register($trait, $setup)
{
$this->registry[$trait] = $setup;
}
/** Resolve trait dependencies */
public function resolve($object)
{
$traits = $this->getTraits(get_class($object));
foreach ($traits as $trait) {
echo "Registering trait '".$trait."'\n";
if (isset($this->registry[$trait])) {
$this->registry[$trait]($object);
}
}
}
/** Recursively list all traits defined on final class */
private function getTraits($className, $stack = array())
{
$parent = get_parent_class($className);
if ($parent !== false) {
$stack = $this->getTraits($parent, $stack);
}
$reflection = new ReflectionClass($className);
$traits = $reflection->getTraitNames();
if (is_array($traits)) {
foreach ($traits as $trait) {
$stack[] = $trait;
}
}
return $stack;
}
}
$petstore = new Petstore;
$tests = array();
$tests[] = function() { echo "#1: class with no dependencies set\n"; };
$tests[] = function() use ($petstore) { echo "#2: setting dependency dog\n"; $petstore->setDog(new Animals\Dog); };
$tests[] = function() use ($petstore) { echo "#3: setting dependency cat\n"; $petstore->setCat(new Animals\Cat); };
$i = 1;
foreach ($tests as $test) {
$test();
try {
$petstore->getInventory();
} catch (Exception $e) {
echo $e->getMessage()."\n";
}
}
$factory = new Factory;
// registers dependencies based on trait names, if a class uses a registered trait then
// this would setup the dependencies and inject them into the passed object $o
$factory->register("AnimalDependencies\\Cat", function($o) { $o->setCat(new Animals\Cat); });
$factory->register("AnimalDependencies\\Dog", function($o) { $o->setDog(new Animals\Dog); });
$factory->register("AnimalDependencies\\Snake", function($o) { $o->setSnake(new Animals\Snake); });
$factory->register("AnimalDependencies\\Turtle", function($o) { $o->setTurtle(new Animals\Turtle); });
$petstore = new BiggerPetstore;
// any and all dependencies are automatically resolved
$factory->resolve($petstore);
// use the class.
$petstore->getInventory();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment