百聞不如一 Run 直接上代碼php
<?php
/** * Copyright (C) wujunze.com 2017 All rights reserved. * * @author :Panda(itwujunze@163.com) * @date :2017/08/31 16:08:13 * @version :1.0 * @brief : PHP依賴注入(DI)和容器(IoC)的簡單實現 */
namespace App;
use ReflectionClass;
use ReflectionParameter;
use Closure;
class Car {
public function driveCar($type = '法拉利') {
return "人開{$type}";
}
}
class People {
private $car;
public function __construct(Car $car) {
$this->car = $car;
}
public function run($type) {
return $this->car->driveCar($type);
}
}
class Container {
/** * 容器綁定,用來裝提供的實例或者 提供實例的回調函數 * @var array */
public $building = [];
/** * 註冊一個綁定到容器 * * @param $abstract * @param null $concrete * @param bool $shared */
public function bind($abstract, $concrete = null, $shared = false) {
if (is_null($concrete)) {
$concrete = $abstract;
}
if (!$concrete instanceOf Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->building[$abstract] = compact("concrete", "shared");
}
/**註冊一個共享的綁定 單例 * * @param $abstract * @param $concrete * @param bool $shared */
public function singleton($abstract, $concrete, $shared = true) {
$this->bind($abstract, $concrete, $shared);
}
/** * 默認生成實例的回調閉包 * * @param $abstract * @param $concrete * @return Closure */
public function getClosure($abstract, $concrete) {
return function ($c) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete);
};
}
/** 生成實例 * * @param $abstract * @return mixed|object */
public function make($abstract) {
var_dump($abstract);
echo '--------' . PHP_EOL;
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
return $object;
}
/** * 獲取綁定的回調函數 */
public function getConcrete($abstract) {
if (!isset($this->building[$abstract])) {
return $abstract;
}
return $this->building[$abstract]['concrete'];
}
/** * 判斷 是否 能夠建立服務實體 */
public function isBuildable($concrete, $abstract) {
return $concrete === $abstract || $concrete instanceof Closure;
}
/** * 根據實例具體名稱實例具體對象 */
public function build($concrete) {
if ($concrete instanceof Closure) {
return $concrete($this);
}
//建立反射對象
$reflector = new ReflectionClass($concrete);
if (!$reflector->isInstantiable()) {
//拋出異常
throw new \Exception('沒法實例化');
}
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
return new $concrete;
}
$dependencies = $constructor->getParameters();
$instance = $this->getDependencies($dependencies);
var_dump($instance);
return $reflector->newInstanceArgs($instance);
}
//經過反射解決參數依賴
public function getDependencies(array $dependencies) {
$results = [];
foreach ($dependencies as $dependency) {
$results[] = is_null($dependency->getClass())
? $this->resolvedNonClass($dependency)
: $this->resolvedClass($dependency);
}
return $results;
}
//解決一個沒有類型提示依賴
public function resolvedNonClass(ReflectionParameter $parameter) {
if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
}
throw new \Exception('出錯');
}
//經過容器解決依賴
public function resolvedClass(ReflectionParameter $parameter) {
return $this->make($parameter->getClass()->name);
}
}
/** * 服務容器運行流程 */
//實例化容器類
$app = new Container();
//向容器中填充Car
$app->bind('Car', 'App\Car');
//填充People
$app->bind('People', 'App\People');
//經過容器實現依賴注入,完成類的實例化;
$people = $app->make('People');
//調用方法
echo $people->run('昌河') . PHP_EOL;
複製代碼