美文网首页laravel核心
Laravel源码解读系列

Laravel源码解读系列

作者: 云龙789 | 来源:发表于2018-10-14 16:06 被阅读3次

    Laravel源码解读系列第一篇-初始化

    laravel 源码解析-1 index.php 文件 $app参数

    首先在 index.php 文件中 require __DIR__.'/../bootstrap/autoload.php'; 引入可所有文件,然后,我们重点说下 $app = require_once __DIR__.'/../bootstrap/app.php'; 中的 $app 的值。

    bootstrap/app.php 文件
    <?php
    
    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    
    $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
    );
    
    return $app;
    

    从以上文件,我们基本可以看出, laravel 主要其实是特别依赖singleton() 方法。这个方法就是讲一个类绑定到我们的容器中。

    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    
    
    查看 Application 的构造器函数。
    
        /**
         * Create a new Illuminate application instance.
         *
         * @param  string|null  $basePath
         * @return void
         */
        public function __construct($basePath = null)
        {
        // 传递的参数是    realpath(__DIR__.'/../') 也就是项目的根目录文件
            if ($basePath) {
                $this->setBasePath($basePath);
            }
    
            $this->registerBaseBindings();
            $this->registerBaseServiceProviders();
            $this->registerCoreContainerAliases();
        }
    

    我们直接在 bootstrap/app.php 中打印 $app 其实是看到的 Application 控制器中的所有属性,通过构造器,是给属性做了一些赋值操作,我们分别查看构造器中的操作

    this->setBasePath(basePath); 以下其实我们可以假设根目录路径是 laravel/

       public function setBasePath($basePath)
        {
        // 首先是转换文件参数,称为我们想要的形式
        //  $this->basePath = laravel/
            $this->basePath = rtrim($basePath, '\/');
    
            $this->bindPathsInContainer();
    
            return $this;
        }
        // 其次绑定所有需要的路径
          protected function bindPathsInContainer()
        {
            $this->instance('path', $this->path());
            $this->instance('path.base', $this->basePath());
            $this->instance('path.lang', $this->langPath());
            $this->instance('path.config', $this->configPath());
            $this->instance('path.public', $this->publicPath());
            $this->instance('path.storage', $this->storagePath());
            $this->instance('path.database', $this->databasePath());
            $this->instance('path.resources', $this->resourcePath());
            $this->instance('path.bootstrap', $this->bootstrapPath());
            // 加一行测试代码
                    $this->instance('name', 'xiaolong');
        }
        
    // 我们以 app/config/ 文件的获取为例
          public function configPath($path = '')
        {
            // 返回的是根目录下的 app 文件
            return $this->basePath.DIRECTORY_SEPARATOR.'config'.($path ? DIRECTORY_SEPARATOR.$path : $path);
        }
    
        /**
         * Register an existing instance as shared in the container.
         *
         * @param  string  $abstract
         * @param  mixed   $instance
         * @return void
         */
        public function instance($abstract, $instance)
        {
            $this->removeAbstractAlias($abstract);
    
            $isBound = $this->bound($abstract);
    
            unset($this->aliases[$abstract]);
    
            // We'll check to determine if this type has been bound before, and if it has
            // we will fire the rebound callbacks registered with the container and it
            // can be updated with consuming classes that have gotten resolved here.
            $this->instances[$abstract] = $instance;
    
            if ($isBound) {
                $this->rebound($abstract);
            }
        }
        通过  $this->instances[$abstract] = $instance; 我们会发现 instances() 传递的两个参数,一个是键,一个是值
    
    

    如果打印 dd(app('name')); 值就是 xiaolong 中间的过程我们需要看以下函数

    if (! function_exists('app')) {
        /**
         * Get the available container instance.
         *
         * @param  string  $abstract
         * @param  array   $parameters
         * @return mixed|\Illuminate\Foundation\Application
         */
        function app($abstract = null, array $parameters = [])
        {
            if (is_null($abstract)) {
                return Container::getInstance();
            }
    
            return empty($parameters)
                ? Container::getInstance()->make($abstract)
                : Container::getInstance()->makeWith($abstract, $parameters);
        }
    }
    
    最终运行的是 Container::getInstance()->make($abstract)
      /**
         * Resolve the given type from the container.
         *
         * @param  string  $abstract
         * @return mixed
         */
        public function make($abstract)
        {
            return $this->resolve($abstract);
        }
        
           /**
         * Resolve the given type from the container.
         *
         * @param  string  $abstract
         * @param  array  $parameters
         * @return mixed
         */
        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;
        }
    
    
    执行到的是这个
     // 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];
            }
    

    我们再来说说 Application 文件中构造函数中 $this->registerBaseServiceProviders();

       /**
         * Register all of the base service providers.
         *
         * @return void
         */
        protected function registerBaseServiceProviders()
        {
            $this->register(new EventServiceProvider($this));
    //
            $this->register(new LogServiceProvider($this));
    
            $this->register(new RoutingServiceProvider($this));
        }
        
        new EventServiceProvider($this);
        
    class EventServiceProvider extends ServiceProvider
    {
        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {
            $this->app->singleton('events', function ($app) {
                return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
                    return $app->make(QueueFactoryContract::class);
                });
            });
        }
    }
    
     $this->app->singleton() 
     来自于 ServiceProvider 中的构造函数
       public function __construct($app)
        {
            $this->app = $app;
        }
        其实还是容器自己
        解析
         $this->app->singleton() 
         Application 继承了Container 
         singleton() 在 Illuminate\Container\Container 中
         
          /**
         * Register a shared binding in the container.
         *
         * @param  string|array  $abstract
         * @param  \Closure|string|null  $concrete
         * @return void
         */
        public function singleton($abstract, $concrete = null)
        {
            $this->bind($abstract, $concrete, true);
        }
        所以上面的三个 singleton() 每一个都是绑定了参数类中的 singleton() 那个参数
        
        
         /**
         * Register a binding with the container.
         *
         * @param  string|array  $abstract
         * @param  \Closure|string|null  $concrete
         * @param  bool  $shared
         * @return void
         */
        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);
            }
        }
        执行了
         $this->bindings[$abstract] = compact('concrete', 'shared');
         
         
         
        /**
         * Register a service provider with the application.
         *
         * @param  \Illuminate\Support\ServiceProvider|string  $provider
         * @param  array  $options
         * @param  bool   $force
         * @return \Illuminate\Support\ServiceProvider
         */
        public function register($provider, $options = [], $force = false)
        {
            if (($registered = $this->getProvider($provider)) && ! $force) {
                return $registered;
            }
    
            // If the given "provider" is a string, we will resolve it, passing in the
            // application instance automatically for the developer. This is simply
            // a more convenient way of specifying your service provider classes.
            if (is_string($provider)) {
                $provider = $this->resolveProvider($provider);
            }
    
            if (method_exists($provider, 'register')) {
                $provider->register();
            }
    
            $this->markAsRegistered($provider);
    
            // If the application has already booted, we will call this boot method on
            // the provider class so it has an opportunity to do its boot logic and
            // will be ready for any usage by this developer's application logic.
            if ($this->booted) {
                $this->bootProvider($provider);
            }
    
            return $provider;
        }
        
    

    相关文章

      网友评论

        本文标题:Laravel源码解读系列

        本文链接:https://www.haomeiwen.com/subject/iwzzaftx.html