前言 單純為了學習
Illuminate\Container\BoundMethod分析
1. 引入
use Closure;//匿名函式
use ReflectionMethod;//反射類
use ReflectionFunction;//報告一個函式的有關資訊
use InvalidArgumentException;//引數異常類
2. 呼叫給定的方法並注入其依賴項
1、isCallableWithAtSign
2、callClass
3、callBoundMethod
4、getMethodDependencies
public static function call($container, $callback, array $parameters = [], $defaultMethod = null)
{
//判斷$callback是否在Class@method語法中 或者 有預設的方法名
if (static::isCallableWithAtSign($callback) || $defaultMethod) {
return static::callClass($container, $callback, $parameters, $defaultMethod);
}
//執行方法
return static::callBoundMethod($container, $callback, function () use ($container, $callback, $parameters) {
return call_user_func_array(
$callback, static::getMethodDependencies($container, $callback, $parameters)//
);
});
}
3. 使用Class@method語法呼叫對類的字串引用
protected static function callClass($container, $target, array $parameters = [], $defaultMethod = null)
{
$segments = explode('@', $target);//按@字元分割callback
$method = count($segments) === 2? $segments[1] : $defaultMethod;//獲取方法名
if (is_null($method)) {
throw new InvalidArgumentException('Method not provided.');//為空的話丟擲異常
}
//直接傳回依賴項繫結的“call”方法。
return static::call(
$container, [$container->make($segments[0]), $method], $parameters
);
}
4. 呼叫繫結到容器的方法
protected static function callBoundMethod($container, $callback, $default)
{
//判斷如果callback不是陣列
if (! is_array($callback)) {
return $default instanceof Closure ? $default() : $default;//如果default是匿名函式就調取否則返回
}
//序列化方法名 class@method
$method = static::normalizeMethod($callback);
//檢測容器是否有給定的方法繫結
if ($container->hasMethodBinding($method)) {
return $container->callMethodBinding($method, $callback[0]);//立即執行容器繫結方法
}
return $default instanceof Closure ? $default() : $default;//如果default是匿名函式就調取否則返回
}
5. 序列化方法名
protected static function normalizeMethod($callback)
{
$class = is_string($callback[0]) ? $callback[0] : get_class($callback[0]);
return "{$class}@{$callback[1]}";
}
6. 獲取給定發放的所有依賴項
1、getCallReflector
2、addDependencyForCallParameter
protected static function getMethodDependencies($container, $callback, array $parameters = [])
{
$dependencies = [];
//獲取反射例項->獲取引數
foreach (static::getCallReflector($callback)->getParameters() as $parameter) {
static::addDependencyForCallParameter($container, $parameter, $parameters, $dependencies);//獲取依賴項
}
return array_merge($dependencies, $parameters);
}
7. 獲取給定回撥的反射例項
protected static function getCallReflector($callback)
{
if (is_string($callback) && strpos($callback, '::') !== false) {
$callback = explode('::', $callback);
}
return is_array($callback)
? new ReflectionMethod($callback[0], $callback[1])
: new ReflectionFunction($callback);
}
8. 獲取給定呼叫引數的依賴項
protected static function addDependencyForCallParameter($container, $parameter, array &$parameters, &$dependencies)
{
//判斷引數名是否已存在傳入的引數陣列
if (array_key_exists($parameter->name, $parameters)) {
$dependencies[] = $parameters[$parameter->name];//加入依賴項陣列
unset($parameters[$parameter->name]);//釋放引數陣列
}
elseif ($parameter->getClass() && array_key_exists($parameter->getClass()->name, $parameters)) {
$dependencies[] = $parameters[$parameter->getClass()->name];
unset($parameters[$parameter->getClass()->name]);
} elseif ($parameter->getClass()) {
$dependencies[] = $container->make($parameter->getClass()->name);
} elseif ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
}
}
9. 確定給定的字串是否在Class@method語法中
protected static function isCallableWithAtSign($callback)
{
return is_string($callback) && strpos($callback, '@') !== false;
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結