由于本人在學(xué)習(xí)laravel框架,在框架里面發(fā)現(xiàn)了很多的匿名函數(shù),由于本來(lái)對(duì)這個(gè)沒(méi)有了解,所以理解不了對(duì)應(yīng)的框架邏輯。
然后,上網(wǎng)找了一些資料,最好的是這個(gè)個(gè)人覺(jué)得很好的 PHP Anonymous Functions 。大家可以過(guò)去看下,然后針對(duì)laravel的例子說(shuō)一個(gè):
步驟1. 在bootstrap/app.php目錄下會(huì)有服務(wù)容器的綁定:
$app->singleton( ? ? Illuminate\Contracts\Http\Kernel::class, ? ? App\Http\Kernel::class );
$app->singleton( ? ? Illuminate\Contracts\Console\Kernel::class, ? ? App\Console\Kernel::class );
$app->singleton( ? ? Illuminate\Contracts\Debug\ExceptionHandler::class, ? ? App\Exceptions\Handler::class );?
步驟2. 這里的singleton調(diào)用的是vendor/laravel/framework/src/Illuminate/Container/Container.php下的方法:
? ? public function singleton($abstract, $concrete = null)
? ? {
? ? ? ? $this->bind($abstract, $concrete, true);
? ? }
? ? public function bind($abstract, $concrete = null, $shared = false)
? ? {
? ? ? ? // 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.
? ? ? ? $this->dropStaleInstances($abstract);
? ? ? ? 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) {
? ? ? ? ? $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);
? ? ? ? }
? ? }
步驟3. 上方的黑體斜體對(duì)應(yīng)的就是下方的匿名方法:
? ? protected function getClosure($abstract, $concrete)
? ? {
? ? ? ? return function ($container, $parameters = []) use ($abstract, $concrete) {
? ? ? ? ? ? if ($abstract == $concrete) {
? ? ? ? ? ? ? ? return $container->build($concrete);
? ? ? ? ? ? }
? ? ? ? ? ? return $container->make($concrete, $parameters);
? ? ? ? };
? ? }
步驟4. 這里會(huì)返回一個(gè)作為閉包的匿名函數(shù)用于處理服務(wù)容器的初始化,可是他這里的初始化還沒(méi)有執(zhí)行,這里只是綁定了這個(gè)服務(wù)容器方便后續(xù)調(diào)用。
步驟5. 最后會(huì)在public/index.php的初始化時(shí)調(diào)用:
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
步驟6. 上方調(diào)用的對(duì)應(yīng)的是vendor/laravel/framework/src/Illuminate/Foundation/Application.php的make方法:
? ? public function make($abstract, array $parameters = [])
? ? {
? ? ? ? $abstract = $this->getAlias($abstract);
? ? ? ? if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
? ? ? ? ? ? $this->loadDeferredProvider($abstract);
? ? ? ? }
? ? ? ? return parent::make($abstract, $parameters);
? ? }
步驟7. 這里會(huì)調(diào)用父類:vendor/laravel/framework/src/Illuminate/Container/Container.php的make方法
? ? public function make($abstract, array $parameters = [])
? ? {
? ? ? ? return $this->resolve($abstract, $parameters);
? ? }
? ? protected function resolve($abstract, $parameters = [])
? ? {
? ? ? ? $abstract = $this->getAlias($abstract);
? ? ? ? $needsContextualBuild = ! empty($parameters) || ! is_null(
? ? ? ? ? ? $this->getContextualConcrete($abstract)
? ? ? ? );
? ? ? ? // If an instance of the type is currently being managed as a singleton we'll
? ? ? ? // just return an existing instance instead of instantiating new instances
? ? ? ? // so the developer can keep using the same objects instance every time.
? ? ? ? if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
? ? ? ? ? ? return $this->instances[$abstract];
? ? ? ? }
? ? ? ? $this->with[] = $parameters;
? ? ? ? $concrete = $this->getConcrete($abstract);
? ? ? ? // We're ready to instantiate an instance of the concrete type registered for
? ? ? ? // the binding. This will instantiate the types, as well as resolve any of
? ? ? ? // its "nested" dependencies recursively until all have gotten resolved.
? ? ? ? if ($this->isBuildable($concrete, $abstract)) {
? ? ? ? ? ? $object = $this->build($concrete);
? ? ? ? } else {
? ? ? ? ? ? $object = $this->make($concrete);
? ? ? ? }
? ? ? ? // If we defined any extenders for this type, we'll need to spin through them
? ? ? ? // and apply them to the object being built. This allows for the extension
? ? ? ? // of services, such as changing configuration or decorating the object.
? ? ? ? foreach ($this->getExtenders($abstract) as $extender) {
? ? ? ? ? ? $object = $extender($object, $this);
? ? ? ? }
? ? ? ? // If the requested type is registered as a singleton we'll want to cache off
? ? ? ? // the instances in "memory" so we can return it later without creating an
? ? ? ? // entirely new instance of an object on each subsequent request for it.
? ? ? ? if ($this->isShared($abstract) && ! $needsContextualBuild) {
? ? ? ? ? ? $this->instances[$abstract] = $object;
? ? ? ? }
? ? ? ? $this->fireResolvingCallbacks($abstract, $object);
? ? ? ? // Before returning, we will also set the resolved flag to "true" and pop off
? ? ? ? // the parameter overrides for this build. After those two things are done
? ? ? ? // we will be ready to return back the fully constructed class instance.
? ? ? ? $this->resolved[$abstract] = true;
? ? ? ? array_pop($this->with);
? ? ? ? return $object;
? ? }
步驟8. 因?yàn)榈谝淮问浅跏蓟?,所以調(diào)用了container的build方法:
? ? public function build($concrete)
? ? {
? ? ? ? // 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.
? ? ? ? if ($concrete instanceof Closure) {
? ? ? ? ? ? return $concrete($this, $this->getLastParameterOverride());
? ? ? ? }
? ? ? ? $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()) {
? ? ? ? ? ? return $this->notInstantiable($concrete);
? ? ? ? }
? ? ? ? $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.
? ? ? ? $instances = $this->resolveDependencies(
? ? ? ? ? ? $dependencies
? ? ? ? );
? ? ? ? array_pop($this->buildStack);
? ? ? ? return $reflector->newInstanceArgs($instances);
? ? }
步驟9. 上方的 $concrete 為步驟3處返回的那個(gè)匿名函數(shù),這里的$concrete($this, $this->getLastParameterOverride());相當(dāng)于調(diào)用了步驟3的方法: function($container, $parameters = []) use ($abstract, $concrete)?
調(diào)用方法的參數(shù)一一對(duì)應(yīng):
$this ----------- $containser
$this->getLastParameterOverride() --------------------- $parameters
$abstract, $concrete這兩個(gè)的話對(duì)應(yīng)回原來(lái)調(diào)用時(shí)的數(shù)據(jù)