成人性生交大片免费看视频r_亚洲综合极品香蕉久久网_在线视频免费观看一区_亚洲精品亚洲人成人网在线播放_国产精品毛片av_久久久久国产精品www_亚洲国产一区二区三区在线播_日韩一区二区三区四区区区_亚洲精品国产无套在线观_国产免费www

主頁 > 知識庫 > 詳解如何實現(xiàn)Laravel的服務容器的方法示例

詳解如何實現(xiàn)Laravel的服務容器的方法示例

熱門標簽:七魚外呼系統(tǒng)停用嗎 阿里云400電話申請加工單 九江外呼系統(tǒng) 智能電話機器人排名前十名南京 海南人工外呼系統(tǒng)有效果嗎 地下城堡2圖九地圖標注 抖音有個地圖標注是什么意思 西區(qū)企業(yè)怎么做地圖標注入駐 保定crm外呼系統(tǒng)運營商

1. 容器的本質

  • 服務容器本身就是一個數(shù)組,鍵名就是服務名,值就是服務。
  • 服務可以是一個原始值,也可以是一個對象,可以說是任意數(shù)據(jù)。
  • 服務名可以是自定義名,也可以是對象的類名,也可以是接口名。
// 服務容器
$container = [
  // 原始值
  'text' => '這是一個字符串',
  // 自定義服務名
  'customName' => new StdClass(),
  // 使用類名作為服務名
  'StdClass' => new StdClass(),
  // 使用接口名作為服務名
  'Namespace\\StdClassInterface' => new StdClass(),
];

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

// 綁定服務到容器
$container['standard'] = new StdClass();
// 獲取服務
$standard = $container['standard'];
var_dump($standard);

2. 封裝成類

為了方便維護,我們把上面的數(shù)組封裝到類里面。

$instances還是上面的容器數(shù)組。我們增加兩個方法,instance用來綁定服務,get用來從容器中獲取服務。

class BaseContainer
{

  // 已綁定的服務
  protected $instances = [];

  // 綁定服務
  public function instance($name, $instance)
  {
    $this->instances[$name] = $instance;
  }

