当看Laravel源码的时候,看到这段代码,竟然没看出来$c
和$parameters
是怎么传过来的,
声明方法
/**
* Get the Closure to be used when building a type.
*
* @param string $abstract
* @param string $concrete
* @return \Closure
*/
protected function getClosure($abstract, $concrete)
{
return function ($c, $parameters = []) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete, $parameters);
};
}
首先看这个方法,没有定义变量$c
和$parameters
,怎么会不报错呢。直到搜索后才看到这是Closure的用法,真实长见识了。
Closure是用于代表匿名函数的类,所以它的用法和匿名函数(Anonymous functions)是一样的。 那么Closure是怎么使用的呢?
Closure通过use引用外部变量到当前环境中,不在use后面引用的参数是在Closure被调用的时候传入的。 通过以下例子来说明
<?php
class ClosureTest
{
public function getClosure($name)
{
// use将外部变量引入进来
return function($score) use ($name) {
return $name."------>".$score."\n";
};
}
}
$my_closure = new ClosureTest;
$closure = $my_closure->getClosure("Jackson"); // 变量$name在实例化一个Closure的时候传进来
echo $closure(80); // 变量$score在Closure被调用的时候传进来
这是laravel调用Closure的方法
/**
* Instantiate a concrete instance of the given type.
*
* @param string $concrete
* @param array $parameters
* @return mixed
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function build($concrete, array $parameters = [])
{
// If the concrete type is actually a Closure, we will just execute it and
// hand back the results of the functions, which allows functions to be
// used as resolvers for more fine-tuned resolution of these objects.
// Laravel调用closure的方式
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
$reflector = new ReflectionClass($concrete);
// If the type is not instantiable, the developer is attempting to resolve
// an abstract type such as an Interface of Abstract Class and there is
// no binding registered for the abstractions so we need to bail out.
if (! $reflector->isInstantiable()) {
$message = "Target [$concrete] is not instantiable.";
throw new BindingResolutionContractException($message);
}
$this->buildStack[] = $concrete;
$constructor = $reflector->getConstructor();
// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
$dependencies = $constructor->getParameters();
// Once we have all the constructor's parameters we can create each of the
// dependency instances and then use the reflection instances to make a
// new instance of this class, injecting the created dependencies in.
$parameters = $this->keyParametersByArgument(
$dependencies, $parameters
);
$instances = $this->getDependencies(
$dependencies, $parameters
);
array_pop($this->buildStack);
return $reflector->newInstanceArgs($instances);
}