PHP經過反射實現自動注入參數

如今的框架中都有一個容器, 而容器解決依賴的問題是經過反射來達到的,
<!--- 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倉庫函數

相關文章
相關標籤/搜索