依赖注入的PHP实现(一)

  突然好奇laravel的依赖注入是怎么实现的,翻看了下laravel的源码,发现在laravel在src/Illuminate/Routing/Route.php下的run方法中开始执行控制器方法

    /**
     * Run the route action and return the response.
     *
     * @return mixed
     */
    public function run()
    {
        $this->container = $this->container ?: new Container;

        try {
            if ($this->isControllerAction()) {
                return $this->runController();
            }

            return $this->runCallable();
        } catch (HttpResponseException $e) {
            return $e->getResponse();
        }
    }

  追踪runController方法,一直到src/Illuminate/Routing/RouteDependencyResolverTrait.php下,我们可以看到,laravel使用反射机制进行依赖注入

    /**
     * Resolve the object method's type-hinted dependencies.
     *
     * @param  array  $parameters
     * @param  object  $instance
     * @param  string  $method
     * @return array
     */
    protected function resolveClassMethodDependencies(array $parameters, $instance, $method)
    {
        if (! method_exists($instance, $method)) {
            return $parameters;
        }

        return $this->resolveMethodDependencies(
            $parameters, new ReflectionMethod($instance, $method)
        );
    }

  通过对laravel源码的查看,网上资料,以及PHP手册的查阅,自己写了个简单的依赖注入实现。

  首先假设存在一个model叫user

class User
{
    public $table = 'users';
}

  然后存在一个控制器叫UserController

class UserController
{

    /**
     * 获取表名称
     *
     * @param  \User  $user
     *
     * @return void
     */
    public static function getTableName(User $user){
        echo $user->table;
    }
}

  可以看到我们的getTableName方法中依赖注入了User类的实例,接下来我们需要通过反射来为这个方法注入参数,注入具体实现如下

class app
{
    /**
     * @param  mixed   $controller  控制器
     * @param  string  $method      方法
     *
     * @throws \ReflectionException
     * @throws \Exception
     */
    public static function run($controller, string $method){

        //判断方法是否存在
        if (! method_exists($controller, $method))
        {
            throw New Exception("Method [$method] is not exist !");
        }

        //通过反射获取方法信息
        $reflectionMethod = New ReflectionMethod($controller,$method);

        //携带参数执行该方法
        $reflectionMethod->invokeArgs(new $controller,self::getMethodParams($reflectionMethod));

    }


    /**
     * 获取方法的参数并实例化
     * @param $reflectionMethod
     *
     * @return array
     * @throws \Exception
     */
    public static function getMethodParams($reflectionMethod) : array
    {
        $result = [];

        foreach ($reflectionMethod->getParameters() as $key => $param) {
            $class = $param->getClass();

            if ($class)
            {
                $result[] = New $class->name(); 
            }else{
                throw New Exception('arguments ' . $key . 'is error!');
            }
        }

        return $result;
    }
}

  最后我们执行方法,打印出User类的table属性,这样我们就通过映射实现了一个简单的依赖注入。

app::run('UserController','getTableName');

  

  所有实例代码如下
  

<?php

//model
class User
{
    public $table = 'users';
}

//控制器
class UserController
{

    /**
     * 获取表名称
     *
     * @param  \User  $user
     *
     * @return void
     */
    public static function getTableName(User $user){
        echo $user->table;
    }
}

//容器
class app
{
    /**
     * @param  mixed   $controller  控制器
     * @param  string  $method      方法
     *
     * @throws \ReflectionException
     * @throws \Exception
     */
    public static function run($controller, string $method){

        //判断方法是否存在
        if (! method_exists($controller, $method))
        {
            throw New Exception("Method [$method] is not exist !");
        }

        //通过反射获取方法信息
        $reflectionMethod = New ReflectionMethod($controller,$method);

        //携带参数执行该方法
        $reflectionMethod->invokeArgs(new $controller,self::getMethodParams($reflectionMethod));

    }


    /**
     * 获取方法的参数并实例化
     * @param $reflectionMethod
     *
     * @return array
     * @throws \Exception
     */
    public static function getMethodParams($reflectionMethod) : array
    {
        $result = [];

        foreach ($reflectionMethod->getParameters() as $key => $param) {
            $class = $param->getClass();

            if ($class)
            {
                $result[] = New $class->name(); 
            }else{
                throw New Exception('arguments ' . $key . 'is error!');
            }
        }

        return $result;
    }
}

app::run('UserController','getTableName');

  

原文地址:https://www.cnblogs.com/zhouyuanpei/p/15775554.html