猿问

laravel中Container依赖注入,多次生成类实例

laravelComtroller发现,类依赖注入时,当我通过make创建对象时,发现依赖被创建了多份实例。

代码如下:

<?php

namespace Tests\Unit;

use Illuminate\Container\Container;
use Tests\TestCase;

interface SessionStorage
{
    public function get($key);

    public function set($key, $value);
}

class FileSessionStorage implements SessionStorage
{
    public function __construct()
    {
        echo "file init \n";
    }

    public function get($key)
    {
        // TODO: Implement get() method.
    }

    public function set($key, $value)
    {
        // TODO: Implement set() method.
    }
}

class MySqlSessionStorage implements SessionStorage
{
    public function __construct()
    {
        echo "mysql init \n";
    }

    public function get($key)
    {
        // TODO: Implement get() method.
    }

    public function set($key, $value)
    {
        // TODO: Implement set() method.

    }
}

class SimpleAuth
{
    protected $session;

    public function __construct(SessionStorage $session)
    {
        $this->session = $session;
    }

    public function get()
    {
        $this->session->get(null);
    }

}

class ExampleTest extends TestCase
{
    /**
     * A basic test example.
     *
     * @return void
     */
    public function testBasicTest()
    {
        $container = Container::getInstance();

        $container->bind( SessionStorage::class, MysqlSessionStorage::class );
        $container->make(SimpleAuth::class);
        echo "-\n";

        $container->bind( SessionStorage::class, FileSessionStorage::class );
        $container->make(SimpleAuth::class);
        echo "-\n";

        $container->bind( SessionStorage::class, MysqlSessionStorage::class );
        $container->make(SimpleAuth::class);
    }
}

代码的输出结果如下:

跟预期不同的地方:

  1. 第一次make操作的时候,通过构造函数的输出,可以看出,依赖关系仅仅被实例化了一次
  2. 但后面再次调用bindmake发现构造函数被调用了两次
mysql init 
-
file init 
file init 
-
mysql init 
mysql init 

尝试debug:在make函数中记录调用的次数。:

public function make($abstract, array $parameters = [])
{
    if (stripos($abstract, 'SessionStorage') !== false) {
        echo "make plus \n";
    }
    return $this->resolve($abstract, $parameters);
}

=================== 输出结果 =================
make plus 
make plus 
mysql init 
-
make plus 
make plus 
file init 
make plus 
make plus 
file init 
-
make plus 
make plus 
mysql init 
make plus 
make plus 
mysql init 

怎么破!!!

拉莫斯之舞
浏览 804回答 2
2回答

繁星coding

跟一下源码,能找到问题:1、bind()调用时,会把bind的abstract放在bindings数组中;2、make()调用时,其实调用resolve,如果是单例(singleton)就会在instances中,查到返回就是单例,直接bind的不是单例,所以每次调用会有切仅有一次构造函数调用;3、但是为啥调用了多次,问题在于第二次bind()的时候,因为前面已经make()过(也就是resolve过),所以在bind()函数的最后,会调用rebound()函数,在rebound()函数中会实例化一个abstract用于调用rebound的回调;4、所以,并不是第二次make()的时候调用了两次实例化,而是第二次bind()一次,第二次make()一次;因为第二次bind的时候,会触发rebound; (PS:不知道为啥我上传图片一直失败。。。将就看文字吧)
随时随地看视频慕课网APP
我要回答