PHP 依賴注入 (DI) 和容器 (IoC) 的簡單實現

百聞不如一 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;


複製代碼

高清原圖

相關文章
相關標籤/搜索