  // 獲取服務
  public function get($name)
  {
    return isset($this->instances[$name]) ? $this->instances[$name] : null;
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

$container = new BaseContainer();
// 綁定服務
$container->instance('StdClass', new StdClass());
// 獲取服務
$stdClass = $container->get('StdClass');
var_dump($stdClass);

3. 按需實例化

現(xiàn)在我們在綁定一個對象服務的時候,就必須要先把類實例化,如果綁定的服務沒有被用到,那么類就會白白實例化,造成性能浪費。

為了解決這個問題,我們增加一個bind函數(shù),它支持綁定一個回調函數(shù),在回調函數(shù)中實例化類。這樣一來,我們只有在使用服務時,才回調這個函數(shù),這樣就實現(xiàn)了按需實例化。

這時候,我們獲取服務時,就不只是從數(shù)組中拿到服務并返回了,還需要判斷如果是回調函數(shù),就要執(zhí)行回調函數(shù)。所以我們把get方法的名字改成make。意思就是生產一個服務,這個服務可以是已綁定的服務,也可以是已綁定的回調函數(shù),也可以是一個類名,如果是類名,我們就直接實例化該類并返回。

然后,我們增加一個新數(shù)組$bindings,用來存儲綁定的回調函數(shù)。然后我們把bind方法改一下,判斷下$instance如果是一個回調函數(shù),就放到$bindings數(shù)組,否則就用make方法實例化類。

class DeferContainer extend BaseContainer
{
  // 已綁定的回調函數(shù)
  protected $bindings = [];

  // 綁定服務
  public function bind($name, $instance)
  {
    if ($instance instanceof Closure) {
      // 如果$instance是一個回調函數(shù),就綁定到bindings。
      $this->bindings[$name] = $instance;
    } else {
      // 調用make方法,創(chuàng)建實例
      $this->instances[$name] = $this->make($name);
    }
  }

  // 獲取服務
  public function make($name)
  {
    if (isset($this->instances[$name])) {
      return $this->instances[$name];
    }

    if (isset($this->bindings[$name])) {
      // 執(zhí)行回調函數(shù)并返回
      $instance = call_user_func($this->bindings[$name]);
    } else {
      // 還沒有綁定到容器中,直接new.
      $instance = new $name();
    }

    return $instance;
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

$container = new DeferContainer();
// 綁定服務
$container->bind('StdClass', function () {
  echo "我被執(zhí)行了\n";
  return new StdClass();
});
// 獲取服務
$stdClass = $container->make('StdClass');
var_dump($stdClass);

StdClass這個服務綁定的是一個回調函數(shù),在回調函數(shù)中才會真正的實例化類。如果沒有用到這個服務,那回調函數(shù)就不會被執(zhí)行,類也不會被實例化。

4. 單例

從上面的代碼中可以看出,每次調用make方法時,都會執(zhí)行一次回調函數(shù),并返回一個新的類實例。但是在某些情況下,我們希望這個實例是一個單例,無論make多少次,只實例化一次。

這時候,我們給bind方法增加第三個參數(shù)$shared,用來標記是否是單例,默認不是單例。然后把回調函數(shù)和這個標記都存到$bindings數(shù)組里。

為了方便綁定單例服務,再增加一個新的方法singleton,它直接調用bind,并且$shared參數(shù)強制為true。

對于make方法,我們也要做修改。在執(zhí)行$bindings里的回調函數(shù)以后,做一個判斷,如果之前綁定時標記的shared是true,就把回調函數(shù)返回的結果存儲到$instances里。由于我們是先從$instances里找服務,所以這樣下次再make的時候就會直接返回,而不會再次執(zhí)行回調函數(shù)。這樣就實現(xiàn)了單例的綁定。

class SingletonContainer extends DeferContainer
{
  // 綁定服務
  public function bind($name, $instance, $shared = false)
  {
    if ($instance instanceof Closure) {
      // 如果$instance是一個回調函數(shù),就綁定到bindings。
      $this->bindings[$name] = [
        'callback' => $instance,
        // 標記是否單例
        'shared' => $shared
      ];
    } else {
      // 調用make方法,創(chuàng)建實例
      $this->instances[$name] = $this->make($name);
    }
  }

  // 綁定一個單例
  public function singleton($name, $instance)
  {
    $this->bind($name, $instance, true);
  }

  // 獲取服務
  public function make($name)
  {
    if (isset($this->instances[$name])) {
      return $this->instances[$name];
    }

    if (isset($this->bindings[$name])) {
      // 執(zhí)行回調函數(shù)并返回
      $instance = call_user_func($this->bindings[$name]['callback']);

      if ($this->bindings[$name]['shared']) {
        // 標記為單例時,存儲到服務中
        $this->instances[$name] = $instance;
      }
    } else {
      // 還沒有綁定到容器中,直接new.
      $instance = new $name();
    }

    return $instance;
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

$container = new SingletonContainer();
// 綁定服務
$container->singleton('anonymous', function () {
  return new class
  {
    public function __construct()
    {
      echo "我被實例化了\n";
    }
  };
});
// 無論make多少次,只會實例化一次
$container->make('anonymous');
$container->make('anonymous');
// 獲取服務
$anonymous = $container->make('anonymous');
var_dump($anonymous)

上面的代碼用singleton綁定了一個名為anonymous的服務,回調函數(shù)里返回了一個匿名類的實例。這個匿名類在被實例化時會輸出一段文字。無論我們make多少次anonymous,這個回調函數(shù)只會被執(zhí)行一次,匿名類也只會被實例化一次。

5. 自動注入

自動注入是Ioc容器的核心,沒有自動注入就無法做到控制反轉。

自動注入就是指,在實例化一個類時,用反射類來獲取__construct所需要的參數(shù),然后根據(jù)參數(shù)的類型,從容器中找到已綁定的服務。我們只要有了__construct方法所需的所有參數(shù),就能自動實例化該類,實現(xiàn)自動注入。

現(xiàn)在,我們增加一個build方法,它只接收一個參數(shù),就是類名。build方法會用反射類來獲取__construct方法所需要的參數(shù),然后返回實例化結果。

另外一點就是,我們之前在調用make方法時,如果傳的是一個未綁定的類,我們直接new了這個類?,F(xiàn)在我們把未綁定的類交給build方法來構建,因為它支持自動注入。

class InjectionContainer extends SingletonContainer
{

  // 獲取服務
  public function make($name)
  {
    if (isset($this->instances[$name])) {
      return $this->instances[$name];
    }
    if (isset($this->bindings[$name])) {
      // 執(zhí)行回調函數(shù)并返回
      $instance = call_user_func($this->bindings[$name]['callback']);

      if ($this->bindings[$name]['shared']) {
        // 標記為單例時,存儲到服務中
        $this->instances[$name] = $instance;
      }
    } else {
      // 使用build方法構建此類
      $instance = $this->build($name);
    }

    return $instance;
  }

  // 構建一個類,并自動注入服務
  public function build($class)
  {

    $reflector = new ReflectionClass($class);

    $constructor = $reflector->getConstructor();

    if (is_null($constructor)) {
      // 沒有構造函數(shù),直接new
      return new $class();
    }

    $dependencies = [];

    // 獲取構造函數(shù)所需的參數(shù)
    foreach ($constructor->getParameters() as $dependency) {
      if (is_null($dependency->getClass())) {
        // 參數(shù)類型不是類時,無法從容器中獲取依賴
        if ($dependency->isDefaultValueAvailable()) {
          // 查找參數(shù)的默認值,如果有就使用默認值
          $dependencies[] = $dependency->getDefaultValue();
        } else {
          // 無法提供類所依賴的參數(shù)
          throw new Exception('找不到依賴參數(shù):' . $dependency->getName());
        }
      } else {
        // 參數(shù)類型是類時,就用make方法構建該類
        $dependencies[] = $this->make($dependency->getClass()->name);
      }
    }

    return $reflector->newInstanceArgs($dependencies);
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

class Redis
{
}

class Cache
{
  protected $redis;

  // 構造函數(shù)中依賴Redis服務
  public function __construct(Redis $redis)
  {
    $this->redis = $redis;
  }
}

$container = new InjectionContainer();
// 綁定Redis服務
$container->singleton(Redis::class, function () {
  return new Redis();
});
// 構建Cache類
$cache = $container->make(Cache::class);
var_dump($cache);

6. 自定義依賴參數(shù)

現(xiàn)在有個問題,如果類依賴的參數(shù)不是類或接口,只是一個普通變量,這時候就無法從容器中獲取依賴參數(shù)了,也就無法實例化類了。

那么接下來我們就支持一個新功能,在調用make方法時,支持傳第二個參數(shù)$parameters,這是一個數(shù)組,無法從容器中獲取的依賴,就從這個數(shù)組中找。

當然,make方法是用不到這個參數(shù)的,因為它不負責實例化類,它直接傳給build方法。在build方法尋找依賴的參數(shù)時,就先從$parameters中找。這樣就實現(xiàn)了自定義依賴參數(shù)。

需要注意的一點是,build方法是按照參數(shù)的名字來找依賴的,所以parameters中的鍵名也必須跟__construct中參數(shù)名一致。

class ParametersContainer extends InjectionContainer
{
  // 獲取服務
  public function make($name, array $parameters = [])
  {
    if (isset($this->instances[$name])) {
      return $this->instances[$name];
    }
    if (isset($this->bindings[$name])) {
      // 執(zhí)行回調函數(shù)并返回
      $instance = call_user_func($this->bindings[$name]['callback']);

      if ($this->bindings[$name]['shared']) {
        // 標記為單例時,存儲到服務中
        $this->instances[$name] = $instance;
      }
    } else {
      // 使用build方法構建此類
      $instance = $this->build($name, $parameters);
    }

    return $instance;
  }

  // 構建一個類,并自動注入服務
  public function build($class, array $parameters = [])
  {
    $reflector = new ReflectionClass($class);

    $constructor = $reflector->getConstructor();

    if (is_null($constructor)) {
      // 沒有構造函數(shù),直接new
      return new $class();
    }

    $dependencies = [];

    // 獲取構造函數(shù)所需的參數(shù)
    foreach ($constructor->getParameters() as $dependency) {

      if (isset($parameters[$dependency->getName()])) {
        // 先從自定義參數(shù)中查找
        $dependencies[] = $parameters[$dependency->getName()];
        continue;
      }

      if (is_null($dependency->getClass())) {
        // 參數(shù)類型不是類或接口時,無法從容器中獲取依賴
        if ($dependency->isDefaultValueAvailable()) {
          // 查找默認值,如果有就使用默認值
          $dependencies[] = $dependency->getDefaultValue();
        } else {
          // 無法提供類所依賴的參數(shù)
          throw new Exception('找不到依賴參數(shù):' . $dependency->getName());
        }
      } else {
        // 參數(shù)類型是類時,就用make方法構建該類
        $dependencies[] = $this->make($dependency->getClass()->name);
      }
    }

    return $reflector->newInstanceArgs($dependencies);
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

class Redis
{
}

class Cache
{
  protected $redis;

  protected $name;

  protected $default;

  // 構造函數(shù)中依賴Redis服務和name參數(shù),name的類型不是類,無法從容器中查找
  public function __construct(Redis $redis, $name, $default = '默認值')
  {
    $this->redis = $redis;
    $this->name = $name;
    $this->default = $default;
  }
}

$container = new ParametersContainer();
// 綁定Redis服務
$container->singleton(Redis::class, function () {
  return new Redis();
});
// 構建Cache類
$cache = $container->make(Cache::class, ['name' => 'test']);
var_dump($cache);

提示:實際上,Laravel容器的build方法并沒有第二個參數(shù)$parameters,它是用類屬性來維護自定義參數(shù)。原理都是一樣的,只是實現(xiàn)方式不一樣。這里為了方便理解,不引入過多概念。

7. 服務別名

別名可以理解成小名、外號。服務別名就是給已綁定的服務設置一些外號,使我們通過外號也能找到該服務。

這個就比較簡單了,我們增加一個新的數(shù)組$aliases,用來存儲別名。再增加一個方法alias,用來讓外部注冊別名。

唯一需要我們修改的地方,就是在make時,要先從$aliases中找到真實的服務名。

class AliasContainer extends ParametersContainer
{
  // 服務別名
  protected $aliases = [];

  // 給服務綁定一個別名
  public function alias($alias, $name)
  {
    $this->aliases[$alias] = $name;
  }

  // 獲取服務
  public function make($name, array $parameters = [])
  {
    // 先用別名查找真實服務名
    $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;

    return parent::make($name, $parameters);
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

$container = new AliasContainer();

// 綁定服務
$container->instance('text', '這是一個字符串');
// 給服務注冊別名
$container->alias('string', 'text');
$container->alias('content', 'text');

var_dump($container->make('string'));
var_dump($container->make('content'));

8. 擴展綁定

有時候我們需要給已綁定的服務做一個包裝,這時候就用到擴展綁定了。我們先看一個實際的用法,理解它的作用后,才看它是如何實現(xiàn)的。

// 綁定日志服務
$container->singleton('log', new Log());

// 對已綁定的服務再次包裝
$container->extend('log', function(Log $log){
  // 返回了一個新服務
  return new RedisLog($log);
});

現(xiàn)在我們看它是如何實現(xiàn)的。增加一個$extenders數(shù)組,用來存放擴展器。再增加一個extend方法,用來注冊擴展器。

然后在make方法返回$instance之前,按順序依次調用之前注冊的擴展器。

class ExtendContainer extends AliasContainer
{
  // 存放擴展器的數(shù)組
  protected $extenders = [];

  // 給服務綁定擴展器
  public function extend($name, $extender)
  {
    if (isset($this->instances[$name])) {
      // 已經實例化的服務,直接調用擴展器
      $this->instances[$name] = $extender($this->instances[$name]);
    } else {
      $this->extenders[$name][] = $extender;
    }
  }

  // 獲取服務
  public function make($name, array $parameters = [])
  {
    $instance = parent::make($name, $parameters);

    if (isset($this->extenders[$name])) {
      // 調用擴展器
      foreach ($this->extenders[$name] as $extender) {
        $instance = $extender($instance);
      }
    }

    return $instance;
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

class Redis
{
  public $name;

  public function __construct($name = 'default')
  {
    $this->name = $name;
  }

  public function setName($name)
  {
    $this->name = $name;
  }
}

$container = new ExtendContainer();

// 綁定Redis服務
$container->singleton(Redis::class, function () {
  return new Redis();
});

// 給Redis服務綁定一個擴展器
$container->extend(Redis::class, function (Redis $redis) {
  $redis->setName('擴展器');
  return $redis;
});
$redis = $container->make(Redis::class);
var_dump($redis->name);

9. 上下文綁定

有時侯我們可能有兩個類使用同一個接口,但希望在每個類中注入不同的實現(xiàn),例如兩個控制器,分別為它們注入不同的Log服務。

class ApiController
{
  public function __construct(Log $log)
  {
  }
}

class WebController
{
  public function __construct(Log $log)
  {
  }
}

最終我們要用以下方式實現(xiàn):

// 當ApiController依賴Log時,給它一個RedisLog
$container->addContextualBinding('ApiController','Log',new RedisLog());

// 當WebController依賴Log時,給它一個FileLog
$container->addContextualBinding('WebController','Log',new FileLog());

為了更直觀更方便更語義化的使用,我們把這個過程改成鏈式操作:

$container->when('ApiController')
    ->needs('Log')
    ->give(new RedisLog());

我們增加一個$context數(shù)組,用來存儲上下文。同時增加一個addContextualBinding方法,用來注冊上下文綁定。以ApiController為例,$context的真實模樣是:

$context['ApiController']['Log'] = new RedisLog();

然后build方法實例化類時,先從上下文中查找依賴參數(shù),就實現(xiàn)了上下文綁定。

接下來,看看鏈式操作是如何實現(xiàn)的。

首先定義一個類Context,這個類有兩個方法,needs和give。

然后在容器中,增加一個when方法,它返回一個Context對象。在Context對象的give方法中,我們已經具備了注冊上下文所需要的所有參數(shù),所以就可以在give方法中調用addContextualBinding來注冊上下文了。

class ContextContainer extends ExtendContainer
{
  // 依賴上下文
  protected $context = [];

  // 構建一個類,并自動注入服務
  public function build($class, array $parameters = [])
  {
    $reflector = new ReflectionClass($class);

    $constructor = $reflector->getConstructor();

    if (is_null($constructor)) {
      // 沒有構造函數(shù),直接new
      return new $class();
    }

    $dependencies = [];

    // 獲取構造函數(shù)所需的參數(shù)
    foreach ($constructor->getParameters() as $dependency) {

      if (isset($this->context[$class])  isset($this->context[$class][$dependency->getName()])) {
        // 先從上下文中查找
        $dependencies[] = $this->context[$class][$dependency->getName()];
        continue;
      }

      if (isset($parameters[$dependency->getName()])) {
        // 從自定義參數(shù)中查找
        $dependencies[] = $parameters[$dependency->getName()];
        continue;
      }

      if (is_null($dependency->getClass())) {
        // 參數(shù)類型不是類或接口時,無法從容器中獲取依賴
        if ($dependency->isDefaultValueAvailable()) {
          // 查找默認值,如果有就使用默認值
          $dependencies[] = $dependency->getDefaultValue();
        } else {
          // 無法提供類所依賴的參數(shù)
          throw new Exception('找不到依賴參數(shù):' . $dependency->getName());
        }
      } else {
        // 參數(shù)類型是一個類時,就用make方法構建該類
        $dependencies[] = $this->make($dependency->getClass()->name);
      }
    }

    return $reflector->newInstanceArgs($dependencies);
  }

  // 綁定上下文
  public function addContextualBinding($when, $needs, $give)
  {
    $this->context[$when][$needs] = $give;
  }

  // 支持鏈式方式綁定上下文
  public function when($when)
  {
    return new Context($when, $this);
  }
}

class Context
{
  protected $when;

  protected $needs;

  protected $container;

  public function __construct($when, ContextContainer $container)
  {
    $this->when = $when;
    $this->container = $container;
  }

  public function needs($needs)
  {
    $this->needs = $needs;

    return $this;
  }

  public function give($give)
  {
    // 調用容器綁定依賴上下文
    $this->container->addContextualBinding($this->when, $this->needs, $give);
  }
}

// ----------- ↓↓↓↓示例代碼↓↓↓↓ ----------- //

class Dog
{
  public $name;

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

class Cat
{
  public $name;

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

$container = new ContextContainer();

// 給Dog類設置上下文綁定
$container->when(Dog::class)
  ->needs('name')
  ->give('小狗');
// 給Cat類設置上下文綁定
$container->when(Cat::class)
  ->needs('name')
  ->give('小貓');

$dog = $container->make(Dog::class);
$cat = $container->make(Cat::class);
var_dump('Dog:' . $dog->name);
var_dump('Cat:' . $cat->name);

10. 完整代碼

class Container
{
  // 已綁定的服務
  protected $instances = [];
  // 已綁定的回調函數(shù)
  protected $bindings = [];
  // 服務別名
  protected $aliases = [];
  // 存放擴展器的數(shù)組
  protected $extenders = [];
  // 依賴上下文
  protected $context = [];

  // 綁定服務實例
  public function instance($name, $instance)
  {
    $this->instances[$name] = $instance;
  }

  // 綁定服務
  public function bind($name, $instance, $shared = false)
  {
    if ($instance instanceof Closure) {
      // 如果$instance是一個回調函數(shù),就綁定到bindings。
      $this->bindings[$name] = [
        'callback' => $instance,
        // 標記是否單例
        'shared' => $shared
      ];
    } else {
      // 調用make方法,創(chuàng)建實例
      $this->instances[$name] = $this->make($name);
    }
  }

  // 綁定一個單例
  public function singleton($name, $instance)
  {
    $this->bind($name, $instance, true);
  }

  // 給服務綁定一個別名
  public function alias($alias, $name)
  {
    $this->aliases[$alias] = $name;
  }

  // 給服務綁定擴展器
  public function extend($name, $extender)
  {
    if (isset($this->instances[$name])) {
      // 已經實例化的服務,直接調用擴展器
      $this->instances[$name] = $extender($this->instances[$name]);
    } else {
      $this->extenders[$name][] = $extender;
    }
  }

  // 獲取服務
  public function make($name, array $parameters = [])
  {
    // 先用別名查找真實服務名
    $name = isset($this->aliases[$name]) ? $this->aliases[$name] : $name;

    if (isset($this->instances[$name])) {
      return $this->instances[$name];
    }

    if (isset($this->bindings[$name])) {
      // 執(zhí)行回調函數(shù)并返回
      $instance = call_user_func($this->bindings[$name]['callback']);

      if ($this->bindings[$name]['shared']) {
        // 標記為單例時,存儲到服務中
        $this->instances[$name] = $instance;
      }
    } else {
      // 使用build方法構建此類
      $instance = $this->build($name, $parameters);
    }

    if (isset($this->extenders[$name])) {
      // 調用擴展器
      foreach ($this->extenders[$name] as $extender) {
        $instance = $extender($instance);
      }
    }

    return $instance;
  }

  // 構建一個類,并自動注入服務
  public function build($class, array $parameters = [])
  {
    $reflector = new ReflectionClass($class);

    $constructor = $reflector->getConstructor();

    if (is_null($constructor)) {
      // 沒有構造函數(shù),直接new
      return new $class();
    }

    $dependencies = [];

    // 獲取構造函數(shù)所需的參數(shù)
    foreach ($constructor->getParameters() as $dependency) {

      if (isset($this->context[$class])  isset($this->context[$class][$dependency->getName()])) {
        // 先從上下文中查找
        $dependencies[] = $this->context[$class][$dependency->getName()];
        continue;
      }

      if (isset($parameters[$dependency->getName()])) {
        // 從自定義參數(shù)中查找
        $dependencies[] = $parameters[$dependency->getName()];
        continue;
      }

      if (is_null($dependency->getClass())) {
        // 參數(shù)類型不是類或接口時,無法從容器中獲取依賴
        if ($dependency->isDefaultValueAvailable()) {
          // 查找默認值,如果有就使用默認值
          $dependencies[] = $dependency->getDefaultValue();
        } else {
          // 無法提供類所依賴的參數(shù)
          throw new Exception('找不到依賴參數(shù):' . $dependency->getName());
        }
      } else {
        // 參數(shù)類型是一個類時,就用make方法構建該類
        $dependencies[] = $this->make($dependency->getClass()->name);
      }
    }

    return $reflector->newInstanceArgs($dependencies);
  }

  // 綁定上下文
  public function addContextualBinding($when, $needs, $give)
  {
    $this->context[$when][$needs] = $give;
  }

  // 支持鏈式方式綁定上下文
  public function when($when)
  {
    return new Context($when, $this);
  }
}

class Context
{
  protected $when;

  protected $needs;

  protected $container;

  public function __construct($when, Container $container)
  {
    $this->when = $when;
    $this->container = $container;
  }

  public function needs($needs)
  {
    $this->needs = $needs;

    return $this;
  }

  public function give($give)
  {
    // 調用容器綁定依賴上下文
    $this->container->addContextualBinding($this->when, $this->needs, $give);
  }
}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:
  • Laravel服務容器綁定的幾種方法總結
  • 詳解Laravel服務容器的綁定與解析
  • laravel ajax curd 搜索登錄判斷功能的實現(xiàn)
  • Laravel中Kafka的使用詳解
  • laravel使用redis隊列實例講解
  • Laravel的加密解密與哈希實例講解
  • Laravel中10個有用的用法小結
  • 詳解Laravel服務容器的優(yōu)勢

標簽:昭通 十堰 九江 韶關 甘肅 遼陽 梅河口 涼山

巨人網絡通訊聲明:本文標題《詳解如何實現(xiàn)Laravel的服務容器的方法示例》,本文關鍵詞  詳解,如何,實現(xiàn),Laravel,的,;如發(fā)現(xiàn)本文內容存在版權問題,煩請?zhí)峁┫嚓P信息告之我們,我們將及時溝通與處理。本站內容系統(tǒng)采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《詳解如何實現(xiàn)Laravel的服務容器的方法示例》相關的同類信息!
  • 本頁收集關于詳解如何實現(xiàn)Laravel的服務容器的方法示例的相關信息資訊供網民參考!
  • 推薦文章
    国产精品视频自在线| 亚洲911精品成人18网站| 天天夜碰日日摸日日澡性色av| 999人在线精品播放视频| 里番在线观看网站| 夜夜嗨aⅴ一区二区三区| 欧美日韩久久婷婷| 5g影院天天爽成人免费下载| 美女毛片在线看| 欧洲av在线播放| 人妻av中文系列| 欧美久久婷婷综合色| 欧洲一区二区三区精品| 亚洲怡红院在线观看| 51色欧美片视频在线观看| 92国产精品久久久久首页| 五月天综合视频| www.亚洲黄色| 91玉足脚交白嫩脚丫| 青青草成人网| 国产成人精品亚洲日本在线桃色| av无码久久久久久不卡网站| 成人在线中文字幕| 久久精品水蜜桃av综合天堂| 欧美老肥妇做.爰bbww| 国产黑丝在线视频| 伊人久久av导航| 伊人婷婷欧美激情| 国产91ⅴ在线精品免费观看| 免费在线看黄色| 欧美一级电影免费在线观看| 狠狠色综合欧美激情| 成人手机在线免费视频| 欧美性生活影院| 久久这里只精品最新地址| 欧美精品三级在线| 老司机精品导航| 免费毛片在线播放免费| 狠狠色伊人亚洲综合网站色| 国产女女做受ⅹxx高潮| 每日更新av在线播放| 欧美伊人久久大香线蕉综合69| 国产一级免费观看| 国产探花在线免费观看| 欧美亚洲丝袜传媒另类| 国产视频亚洲| 啦啦啦高清在线观看www| 一本色道久久88综合日韩精品| 国产破处视频在线观看| 九九热这里有精品视频| 一区二区在线免费观看| 国产麻豆成人精品| 日本激情一区二区三区| 视频一区二区三区免费观看| 波多野结衣综合网| 国产成人无码精品亚洲| 欧美性天天影院| 欧美三级电影一区二区三区| 99re8这里只有精品| 性网站在线免费观看| 正在播放久久| 国产一区二区三区久久悠悠色av| 天堂网视频在线| 欧美性猛交一区二区三区精品| 少妇太紧太爽又黄又硬又爽小说| 国产欧美日韩在线一区二区| 成人免费电影视频| 亚洲免费看黄网站| 国产成人精品亚洲精品| 影音先锋中文字幕一区| 国产盗摄——sm在线视频| 三级黄色网址| 麻豆md0077饥渴少妇| 五月婷婷激情久久| 久久99久久98精品免观看软件| www在线观看播放免费视频日本| 在线看黄的网站| 看一级黄色录像| 亚洲第九十七页| 国产欧美视频在线观看| 欧美一区二区三区免费视频| 日皮视频在线免费观看| 亚洲а∨天堂久久精品2021| 黄色av免费在线| 亚洲男女视频在线观看| 亚洲av无码片一区二区三区| 1000部国产精品成人观看| 中文字幕第一页在线视频| 国产精品高清在线| 国产a∨精品一区二区三区仙踪林| 99精品视频免费版的特色功能| 尤物在线观看一区| 国产探花在线播放| 在线免费观看黄色网址| 成人片在线看| 国精产品一区一区三区有限在线| 麻豆成人小视频| 一本色道久久综合狠狠躁篇的优点| 一区二区不卡在线观看| va中文字幕| a级免费观看| 91成人在线观看喷潮| 国产一区二区三区成人欧美日韩在线观看| 欧美激情三区| 天堂中文字幕av| 91精品国产综合久久精品麻豆| 国产成人精品久久一区二区小说| 91精品啪在线观看国产60岁| 黑人巨大精品欧美一区二区桃花岛| 欧美偷拍一区二区三区| brazzers在线观看| 亚洲国产成人在线| 欧美性猛交xxxx乱大交退制版| 999福利在线视频| 日本h片在线观看| 日韩欧美一区二区三区免费看| 欧美激情国产精品日韩| 国产女主播福利| 国产自产高清不卡| 污污动漫在线观看| 亚洲欧美视频二区| 免费av成人在线| 久本草在线中文字幕亚洲| 一区二区三区精品| 亚洲电影网站| 成人精品国产福利| 国产精品99久久久久久人| 久久久久久人妻一区二区三区| 激情五月婷婷综合网| 亚洲成人自拍视频| 亚洲人精品午夜在线观看| 免费在线观看a级片| 久久精品国产亚洲| 国产精品传媒精东影业在线| 男人操女人免费| 久久精品欧美一区| 一级毛片aaaaaa免费看| 精品美女在线观看视频在线观看| 91在线观看污| 国产精品午夜一区二区欲梦| 亚洲小说图片视频| 不卡精品视频| 亚洲国产一区二区在线观看| 亚洲小视频网站| 亚洲人成在线影院| 欧美xxxxx精品| 久久亚洲综合av| 日韩激情电影| 中文字幕在线观| 欧美中文字幕视频| 国产麻豆精品在线观看| 亚洲国产高清在线| 欧美黑人极品猛少妇色xxxxx| 日韩av影视在线| 视频一区视频二区视频| 懂色av一区二区三区免费观看| 久久免费视频观看| www.激情.com| 青青草华人在线视频| 久久久久久77777| 日韩在线无毛| 亚洲成人教育av| 欧美激情18p| 精品偷拍各种wc美女嘘嘘| 美女的尿口免费视频| 国产精品无码一区二区在线| 少妇高潮一区二区三区喷水| 俄罗斯精品一区二区三区| 免费在线观看成年人视频| 色婷婷在线观看视频| 亚洲精品乱码| 97视频免费在线| 激情成人开心网| 97se亚洲国产一区二区三区| 丁香啪啪综合成人亚洲小说| 亚洲精品aa| 国内视频在线精品| 国产97在线 | 亚洲| 年下总裁被打光屁股sp| 欧美激情videos| 亚洲大尺度视频在线观看| 希岛爱理一区二区三区av高清| 91www在线观看| 亚洲熟妇一区二区三区| 国产一区二区三区四区在线观看| 欧美视频一区在线| 91福利视频久久久久| 在线观看日本www| 你懂的国产视频| 男人午夜免费视频| 精品福利在线视频| 欧美性猛交久久久乱大交小说| 中文字幕在线2021| 水蜜桃久久夜色精品一区的特点| 麻豆av一区二区三区| 欧美激情精品久久久久久| 免费看精品久久片| 女人裸体性做爰全过| 国产日韩欧美制服另类| 欧美久久一二三四区| 中文字幕码精品视频网站| 国产a级免费视频| 91国产精品91| 久久久久久久网站| 91首页免费视频| 国产精品性做久久久久久| 中文字幕在线永久在线视频2020| 国产永久在线观看| 中文精品视频一区二区在线观看| 亚洲一区二区三区四区中文| 成年人视频观看| 欧美xx在线| 久久丝袜视频| 国产精品日韩在线一区| 国产精品免费网站在线观看| 成人avav影音| 亚洲男人天堂2020| а√中文在线8| 精品少妇人欧美激情在线观看| 高清免费成人av| 亚洲成色www.777999| 欧美成在线视频| 最近日本中文字幕| 国产视频一区二区三区四区| 国产成人无吗| h在线视频免费观看完整版| 精品中文字幕一区二区小辣椒| 国产在线一区二区三区播放| 午夜黄色小视频| 日本一区二区在线看| 亚洲欧美在线aaa| 香蕉视频网站在线播放| 激情黄产视频在线免费观看| 久久精品无码一区二区三区| 国产美女自拍| 91狠狠综合久久久久久| 久久99久国产精品黄毛片色诱| 另类人妖一区二区av| 成人精品国产福利| 欧美日韩国产观看视频| 免费一看一级毛片| 正义之心1992免费观看全集完整版| 亚洲女同另类| 亚洲精品日韩丝袜精品| 一区二区在线播放视频| 欧美精品99久久| 亚洲欧美日韩久久| 欧美极品欧美精品欧美图片| 中文字幕自拍偷拍| 日韩亚洲综合在线| 女人天堂亚洲aⅴ在线观看| 91中文字幕在线视频| 欧美精品一区二区三区久久久竹菊| 好操啊在线观看免费视频| 色偷偷亚洲第一综合| 136fldh精品导航福利| 国产成人在线视频网址| 国产一级黄色片免费| 国产精品初高中害羞小美女文| 国产在线综合视频| xfplay爱情电影网love| 在线观看涩涩| 久久免费看少妇高潮| 秋霞伦理一区| a视频网址在线观看| 欧美一区二区三区人| 亚洲一区二区三区sesese| 天堂а√在线最新版中文在线| 中文字幕在线观看不卡| 丰满少妇又爽又紧又丰满69| 中文字幕在线免费观看| 色资源在线观看| 国产精品视频xxxx| 中国一区二区三区| 97精品久久久| 国产成人美女视频| 天天摸天天碰天天爽天天弄| 久久另类ts人妖一区二区| 国产成人av网站| 成人免费在线视频网址| 狠狠色henhense| 农民人伦一区二区三区| 国产精品白丝jk白祙喷水网站| 黄色av免费在线| 国产亚洲一区二区手机在线观看| 久久综合给合| 日韩美女毛茸茸| 少妇av一区二区| 国产日韩精品推荐| 国产精品激情偷乱一区二区∴| 一区二区视频免费在线观看| a级大片在线观看| 国产亚洲视频在线| 久久精品一区二区三区不卡| 亚洲美女视频网站| 国产美女永久免费| 野外做受又硬又粗又大视频√| 日韩成人在线免费观看| 日韩欧美在线综合| 天天干中文字幕| 国产一区二区三区国产精品| 国产精品婷婷午夜在线观看| 性生活免费网站| 亚洲av综合色区无码一区爱av| 国产精品99一区二区三区| 欧美日韩亚洲一二三| 日韩激情小视频| 国产女片a归国片aa| 亚洲高清免费在线观看| 五月婷婷亚洲| 欧美日本黄色| 国产suv精品一区二区三区| 三级一区在线视频先锋| 99视频精品免费观看| 97精品国产综合久久久动漫日韩| 亚洲欧美日韩精品久久久久| 精品国产百合女同互慰| 在线欧美日韩精品| 色片在线免费观看| 成人精品视频| 黄色片子免费| 国产一区在线电影| 欧美a在线播放| 岳张嘴把我的精子吞下去| 国产一区在线播放| 欧美精品videos另类日本| 日韩在线免费高清视频| 麻豆精品传媒视频观看|