Dependency Injection


What? Why? How?

What is Dependency Injection?

"Don't Look for Things! (Ask for them)" - Miško Hevery


Ask Look
  • (explicit)
  • Method Parameters
  • Object Constructor
  • Object Methods
  • (implicit)
  • New
  • Factory / Locator Object
  • Global Scope
  • Functions

class CoffeeMaker {
	public function __construct(IGrinder $grinder, IHeater $heater, IPump $pump) {
		$this->grinder = new Grinder();$grinder;
		$this->heater = Heater::getInstance();$heater;
		$this->pump = $GLOBALS['pump'];$pump;
	}

	public function brew() {
		$this->grinder->grind();
		$this->heater->on();
		$this->pump->pump();
	}
}
						

Two Common Misconceptions:


  1. Requires a Framework.

  2. Just for objects

Why use Dependency Injection?

Advantages:

  • Modular / Reusable
  • Testable
  • Easier to Write
  • Easier to Debug
  • Easier to Change

How?


class Club {
	public function __construct() {
		$this->performers = new Performers();
		$this->bar = Bar::getInstance();
		$this->parkingLot = $GLOBALS['parkingLot'];
	}

	public function open() {
		foreach ($this->performers->dancers as $dancer) {
			$dancer->rightLeg->position('in');
			$dancer->rightLeg->position('out');
		}

		$this->bar->cabinet->stock('bloody mary');
		$this->bar->cabinet->stock('shirley temple');
		$this->bar->cabinet->stock('blue moon');
		$this->bar->barTender->servePatrons();

		$this->parkingLot->waitingCars->park();
	}
}
						

Law of Demeter (principal of least knowledge)

Only talk to your neighbors

$this->neighbor->doStuff();
$this->neighbor->neighborsStuff;
$this->neighbor->neighborsNeighbor()->doStuff();
$GLOBALS['worldGovernment']->enactRule();

The Anti-DI Pattern: Service Locator

Also known as a Manager, Factory, or Container


class Car {
	public function __construct(Factory $factory) {
		$this->engine = $factory->getEngine();
	}

	public function vroomVroom() {
		$this->engine->accelerate();
	}
}

Lightweight Constructor


class ConfigReader {
	public function __construct() {
		$this->config = (object)explode("\n", file_get_contents('config.txt'));
	}

	public function get($key) {
		return $this->config->$key;
	}
}
						

class ConfigReader {
	public function __construct($file) {
		$this->file = $file;
	}

	public function get($key) {
		return $this->getConfig()->$key;
	}

	protected function getConfig() {
		if ($this->config === null) {
			$this->config = explode("\n", file_get_contents($this->file));
		}

		return $this->config;
	}
}
						

class Club {
	public function __construct() {
		$this->performers = new Performers();
		$this->bar = Bar::getInstance();
		$this->parkingLot = $GLOBALS['parkingLot'];
	}

	public function __construct(Performers $performers, Bar $bar, ParkingLot $parkingLot) {
		$this->performers = $performers;
		$this->bar = $bar;
		$this->parkingLot = $parkingLot;
	}

	public function open() {
		foreach ($this->performers->dancers as $dancer) {
			$dancer->rightLeg->position('in');
			$dancer->rightLeg->position('out');
		}

		$this->performers->entertain();

		$this->bar->cabinet->stock('bloody mary');
		$this->bar->cabinet->stock('shirley temple');
		$this->bar->cabinet->stock('blue moon');
		$this->bar->barTender->servePatrons();

		$this->bar->open();

		$this->parkingLot->waitingCars->park();
		$this->parkingLot->open();
	}
}
						

The End

Questions? Comments?


Additional Resources: