如今的框架中都有一個容器, 而容器解決依賴的問題是經過反射來達到的,
<!--- more -->
首先先說明一下項目文件結構:php
/ ROOT_PATH ├─src │ ├─Controllers │ │ └─IndexController.php | ├─Application.php (核心,得到實例) │ ├─Http.php │ └─Request.php │ ├─vendor │ └─autoload.php │ ├─composer.json └─index.php
而咱們要運行IndexController.php
,而這個控制器的構造函數須要一個Request
類,而Request
類構造函數須要一個Http
類。git
IndexController.phpgithub
<?php namespace Waitmoonman\Reflex\Controllers; use Waitmoonman\Reflex\Request; class IndexController { /** * 注入一個 Request 類 * IndexController constructor. * @param Request $request */ public function __construct(Request $request) { echo '我是 ' . __CLASS__ . ' 我依賴' . $request->className; } }
Application.phpshell
<?php namespace Waitmoonman\Reflex; use Exception; use ReflectionClass; class Application { /* * @param $class * @param array $parameters * @return mixed * @throws Exception */ public static function make($class, $parameters = []) { // 經過反射獲取反射類 $rel_class = new ReflectionClass($class); // 查看是否能夠實例化 if (! $rel_class->isInstantiable()) { throw new Exception($class . ' 類不可實例化'); } // 查看是否用構造函數 $rel_method = $rel_class->getConstructor(); // 沒有構造函數的話,就能夠直接 new 本類型了 if (is_null($rel_method)) { return new $class(); } // 有構造函數的話就獲取構造函數的參數 $dependencies = $rel_method->getParameters(); // 處理,把傳入的索引數組變成關聯數組, 鍵爲函數參數的名字 foreach ($parameters as $key => $value) { if (is_numeric($key)) { // 刪除索引數組, 只留下關聯數組 unset($parameters[$key]); // 用參數的名字作爲鍵 $parameters[$dependencies[$key]->name] = $value; } } // 處理依賴關係 $actual_parameters = []; foreach ($dependencies as $dependenci) { // 獲取對象名字,若是不是對象返回 null $class_name = $dependenci->getClass(); // 獲取變量的名字 $var_name = $dependenci->getName(); // 若是是對象, 則遞歸new if (array_key_exists($var_name, $parameters)) { $actual_parameters[] = $parameters[$var_name]; } elseif (is_null($class_name)) { // null 則不是對象,看有沒有默認值, 若是沒有就要拋出異常 if (! $dependenci->isDefaultValueAvailable()) { throw new Exception($var_name . ' 參數沒有默認值'); } $actual_parameters[] = $dependenci->getDefaultValue(); } else { $actual_parameters[] = self::make($class_name->getName()); } } // 得到構造函數的數組以後就能夠實例化了 return $rel_class->newInstanceArgs($actual_parameters); } }
Http.phpjson
<?php namespace Waitmoonman\Reflex; class Http { public $className; public function __construct() { $this->className = __CLASS__; } }
Request.php數組
<?php namespace Waitmoonman\Reflex; class Request { public $className; public function __construct(Http $http) { $this->className = __CLASS__; $this->className = $this->className . ' -> ' . $http->className; } }
index.phpcomposer
<?php // 要實現自動載入 use Waitmoonman\Reflex\Application; require 'vendor/autoload.php'; // new 一個 ReflectionClass 類, 放入須要實例的類名 $ctl = Application::make(\Waitmoonman\Reflex\Controllers\IndexController::class); var_dump($ctl);
輸出:框架
我是 Waitmoonman\Reflex\Controllers\IndexController 我依賴Waitmoonman\Reflex\Request -> Waitmoonman\Reflex\Http F:\phpStudy\WWW\reflex\index.php:12: object(Waitmoonman\Reflex\Controllers\IndexController)[9]
這就是一個完整的反射類動態注入參數的實例。
以上代碼能夠查看個人git倉庫函數