Created
July 5, 2013 11:36
-
-
Save titpetric/5933966 to your computer and use it in GitHub Desktop.
Dependency Injection with Traits (PHP 5.4+)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Animals; | |
class Dog { | |
public $name = "doggy"; | |
} | |
class Cat { | |
public $name = "kitten"; | |
} | |
class Turtle { | |
public $name = "raphael"; | |
} | |
class Snake { | |
public $name = "trouser"; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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