精华内容
下载资源
问答
  • 在《简单理解Laravel的核心概念----服务容器、服务提供者、契约》中,对于Facades,我们说它是一组静态接口或者代理,作用是方便开发者简单使用绑定到容器中各种服务,还是那个例子: 我们经常用Route就是一...

    在《简单理解Laravel的核心概念----服务容器、服务提供者、契约》中,对于Facades,我们说它是一组静态接口或者代理,作用是方便开发者简单的使用绑定到容器中的各种服务,还是那个例子:

    我们经常用的Route就是一个Facade, 它是\Illuminate\Support\Facades\Route类的别名,这个Facade类代理的是注册到服务容器里的router服务,所以通过Route类我们就能够方便地使用router服务中提供的各种服务,而其中涉及到的服务解析完全是隐式地由Laravel完成的,这在一定程度上让应用程序代码变的简洁了不少.

    那么Facades从被注册进laravel到被应用程序使用,这一过程是怎样一个流程呢?Facades又是如何隐式的实现服务解析呢?

    注册Facades

    如果深入了解过laravel的请求周期,那么一定知道Facades的注册阶段是在请求周期的Bootstrap阶段了,在请求通过中间件和路由之前,一定有一个启动应用程序的过程:具体的代码:

    //  class:\Illuminate\Foundation\Http\Kernel
    
        /**
         * Send the given request through the middleware / router.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return \Illuminate\Http\Response
         */
        protected function sendRequestThroughRouter($request)
        {
            $this->app->instance('request', $request);
    
            Facade::clearResolvedInstance('request');
    
            $this->bootstrap();
    
            return (new Pipeline($this->app))
                        ->send($request)
                        ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                        ->then($this->dispatchToRouter());
        }
    
        /**
         * The bootstrap classes for the application.
         *
         * @var array
         */
        protected $bootstrappers = [
            \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
            \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
            \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
            \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
            \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
            \Illuminate\Foundation\Bootstrap\BootProviders::class,
        ];
    

    在应用启动过程中的\Illuminate\Foundation\Bootstrap\RegisterFacades::class阶段会注册应用程序里用到的所有Facades,我们可以打开这个RegisterFacades类查看一下:

    namespace Illuminate\Foundation\Bootstrap;
    
    use Illuminate\Foundation\AliasLoader;
    use Illuminate\Support\Facades\Facade;
    use Illuminate\Foundation\PackageManifest;
    use Illuminate\Contracts\Foundation\Application;
    
    class RegisterFacades
    {
        /**
         * Bootstrap the given application.
         *
         * @param  \Illuminate\Contracts\Foundation\Application  $app
         * @return void
         */
        public function bootstrap(Application $app)
        {
            Facade::clearResolvedInstances();
    
            Facade::setFacadeApplication($app);
    
            AliasLoader::getInstance(array_merge(
                $app->make('config')->get('app.aliases', []),
                $app->make(PackageManifest::class)->aliases()
            ))->register();
        }
    }
    

    里面只有一个bootstrap方法,这个方法的作用是通过AliasLoader类为所有的Facades注册别名,而Facades和别名的对应关系存放在config/app.php文件的$aliases数组中。

        'aliases' => [
    
            'App' => Illuminate\Support\Facades\App::class,
            'Arr' => Illuminate\Support\Arr::class,
            'Artisan' => Illuminate\Support\Facades\Artisan::class,
            'Route' => Illuminate\Support\Facades\Route::class,
    		...
    		...
        ],
    

    我们再来看一下AliasLoader类是如何注册别名的。

    
    //  class: Illuminate\Foundation\AliasLoader
    
        /**
         * Get or create the singleton alias loader instance.
         *
         * @param  array  $aliases
         * @return \Illuminate\Foundation\AliasLoader
         */
        public static function getInstance(array $aliases = [])
        {
            if (is_null(static::$instance)) {
                return static::$instance = new static($aliases);
            }
    
            $aliases = array_merge(static::$instance->getAliases(), $aliases);
    
            static::$instance->setAliases($aliases);
    
            return static::$instance;
        }
    
        /**
         * Register the loader on the auto-loader stack.
         *
         * @return void
         */
        public function register()
        {
            if (! $this->registered) {
                $this->prependToLoaderStack();
    
                $this->registered = true;
            }
        }
    
        /**
         * Prepend the load method to the auto-loader stack.
         *
         * @return void
         */
        protected function prependToLoaderStack()
        {
            spl_autoload_register([$this, 'load'], true, true);
        }
    

    简单解释一下上面的代码:通过getInstance方法设置应用中几乎所有的门面,并通过$aliases进行缓存。设置成功后调用register方法对其进行别名绑定,而在register方法中的$registered状态记录的是是否已经完成了别名的绑定。如果没有进行别名的绑定,那么会调用prependToLoaderStack方法,将load方法注册到了SPL __autoload函数队列的头部
    我们再来看看load方法:

    //  class: Illuminate\Foundation\AliasLoader
    
        /**
         * Load a class alias if it is registered.
         *
         * @param  string  $alias
         * @return bool|null
         */
        public function load($alias)
        {
            if (static::$facadeNamespace && strpos($alias, static::$facadeNamespace) === 0) {
                $this->loadFacade($alias);
    
                return true;
            }
    
            if (isset($this->aliases[$alias])) {
                return class_alias($this->aliases[$alias], $alias);
            }
        }
    

    在load方法里$aliases配置里的Facade类创建了对应的别名,比如当我们使用别名类Route时,PHP会通过AliasLoader的load方法为把Illuminate\Support\Facades\Route::class类创建一个别名类Route,所以我们在程序里使用别Route其实使用的就是Illuminate\Support\Facades\Route类。其中的class_alias方法就是PHP对类创建别名的方法。

    到此就完成了注册Facades的阶段

    解析Facades代理的服务

    将Facades注册到Laravel中就可以在应用程序中使用Facades了,还是以Route进行设问,如果现在存在一个路由:

    Route::get('/index', 'Controller@index);
    

    那么如何将Route解析到路由服务的呢?这就扯出来了Facades对服务的隐式解析了
    我们可以看一看Route的源码:

    
    namespace Illuminate\Support\Facades;
    
    /**
     *
     * @see \Illuminate\Routing\Router
     */
    class Route extends Facade
    {
        /**
         * Get the registered name of the component.
         *
         * @return string
         */
        protected static function getFacadeAccessor()
        {
            return 'router';
        }
    }
    

    奇怪的是,在Route类中并没有定义哪些get、post、put、any等方法,在父类Facade中也没有这些方法,但是我们知道调用类不存在的静态方法时会触发PHP的__callStatic静态方法。

    
    //   class Illuminate\Support\Facades\Facade
    
        /**
         * Handle dynamic, static calls to the object.
         *
         * @param  string  $method
         * @param  array   $args
         * @return mixed
         *
         * @throws \RuntimeException
         */
        public static function __callStatic($method, $args)
        {
            $instance = static::getFacadeRoot();
    
            if (! $instance) {
                throw new RuntimeException('A facade root has not been set.');
            }
    
            return $instance->$method(...$args);
        }
    
        /**
         * Get the root object behind the facade.
         *
         * @return mixed
         */
        public static function getFacadeRoot()
        {
            return static::resolveFacadeInstance(static::getFacadeAccessor());
        }
    
        /**
         * Get the registered name of the component.
         *
         * @return string
         *
         * @throws \RuntimeException
         */
        protected static function getFacadeAccessor()
        {
            throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
        }
    
        /**
         * Resolve the facade root instance from the container.
         *
         * @param  object|string  $name
         * @return mixed
         */
        protected static function resolveFacadeInstance($name)
        {
            if (is_object($name)) {
                return $name;
            }
    
            if (isset(static::$resolvedInstance[$name])) {
                return static::$resolvedInstance[$name];
            }
    
            return static::$resolvedInstance[$name] = static::$app[$name];
        }
    

    通过在子类Route Facade里设置的accessor(字符串’router’), 从服务容器中解析出对应的服务,router服务是在应用程序初始化时的registerBaseServiceProviders阶段(具体可以看Application的构造方法)被\Illuminate\Routing\RoutingServiceProvider注册到服务容器里的:

    class RoutingServiceProvider extends ServiceProvider
    {
        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {
            $this->registerRouter();
            ......
        }
    
        /**
         * Register the router instance.
         *
         * @return void
         */
        protected function registerRouter()
        {
            $this->app->singleton('router', function ($app) {
                return new Router($app['events'], $app);
            });
        }
        ......
    }
    
    

    router服务对应的类就是\Illuminate\Routing\Router, 所以Route Facade实际上代理的就是这个类,Route::get实际上调用的是\Illuminate\Routing\Router对象的get方法

    /**
     * Register a new GET route with the router.
     *
     * @param  string  $uri
     * @param  \Closure|array|string|null  $action
     * @return \Illuminate\Routing\Route
     */
    public function get($uri, $action = null)
    {
        return $this->addRoute(['GET', 'HEAD'], $uri, $action);
    }
    

    参考:
    https://laravelacademy.org/post/19439.html
    https://segmentfault.com/a/1190000013969013

    展开全文
  • 在写之前,我要吐槽一番,laravel的官方文档写的是真恶心,上文不接下文,看的人头皮发麻。 先来说说laravel中的几个核心概念 ...简单的说服务容器就是管理类的依赖和执行依赖注入的工具,这是官方文档上说的。 但是...

    在写之前,我要吐槽一番,laravel的官方文档写的是真恶心,上文不接下文,看的人头皮发麻。
    先来说说laravel中的几个核心概念

    服务容器

    Laravel 服务容器是一个用于管理类依赖和执行依赖注入的强大工具。依赖注入听上去很花哨,其实质是通过构造函数或者某些情况下通过「setter」方法将类依赖注入到类中。

    简单的说服务容器就是管理类的依赖和执行依赖注入的工具,这是官方文档上说的。
    但是我的理解更偏向于:

    一段生命周期所抽象的一个对象

    很难理解,打个比方,在一次请求中,你可能会用到很多服务,比如路由,队列,中间件,自定义服务等等。那么如何这么多的服务,如果不能妥善管理,势必会造成各种混乱,这是你不希望看到的,于是你想出了一个办法,用一个篮子,来乘放这些服务,然后使用的时候从篮子中拿就行了。

    说到服务容器,就需要说服务容器的两个重要概念IOC(控制反转)DI(依赖注入)
    这两个概念并不是laravel中特有的。目的是为了降低软件开发的复杂度;提升模块低耦合、高内聚的一种设计模式

    • 控制反转:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源;
    • 依赖注入:应用程序依赖容器创建并注入它所需要的外部资源。

    好的,我们知道了控制反转的作用就是实现模块或对象的解耦,通过借助第三方将具有依赖的模块或对象进行解耦,而这个第三方,就是IOC容器
    在这里插入图片描述
    引入了IoC容器后,对象A、B、C、D之间没有了依赖关系,全体齿轮转动的控制权交给IoC容器。这时候齿轮转动控制权不属于任何对象,而属于IoC容器,所以控制权反转了,从某个对象转到了IoC容器。
    在这里插入图片描述
    而对于依赖注入,其实首先要明白依赖就是一种关系。如果在类A中创建了类B的实例,就可以说A依赖于B。那么直接在需要依赖的类中声明被依赖的类的实例的方法,会出现下面问题:

    • 如果需要修改类B的创建方式,那么需要修改类A中对B的声明代码
    • 如果想测试不同B对象对A的影响很困难,因为B的初始化被写死在了A的构造函数中
    • 如果要对类B的实例进行调试时,就必须在类A中对类B的实例进行测试,增加了测试难度和复杂度

    如果将类B实例作为类A构造器参数进行传入,在调用A的构造器前,B实例已经初始化好了,像这种不是自己主动初始化依赖,而是通过外部传入依赖对象的方式,就是依赖注入

    解释完IOC和DI的概念,我们在回想一下刚刚将服务放在篮子中的例子,那么现在就有两个问题了:

    • 如何将服务放在篮子里?
    • 需要某个服务的时候,如果从篮子中拿出来?

    这就是laravel中服务容器的两个基本作用:

    • 服务绑定
    • 服务解析

    对于具体的绑定/解析方法,官方文档上已经说的很详细了,这里就不举例了,还是对于概念的理解。

    服务绑定

    一个类要被容器提取,首先要先注册到这个容器。laravel叫这个容器为服务容器,那么我们需要某个服务,就得先注册、绑定这个服务到容器中,那么提供服务并绑定服务到容器的东西,就是服务提供者了。

    注:如果一个类没有基于任何接口那么就没有必要将其绑定到容器。容器并不需要被告知如何构建对象,因为它会使用PHP的反射服务自动解析出具体的对象。

    服务解析

    注册、绑定服务后,就可以根据需要从IOC容器中提取出对应的服务了。就是一个“拿出来”的过程。同样的,具体方法可以自行查看官方文档。

    服务提供者

    由服务绑定,我们引出了laravel的另外一个核心概念----服务提供者。我们知道,服务容器是“乘放”服务的地方,而服务提供者就是我们将服务放到服务容器的地方。简单说服务提供者就是把服务注册、绑定到容器上的地方。根据官方文档,就是:

    服务提供者是Laravel应用启动的中心,你自己的应用以及所有Laravel的核心服务都是通过服务提供者启动。当然启动这些服务,需要加载注册服务,包括注册服务容器绑定、事件监听器、中间件甚至路由。服务提供者是应用配置的中心。

    所有的服务提供者都有一个共同的父类Illuminate\Support\ServiceProvider类,这是一个抽象类,要求所有的服务提供者至少需要实现一个register方法,在这个方法中应该只绑定内容到服务容器。

    注:永远不要在register方法中尝试在其中注册任何的事件监听,路由或者其它功能。因为我们可能使用了还未注册的服务,从而导致异常。

    如何理解这句话的含义呢?

    如果有了解过服务容器,就会知道在「绑定」操作仅仅是建立起接口和实现的对应关系,此时并不会创建具体的实例,即不会存在真实的依赖关系。直到某个服务真的被用到时才会从「服务容器」中解析出来,而解析的过程发生在所有服务「注册」完成之后。
    一旦我们尝试在 register 注册阶段使用某些未被加载的服务依赖,即这个服务目前还没有被注册所以不可用。
    我们可以随意打开一个服务提供者看看:

    namespace Illuminate\Cache;
    
    use Illuminate\Support\ServiceProvider;
    use Illuminate\Contracts\Support\DeferrableProvider;
    
    class CacheServiceProvider extends ServiceProvider implements DeferrableProvider
    {
        /**
         * Register the service provider.
         *
         * @return void
         */
        public function register()
        {
            $this->app->singleton('cache', function ($app) {
                return new CacheManager($app);
            });
    
            $this->app->singleton('cache.store', function ($app) {
                return $app['cache']->driver();
            });
    
            $this->app->singleton('memcached.connector', function () {
                return new MemcachedConnector;
            });
        }
    
        /**
         * Get the services provided by the provider.
         *
         * @return array
         */
        public function provides()
        {
            return [
                'cache', 'cache.store', 'memcached.connector',
            ];
        }
    }
    

    可以看到,在register中只是完成了三个简单的注册。

    OK,通过register,我们将服务可以注册绑定到服务容器中,那么当所有的服务都被注册之后,我们需要使用某些服务时,应该在哪里使用呢?服务提供者模版提供了一个boot方法。

    boot方法在所有服务提供者被注册以后才会被调用,这就是说我们可以在其中访问框架已注册的所有其它服务。

    boot方法在register方法之后调用,这就意味着我们无需在注入某个实例的时候, 它还没有绑定或者实例化。
    boot中一般完成启动相应的服务的工作,比如需要处理依赖关系的业务逻辑时,就可以将这些业务逻辑放在boot当中,或者是注册事件监听器,引入路由等你能想到的业务逻辑。
    声明完成服务提供者后,添加到config/app.php中的providers数组中进行注册,而在providers数组中默认的注册了laravel中所有的核心服务,这些提供者启动了laravel的核心组件,如邮件,队列,缓存等。

    Facades

    Facades,我们可以叫做门面,其实就是一组静态接口或者代理,能让开发者简单的访问绑定到容器中的各种服务。

    Facades 为应用程序的 服务容器 中可用的类提供了一个「静态」接口。Laravel 本身附带许多的 facades,甚至你可能在不知情的状况下已经在使用他们!Laravel 「facades」作为在服务容器内基类的「静态代理」,拥有简洁、易表达的语法优点,同时维持着比传统静态方法更高的可测试性和灵活性。

    举个例子,我们熟知的Route,其实就是一个Facades,它其实就是Illuminate\Support\Facades\Route类的别名,这个facades类代理的是注册到服务容器中的router服务,所以通过Route类就可以很方便的使用router服务中的各种服务,而其中的服务解析完全是进行自动的隐式解析的。至于怎么解析,我们之后会看一看源码,了解一下其流程。

    'Route' => Illuminate\Support\Facades\Route::class,
    

    由此,我们可以理解Facade和服务提供者是紧密配合的,所以如果以后自己写Laravel自定义服务时除了通过组件的Service Provider将服务注册进服务容器,还可以在组件中提供一个Facade让应用程序能够方便的访问你写的自定义服务。

    展开全文
  • Laravel 核心概念包括:服务容器、服务提供者、门面(Facades)、契约(Contracts)。 服务容器是 Laravel 核心,是一个 IoC 容器,是管理依赖和运行依赖注入有力工具。 服务提供者则提供服务并绑定服务至...

    Laravel核心概念

    Laravel 的核心概念包括:服务容器、服务提供者、门面(Facades)、契约(Contracts)。

    服务容器是 Laravel 的核心,是一个 IoC 容器,是管理类依赖和运行依赖注入的有力工具。

    服务提供者则提供服务并绑定服务至服务容器。是所有 Laravel 应用程序引导启动的中心所在。

    Facades 为应用程序的服务容器中可用的类提供了一个「静态」接口。它实际上是服务容器中那些底层类的「静态代理」。

    Laravel 的 契约(Contracts )是一系列框架用来定义核心服务的接口。

    不管是契约还是门面都可以创建出强大的、容易测试的 Laravel 应用程序。

    0x00 服务容器

    Laravel 的核心就是一个 IoC 容器,该容器提供了整个框架中需要的一系列服务。

    IoC(Inversion Of Control)控制反转,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。IoC 容器会根据类的依赖需求,自动在注册、绑定的一堆实例中搜寻符合的依赖需求,并自动注入到构造函数参数中去。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。这就是依赖注入(Dependency Injection, DI)。依赖注入实质上是指:类的依赖通过构造器或在某些情况下通过「setter」方法进行「注入」。

    Laravel服务容器

    如何实现与服务容器的绑定?

    几乎所有服务容器的绑定都是在服务提供者中进行的。在服务提供者内部,可以通过 $this->app 来访问容器的实例。

    绑定的方式包括:

    • 简单绑定
    • 绑定一个单例
    • 绑定实例
    • 绑定接口到实现
    • 情境绑定
    • 绑定包括原始数据在内的初始数据
    • 标记

    其中,标记能够针对某种类别的所有做绑定。

    如何从服务容器解析出对象?

    绑定后可以从服务容器中解析出对象才能够使用。解析方法包括:

    • 通过 make 方法,接收一个你想要解析的类或者接口
    • 通过数组方式从容器中解析对象
    • 自动注入

    自动注入实例

    下面的例子中,在控制器的构造函数中对应用程序定义的 Repository 使用类型提示。这样 Repository 实例会被自动解析并注入到类中:

    <?php
    
    namespace App\Http\Controllers;
    
    use App\Users\Repository as UserRepository;
    
    class UserController extends Controller
    {
        /**
         * user repository 实例。
         */
        protected $users;
    
        /**
         * 控制器构造方法。
         *
         * @param  UserRepository  $users
         * @return void
         */
        public function __construct(UserRepository $users)
        {
            $this->users = $users;
        }
    
        /**
         * 显示指定 ID 的用户信息。
         *
         * @param  int  $id
         * @return Response
         */
        public function show($id)
        {
            //
        }
    }
    

    0x01 服务提供者

    Laravel 中,包括应用程序,以及所有的 Laravel 核心服务,都是通过服务提供者引导启动的。所谓的「引导启动」指的是注册事务,包括注册服务容器绑定,事件监听器,中间件,甚至路由。

    Laravel服务提供者

    所有服务提供者都需要继承 Illuminate\Support\ServiceProvider 类。大多数服务提供者都包含 register 和 boot 方法。register 方法中,只能将事务绑定到 服务容器。不应该在 register 方法中尝试注册任何事件监听器,路由或者任何其他功能。可以为服务提供者的 boot 方法设置类型提示。服务容器会自动注入需要的任何依赖。boot 方法将在所有其他服务提供者均已注册之后调用。

    所有服务提供者都在 config/app.php 配置文件中注册。可以选择推迟服务提供者的注册,直到真正需要注册绑定时,这样可以提供应用程序的性能。

    0x02 门面(Facades)

    Laravel Facade

    Facades 工作原理

    在 Laravel 应用中,一个 facade 就是一个提供访问容器中对象的类。其中核心的部件就是 Facade 类。不管是 Laravel 自带的 Facades ,还是用户自定义的 Facades ,都继承自 Illuminate\Support\Facades\Facade 类。

    Facade 基类使用 __callStatic() 魔术方法在你的 Facades 中延迟调用容器中对应对象的方法,在下面的例子中,调用了 Laravel 的缓存系统。在代码里,我们可能认为是 Cache 类中的静态方法 get 被调用了:

    <?php
    namespace App\Http\Controllers;
    
    use Illuminate\Support\Facades\Cache;
    use App\Http\Controllers\Controller;
    
    class UserController extends Controller
    {
        /**
         * 显示给定用户的大体信息。
         *
         * @param  int  $id
         * @return Response
         */
        public function showProfile($id)
        {
            $user = Cache::get('user:'.$id);
    
            return view('profile', ['user' => $user]);
        }
    }
    

    注意在代码的最上面,我们导入的是 Cache facade 。这个 facade 其实是我们获取底层 Illuminate\Contracts\Cache\Factory 接口实现的一个代理。我们通过这个 facade 调用的任何方法,都会被传递到 Laravel 缓存服务的底层实例中。

    如果我们看一下 Illuminate\Support\Facades\Cache 这个类,你会发现类中根本没有 get 这个静态方法:

    class Cache extends Facade
    {
        /**
         * 获取组件在容器中注册的名称。
         *
         * @return string
         */
        protected static function getFacadeAccessor() { return 'cache'; }
    }
    

    其实,Cache facade 是继承了 Facade 基类,并且定义了 getFacadeAccessor() 方法。这个方法的作用是返回服务容器中对应名字的绑定内容。当用户调用 Cache facade 中的任何静态方法时, Laravel 会解析到服务容器中绑定的键值为 cache 实例对象,并调用这个对象对应的方法(在这个例子中就是 get 方法)。

    0x03 契约(Contracts)

    Laravel Contract

    如何使用契约?

    Laravel 中的许多类型的类都是通过 服务容器 解析出来的。包括控制器、事件监听器、中间件、任务队列,甚至路由的闭包。所以说,要获得一个契约的实现,你只需要解析在类的构造函数中相应的类型约束即可。

    例如,看看这个事件监听器,当事件监听器被解析时,服务容器会从构造函数里读取到类型约束,并注入对应的值。

    <?php
    
    namespace App\Listeners;
    
    use App\User;
    use App\Events\OrderWasPlaced;
    use Illuminate\Contracts\Redis\Database;
    
    class CacheOrderInformation
    {
        /**
         * Redis 数据库实现。
         */
        protected $redis;
    
        /**
         * 创建事件处理器实例。
         *
         * @param  Database  $redis
         * @return void
         */
        public function __construct(Database $redis)
        {
            $this->redis = $redis;
        }
    
        /**
         * 处理事件。
         *
         * @param  OrderWasPlaced  $event
         * @return void
         */
        public function handle(OrderWasPlaced $event)
        {
            //
        }
    }
    

    下一步

    Laravel 作为“为 Web 艺术家创造的 PHP 框架”,接下来我将学习其中最重要的内容之一 HTTP 层的相关知识。同样会整理成思维导图的形式以方便记忆与回顾。

    这些文章都将首发在微信公众号:up2048 上。欢迎大家扫描下面的二维码,我们一起学习,分享,讨论,反思。

    思维导图导出为图片时会导致其变模糊。若需要高清的思维导图源文件,请关注微信公众号:up2048,并回复“精进脑图”来获取。

    - EOF -

    推荐阅读

    转载于:https://my.oschina.net/u/3630350/blog/1522870

    展开全文
  • 服务容器就是一个普通的容器,用来装类的实例,然后在需要的时候再取出来。用更专业的术语来说是服务容器实现了控制反转(Inversion of Control,缩写为 IoC),意思是正常情况下类 A 需要一个类 B 的时候,我们需要...
    1. 什么是服务器容器
      服务容器就是一个普通的容器,用来装类的实例,然后在需要的时候再取出来。用更专业的术语来说是服务容器实现了控制反转(Inversion of Control,缩写为 IoC),意思是正常情况下类 A 需要一个类 B 的时候,我们需要自己去 new 类 B,意味着我们必须知道类 B 的更多细节,比如构造函数,随着项目的复杂性增大,这种依赖是毁灭性的。控制反转的意思就是,将类 A 主动获取类 B 的过程颠倒过来变成被动,类 A 只需要声明它需要什么,然后由容器提供。

    这样做的好处是,类 A 不依赖于类 B 的实现,这样在一定程度上解决了耦合问题。

    在 Laravel 的服务容器中,为了实现控制反转,可以有以下两种:

    依赖注入(Dependency Injection)。
    绑定。

    1. 什么是解耦

    简而言之:A类不再直接依赖B类,而是在A类和B类之间生成一个缓冲区,利用这个缓冲区传递数据

    1. 什么是依赖注入

    简而言之:A类调用B类的方法的时候,不在A类中实例化一个B类的对象,而是只在函数中引入B类的对象(举例用构造函数),并在A类中保存后调用。而实例化B类的过程,放在了A类外部。

    传统方法

    clas A {
    	public function __construct() {
    		$this->obj = new B();
    	}
    }
    
    $a = new A()
    

    依赖注入方法

    clas A {
    	public function __construct(B $b) {
    		$this->obj = $b;
    	}
    }
    
    $b = new B();
    $a = new A($b);
    

    PS:PHP中为了解决依赖注入的一些问题,引入了接口类的概念(Interface

    1. PHP和Laravel的生命周期
    1. 模块初始化(MINIT),即调用 php.ini 中指明的扩展的初始化函数进行初始化工作,如 mysql 扩展。
    2. 请求初始化(RINIT),即初始化为执行本次脚本所需要的变量名称和变量值内容的符号表,如 $_SESSION 变量。
    3. 执行该 PHP 脚本。(Lravel生命周期开始)
    	
    	3.1 注册加载 composer 自动生成的 class loader,包括所有你 composer require 的依赖(对应代码 1.
    	3.2 生成容器 Container,Application 实例,并向容器注册核心组件。这里牵涉到了容器 Container 和合同 Contracts,以及依赖注入等问题
    	3.3 处理请求,生成并发送响应(对应代码 3,毫不夸张的说,你 99% 的代码都运行在这个小小的 handle 方法里面)。(具体代码的实现位置)
    	3.4 请求结束,进行回调(对应代码 4,还记得可终止中间件吗?没错,就是在这里回调的)。
    
    4. 请求处理完成 (Request Shutdown),按顺序调用各个模块的 RSHUTDOWN 方法,对每个变量调用 unset 函数,如 unset $_SESSION 变量。
    5. 关闭模块 (Module Shutdown)PHP 调用每个扩展的 MSHUTDOWN 方法,这是各个模块最后一次释放内存的机会。这意味着没有下一个请求了。
    

    PS:其他文档

    使用  bind()/singleton()  方法把容器与接口具体的实现类进行绑定:
    app()->bind(MyInterface::class, MyClass::class);  // 使用一次绑定一次,下一次需要重新绑定
    app()->singleton(MyInterface::class, MyClass::class);  // 一个周期只绑定一次,下一次不需要绑定
    
    $instance = app()->make(MyInterface::class);
    // 相当于
    $instance = app(MyInterface::class);
    // 相当于
    $instance = new MyClass(new AnotherClass());
    
    

    绑定服务容器

    interface Fruit
    {
        public function color();
    }
    
    class Apple implements Fruit
    {
        public $color;
    
        public function __construct($color){
            $this->color = $color;
        }
    
        public function color(){
            return $this->color;
        }
    }
    
    app()->bind('Fruit', 'Apple');
    // 当类Apple需要$color参数的时候,将red传给他
    app()->bind(Fruit::class, Apple::class);
    app()->when(Apple::class)->needs('$color')->give('22');
    echo app(Fruit::class)->color();
    
    1. 服务提供者Server Provider

    用于绑定类到容器中
    相当于将药片(类)放入药箱(容器)的小格子中(服务提供者),每个格子管理一种药片

    // 新建一个服务提供者
    php artisan make:provider AbcServiceProvider
    

    解析顺序为:

    // public/index.php
    $app = require_once __DIR__.'/../bootstrap/app.php';// 注册核心服务
    
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    
    // bootstrap/app.php
    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );
    // vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php,执行handle方法中的sendRequestThroughRouter
        public function handle($request) {
        	...
        	$response = $this->sendRequestThroughRouter($request);
        }
    	// 在sendRequestThroughRouter方法中再执行bootstrap()
       \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    
    // 因为执行的是根据config/app.php加载的providers,例如
         /*
          * Application Service Providers...
          */
         App\Providers\AppServiceProvider::class,
         App\Providers\AuthServiceProvider::class,
         // App\Providers\BroadcastServiceProvider::class,
         App\Providers\EventServiceProvider::class,
         App\Providers\RouteServiceProvider::class,
    

    所以要在config/app.php中注册AbcServiceProvider

    之后在AbcServiceProvider中绑定类和容器

    class AbcServiceProvider extends ServiceProvider implements DeferrableProvider
    {
        public function register()
        {
            $this->app->singleton(Connection::class, function ($app) {
                return new Connection(config('riak'));
            });
        }
    
    	// 默认生成的方法是没有这个的
    	// 使用延时服务提供者后,只有在真正调用这个服务器提供者的时候,才会进行加载,节约内存
    	// 实现方法:implements DeferrableProvider和public function provides()和类名Connection::class
    	// 可以参考缓存的服务提供者vendor/laravel/framework/src/Illuminate/Cache/CacheServiceProvider.php
        public function provides()
        {
            return [Connection::class];
        }
    }
    
    1. 深入浅出 Laravel 的 Facade 外观系统

    加载外观服务有 AliasLoader 组件完成:

    首先,会从配置文件 config/app.php 中读取所有的「外观」服务配置 aliases;

    再从清单文件中读取别名服务 $app->make(PackageManifest::class)->aliases();

    将两个配置数组合并后注入到 AliasLoader 完成 注册(先在使用「外观」服务时动态引入这个类后再进行注册。)

    最后后在客户端中调用外观服务时,会调用实现「外观」的 getFacadeAccessor 方法获取到组件(服务或者说接口)的名称;然后从 Laravel 服务容器中解析出相关服务。

    展开全文
  • Laravel 核心概念讲解

    2017-12-11 08:36:19
    首先,定义一个: /routes/web.php class Bar {} 假如我们在其他地方要使用到 Bar 提供功能(服务),怎么办,直接传入参数即可: /routes/web.php Route::get('bar', function(Bar $bar) { dd
  • 一个laravel service provider就是一个注册IoC container binding的类。实际上,laravel本身就自包含了一堆管理核心框架组件container bindingservice provider. 一个service provider必须具有至少一个方法: ...
  • [Laravel] 从 1 行代码开始,带你系统性理解 Laravel Service Container 核心概念   laravel 5.6 route 注册已转移到app内部实现,而非由RouteServiceProvider提供 Laravel /未分类 /[Laravel] 从 1 行...
  • 自动依赖注入 什么是依赖注入,用大白话将通过类型提示...首先,定义一个: /routes/web.php class Bar {} 假如我们在其他地方要使用到Bar提供功能(服务),怎么办,直接传入参数即可: /routes/web.php...
  • 第一次写技术博客,因为比较懒,至于作为一个懒人为何会写博客,因为记性比较差,常常当初灵光一闪理解的概念最后会忘记。所以还是用文字记录下来,以备自己后查,有缘人看到也可以做个参考,不同意见欢迎指正。...
  • 自动依赖注入 ...首先,定义一个: /routes/web.php class Bar {} 假如我们在其他地方要使用到 Bar 提供功能(服务),怎么办,直接传入参数即可: /routes/web.php Route::get('bar', function(Bar...
  • laravel 服务容器,容器概念

    千次阅读 2019-11-06 11:38:11
    实质是工厂模式的升级,类的传递动态加载 ####以下内容转载 容器,字面上理解就是装东西的东西。常见的变量、对象属性等都可以算是容器。一个容器能够装什么,全部取决于你对该容器的定义。当然,有这样一种容器...
  • 首先,定义一个: /routes/web.php class Bar {} 假如我们在其他地方要使用到Bar提供功能(服务),怎么办,直接传入参数即可: /routes/web.php Route::get('bar', function(Bar $bar) { dd($bar)...
  • PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法、成员,而反射类则是...本章讲解反射类的使用及Laravel对反射的使用。 反射 反射类是PHP内部类,无需加载即可使用,你可以通过实例化 ReflectionC...
  • 领域层无需关心这些数据库各自的类文件放哪里,只需要告诉Repository需要哪一个,由Repository拿出来给领域层。可以看到,好处就是领域层可以方便地切换数据库,理论上只要改一处配置,无需改太多代码。 来个...
  • Laravel这个框架,用起来方便,理解起来不简单。为什么不简单?因为包含了一大堆所谓“先进”的概念,其中...下面这篇文章主要给大家介绍了关于Laravel 5.4向IoC容器中添加自定义类的相关资料,需要的朋友可以参考下。
  • 该软件包主要概念是提供一种从应用程序发出新事件简便方法,并允许在使用同一Redis服务器其他应用程序中侦听它们。 安装 通过composer命令安装软件包composer require prwnr/laravel-streamer或将其添加到带...
  • 《简单理解Laravel的核心概念----服务容器、服务提供者、契约》 在这篇文章中,你会了解到: 服务是如何被注册到服务容器 服务是究竟怎样从容器中解析 我们知道,laravel的服务容器,会有两方面工作: ...
  • Laravel的Ioc设计

    2018-02-05 20:36:59
    一、IoC的概念介绍 控制反转(IOC)模式(又称DI:DependencyInjection)就是Inversion ofControl,控制反转。在Java开发中,IoC意 味着将你设计好的交给系统去控制,而不是在你的内部控制。这称为控制反转。 ...
  • 本章讲解反射类的使用及Laravel对反射的使用。 反射 反射类是PHP内部类,无需加载即可使用,你可以通过实例化 ReflectionClass 类去使用它。 方法 这里列举下PHP反射类常用的方法 方法名 注释 ReflectionCl
  • 前言 ...就如“解刨”一样,我们可以调用任何关键字修饰的方法、成员。当然在正常业务中是建议不使用,比较反射类已经摒弃了封装的概念。...本章讲解反射类的使用及Laravel对反射的使用。 反射 反射类是PHP内部类,...
  • 模型层是使用2个定义:一个Entity可以是任何PHP,或者可以扩展提供魔术getter和setter基本Analogue \ ORM \ Entity,以及一个EntityMap定义关系,转换,表名,数据库列名。 使用这个简单域模型: ...
  • 和模型相关的类对象 Eloquent 集合 => 可以简单理解为对象数组,里面每一个元素都是一个Model 对象 DB Facades 1, $users = DB::table('users')->get(); 返回值:数组结果,其中每一个结果都是 StdClass ...
  • Laravel中间键创建及使用

    千次阅读 2017-04-05 13:43:17
    2.先说一个没有中间键概念的PHP框架,如ThinkPHP(简称TP),在TP框架中进行开发时,有些页面必须是登录用户才能访问,通常做法是创建一个父类控制器,该控制器里构造方法判断用户是否登录,其他有登录限制控制...

空空如也

空空如也

1 2 3 4 5
收藏数 87
精华内容 34
关键字:

laravel类的概念