marcus-ma/myBlog

一个依赖注入的简单实现

Opened this issue · 0 comments

先看一个例子:

class A{
    public function hello()
    {
        echo "hello world";
    }
}

class B{
    public function say()
    {
        $a=new A;
        $a->hello();
    }
}
$b=new B;
$b->say();

上面代码,我们很容易理解一句话:

B类依赖A类

也就是说,如果今后开发过程中,要对A类修改,一旦涉及函数改名,函数参数数量变动,甚至整个类结构的调整,我们也要对B类做出相应的调整,B类的独立性丧失了,这在开发过程中是很不方便的,也就是我们说的“牵一发动全身”,如果两个类是两个人分别写的,矛盾往往就在这个时候产生了。。。

万一真的要改动A类,有没有办法,可以不去改动或者尽量少改动A类的代码呢?这里要用到控制反转。

高层模块不应该依赖于底层模块,两个都应该依赖抽象。控制反转(IOC)是一种**,依赖注入(DI)是实施这种**的方法。

代码如下:

class A{
    public function hello()
    {
        echo "hello world";
    }
}
class B{
    public function say(A $a)
    {
        $a->hello();
    }
}

$b=new B;
$b->say(new A);

以上其实都是铺垫,下面才是正题:
使用过laravel的人应该对以下写法不陌生:

    public function store(Request $request)
    {
        $name = $request->input('name');
    }

上面的function参数就是注入了Request类,而在写路由的时候我们却只是填写路由对应映射的控制器和方法,并不需要把Request作为参数传进入。

Route::get('user/profile', 'UserController@store')

laravel内部是把实例传参等一些工作帮我们实现好了,但其实其中到底是如何实现的呢?
解决的思路是:在调用函数之前,先获取函数的参数,然后将类参数实例化后作传进函数,最后再调用函数。
问题就是如何获取函数的参数?php手册的反射机制了解一下就好^_^。

以下代码例子就是简单地实现其中的机制:

class A{
    public function hello()
    {
        echo "hello world";
    }
}

class B{
    public function say(A $a)
    {
        $a->hello();
    }
}
function route($className,$classFunction){
    //采用反射机制获取函数参数来完成依赖注入
    $p = new ReflectionMethod($className, $classFunction);
    //获取参数的名
    $a=$p->getParameters()[0]->getClass()->name;
    //调用call_user_func([类实例,'方法'],该方法的参数)
    $b = new $className;
    call_user_func([$b,$classFunction],(new $a));
}
route('B','say');