源码问题请教

src/Illuminate/Container/Container.php有下面这段代码,其中$container这个参数是没有的,这里为什么可以这样用?

/**
     * 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 ($container, $parameters = []) use ($abstract, $concrete) {
            if ($abstract == $concrete) {
                return $container->build($concrete);
            }

            return $container->resolve(
                $concrete, $parameters, $raiseEvents = false
            );
        };
    }
Just like to code.:smirk:
pndx
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

匿名函数的用法
具体的用法是这样的
$this->getClosure($abstract, $concrete)($container, $parameters)

1年前 评论
deatil (作者) 1年前
pndx (楼主) 1年前
deatil (作者) 1年前
pndx (楼主) 1年前
讨论数量: 21

因为这里是返回了一个函数,这个返回的函数在被调用时,可以接受$container形参的实参,就有值了

1年前 评论
pndx (楼主) 1年前
V2R (作者) 1年前
V2R (作者) 1年前
pndx (楼主) 1年前

匿名函数的用法
具体的用法是这样的
$this->getClosure($abstract, $concrete)($container, $parameters)

1年前 评论
deatil (作者) 1年前
pndx (楼主) 1年前
deatil (作者) 1年前
pndx (楼主) 1年前

匿名类

$str = 'abc';

(function($s){
    var_dump($s);
})($str); // 1. 输出 abc

$fun1 = function($s){
    var_dump($s);
};
$fun1($str); // 2. 输出 abc
// 这里把 $fun1 换成上面的 function 再加个括号,就变成第一种

function fun2()
{
  return function ($param1) {
      var_dump($param1);
  };
}
fun2()($str); // 3. 输出 abc (是不是跟 $container 有一点点相似了)

// 常规函数声明
function funX($s){
    var_dump($s);
};
funX($str); // x. 输出 abc (常规方法)

上面写了 4 中函数调用方法,其中前面 3 种是匿名函数,调用方法基本类似,实现的也是同一个功能,都是输出变量 $abc

如果你用过 JavaScript ,会感到很熟悉

1年前 评论

换个形式,语法是没问题的

$closure = function($container, $abc){ };
return $closure;

// 调用闭包
$closure($app)

bind方法的参数闭包或者类名
getClosure 在 bind 方法中被使用,bind 的参数可以看源码参数说明

Laravel

文档 简单绑定
但是也可以传入 Path\Class::Class,这种形式时就需要调用 getClosure 方法封装成闭包

bind 传入闭包意味着是动态解析,每次 make() 都返回新的实例,而 instance()是直接绑定实例对象,对比 singleton(),bind 是不共享的

bind 方法最后存储在 bingings 属性里是这个形式

$bindings = [
    'key' =>[
         'concrete' =>  Closure,
         'shared' => false //而 singleton() 时为 true
    ]
]

make(‘key’) 时,先从存储已经实例化的类的 instances 属性中没有查找到时,就从 bindings 属性中找

Laravel

Laravel

找到 key 时调用 build
Laravel

build 中解析闭包时,注入 $this 即 container 容器,这就是为什么要通过 getClosure 封装成闭包,而且第一个参数是 $container,因为闭包中可能需要容器解析依赖

Laravel

比如 make(Test::class) 时,Test 类依赖于容器解析 Test2

$this->app->bind(Test::class, function ($app) {
    return new Test($app->make(Test2::class));
});
1年前 评论
pndx (楼主) 1年前
pndx

还是没想明白。。。

/**
     * Register a binding with the container.
     *
     * @param  string  $abstract
     * @param  \Closure|string|null  $concrete
     * @param  bool  $shared
     * @return void
     *
     * @throws \TypeError
     */
    public function bind($abstract, $concrete = null, $shared = false)
    {
        $this->dropStaleInstances($abstract);

        // If no concrete type was given, we will simply set the concrete type to the
        // abstract type. After that, the concrete type to be registered as shared
        // without being forced to state their classes in both of the parameters.
        if (is_null($concrete)) {
            $concrete = $abstract;
        }

        // If the factory is not a Closure, it means it is just a class name which is
        // bound into this container to the abstract type and we will just wrap it
        // up inside its own Closure to give us more convenience when extending.
        if (! $concrete instanceof Closure) {
            if (! is_string($concrete)) {
                throw new TypeError(self::class.'::bind(): Argument #2 ($concrete) must be of type Closure|string|null');
            }

            $concrete = $this->getClosure($abstract, $concrete);
        }

        $this->bindings[$abstract] = compact('concrete', 'shared');

        // If the abstract type was already resolved in this container we'll fire the
        // rebound listener so that any objects which have already gotten resolved
        // can have their copy of the object updated via the listener callbacks.
        if ($this->resolved($abstract)) {
            $this->rebound($abstract);
        }
    }

    /**
     * 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 ($container, $parameters = []) use ($abstract, $concrete) {
            if ($abstract == $concrete) {
                return $container->build($concrete);
            }

            return $container->resolve(
                $concrete, $parameters, $raiseEvents = false
            );
        };
    }
1年前 评论
pndx

@php_yt @kis龍 @deatil @V2R 能讲细点吗?这个地方还是没看明白

1年前 评论
JinBB 1年前
kis龍 1年前
pndx (作者) (楼主) 1年前

我其实不理解什么叫 “ $container 这个参数是没有的”?

file

file

1年前 评论
pndx (楼主) 1年前

file 看堆栈式这个地方调用的,并且传入了 $container 自身

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!