精华内容
下载资源
问答
  • Laravel核心概念

    2021-03-16 17:24:26
    Laravel核心概念 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 框架”。

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

    2017-12-11 08:36:19
    首先,定义一个: /routes/web.php class Bar {} 假如我们在其他地方要使用到 Bar 提供的功能(服务),怎么办,直接传入参数即可: /routes/web.php Route::get('bar', function(Bar $bar) { dd

    自动依赖注入

    什么是依赖注入,用大白话将通过类型提示的方式向函数传递参数。

    实例 1

    首先,定义一个类:

    /routes/web.php
    class Bar {}

    假如我们在其他地方要使用到 Bar 提供的功能(服务),怎么办,直接传入参数即可:

    /routes/web.php
    Route::get('bar', function(Bar $bar) {
        dd($bar);
    });

    访问 /bar,显示 $bar 的实例:

    Bar {#272}

    也就是说,我们不需要先对其进行实例!如果学过 PHP 的面向对象,都知道,正常做法是这样:

    class Bar {}
    $bar = new Bar();
    dd($bar);

    实例 2

    可以看一个稍微复杂的例子:

    class Baz {}
    class Bar { public $baz; public function __construct(Baz $baz) { $this->baz = $baz; } } $baz = new Baz(); $bar = new Bar($baz); dd($bar);

    为了在 Bar 中能够使用 Baz 的功能,我们需要实例化一个 Baz,然后在实例化 Bar 的时候传入 Baz 实例。

    在 Laravel 中,不仅仅可以自动注入 Bar,也可以自动注入 Baz:

    /routes/web.php
    class Baz {}
    class Bar { public $baz; public function __construct(Baz $baz) { $this->baz = $baz; } } Route::get('bar', function(Bar $bar) { dd($bar->baz); });

    显示结果:

    Baz {#276}

    小结

    通过上述两个例子,可以看出,在 Laravel 中,我们要在类或者函数中使用其他类体用的服务,只需要通过类型提示的方式传递参数,而 Laravel 会自动帮我们去寻找响对应的依赖。

    那么,Laravel 是如何完成这项工作的呢?答案就是通过服务容器。

    服务容器

    什么是服务容器

    服务容器,很好理解,就是装着各种服务实例的特殊类。可以通过「去餐馆吃饭」来进行类比:

    • 吃饭 - 使用服务,即调用该服务的地方

    • 饭 - 服务

    • 盘子 - 装饭的容器,即服务容器

    • 服务员 - 服务提供者,负责装饭、上饭

    这个过程在 Laravel 中如何实现呢?

    定义 Rice 类:

    /app/Rice.php
    <?php
    
    namespace App;
    
    class Rice { public function food() { return '香喷喷的白米饭'; } }
    • 把饭装盘子

    在容器中定义了名为 rice 的变量(你也可以起其他名字,比如 rice_container),绑定了 Food 的实例:

    app()->bind('rice', function (){
        return new \App\Rice(); });

    也可以写成:

    app()->bind('rice',\App\Rice::class);

    现在,吃饭了,通过 make 方法提供吃饭的服务:

    Route::get('eat', function() {
           
           return app()->make('rice')->food(); // 或者 return resolve('rice')->food(); });

    make 方法传入我们刚才定义的变量名即可调用该服务。

    访问 /eat,返回 香喷喷的白米饭

    为了方便起见,我们在路由文件中直接实现了该过程,相当于自给自足。但是服务通常由服务提供者来管理的。

    因此,我们可以让 AppServiceProvider 这个服务员来管理该服务:

    /app/Providers/AppServiceProvider.php
    namespace App\Providers;
    
    public function register() { $this->app->bind('food_container',Rice::class); }

    更为常见的是,我们自己创建一个服务员:

    $ php artisan make:provider RiceServiceProvider

    注册:

    /app/Providers/RiceServiceProvider.php
    <?php
    
    use App\Rice;
    public function register() { $this->app->bind('rice',Rice::class); }

    这里定义了 register() 方法,但是还需要调用该方法才能真正绑定服务到容器,因此,需要将其添加到 providers 数组中:

    /config/app.php
    'providers' => [
       App\Providers\RiceServiceProvider::class,
    ],

    这一步有何作用呢?Laravel 在启动的时候会访问该文件,然后调用里面的所有服务提供者的 register() 方法,这样我们的服务就被绑定到容器中了。

    小结

    通过上述的例子,基本上可以理解服务容器和服务提供者的使用。当然了,我们更为常见的还是使用类型提示来传递参数:

    use App\Rice;
    
    Route::get('eat', function(Rice $rice) { return $rice->food(); });

    在本例中,使用自动依赖注入即可。不需要在用 bind 来手动绑定以及 make 来调用服务。那么,为什么还需要 bind 和 make 呢? make 比较好理解,我们有一些场合 Laravel 不能提供自动解析,那么这时候手动使用 make 解析就可以了,而 bind 的学问就稍微大了点,后面将会详细说明。

    门面

    门面是什么,我们回到刚才的「吃饭」的例子:

    Route::get('eat', function(Rice $rice) {
           return $rice->food(); });

    在 Laravel,通常还可以这么写:

    Route::get('eat', function() {
           return Rice::food(); });

    或者

    Route::get('eat', function() {
           return rice()->food(); });

    那么,Laravel 是如何实现的呢?答案是通过门面。

    门面方法实现

    先来实现 Rice::food(),只需要一步:

    /app/RiceFacade.php
    <?php 
    
    namespace App;
    use Illuminate\Support\Facades\Facade; class RiceFacade extends Facade { protected static function getFacadeAccessor() { return 'rice'; } }

    现在,RiceFacade 就代理了 Rice 类了,这就是门面的本质了。我们就可以直接使用:

    Route::get('eat', function() {
    
        dd(\App\RiceFacade::food());
    
    });

    因为 \App\RiceFacade 比较冗长,我们可以用 php 提供的 class_alias 方法起个别名吧:

    /app/Providers/RiceServiceProvider.php
    public function register() { $this->app->bind('rice',\App\Rice::class); class_alias(\App\RiceFacade::class, 'Rice'); }

    这样做的话,就实现了一开始的用法:

    Route::get('eat', function() {
           return Rice::food(); });

    看上去就好像直接调用了 Rice 类,实际上,调用的是 RiceFacade 类来代理,因此,个人觉得Facade 翻译成假象比较合适。

    最后,为了便于给代理类命名,Laravel 提供了统一命名别名的地方:

    /config/app.php
    
    'aliases' => [
    
        'Rice' => \App\RiceFacade::class,
    
    ],

    门面实现过程分析

    首先:

    Rice::food();

    因为 Rice 是别名,所以实际上执行的是:

    \App\RiceFacade::food()

    但是我们的 RiceFacade 类里面并没有定义静态方法 food 啊?怎么办呢?直接抛出异常吗?不是,在 PHP 里,如果访问了不可访问的静态方法,会先调用 __callstatic,所以执行的是:

    \App\RiceFacade::__callStatic()

    虽然我们在 RiceFacade 中没有定义,但是它的父类 Facade 已经定义好了:

    /vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php
    public static function __callStatic($method, $args) { // 实例化 Rice {#270} $instance = static::getFacadeRoot(); // 实例化失败,抛出异常 if (! $instance) { throw new RuntimeException('A facade root has not been set.'); } // 调用该实例的方法 return $instance->$method(...$args); }

    主要工作就是第一步实例化:

    public static function getFacadeRoot() { return static::resolveFacadeInstance(static::getFacadeAccessor()); // 本例中:static::resolveFacadeInstance('rice') }

    进一步查看 resolveFacadeInstance() 方法:

     protected static function resolveFacadeInstance($name) { // rice 是字符串,因此跳过该步骤 if (is_object($name)) { return $name; } // 是否设置了 `rice` 实例 if (isset(static::$resolvedInstance[$name])) { return static::$resolvedInstance[$name]; } return static::$resolvedInstance[$name] = static::$app[$name]; }

    第一步比较好理解,如果我们之前在 RiceFacade 这样写:

    protected static function getFacadeAccessor() { return new \App\Rice; }

    那么就直接返回 Rice 实例了,这也是一种实现方式。

    主要难点在于最后这行:

    return static::$resolvedInstance[$name] = static::$app[$name];

    看上去像是在访问 $app数组,实际上是使用 数组方式来访问对象,PHP 提供了这种访问方式接口,而 Laravel 实现了该接口。

    也就是说,$app 属性其实就是对 Laravel 容器的引用,因此这里实际上就是访问容器上名为 rice 的对象。而我们之前学习容器的时候,已经将 rice 绑定了 Rice 类:

    public function register() { $this->app->bind('rice',\App\Rice::class); // class_alias(\App\RiceFacade::class, 'Rice'); }

    所以,其实就是返回该类的实例了。懂得了服务容器和服务提供者,理解门面也就不难了。

    辅助方法实现

    辅助方法的实现,更简单了。不就是把 app->make('rice') 封装起来嘛:

    /vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
    if (! function_exists('rice')) {
      
        function rice() { return app()->make('rice'); // 等价于 return app('rice'); // 等价于 return app()['rice']; } } 

    然后我们就可以使用了:

    Route::get('eat', function() {
    
        dd(rice()->food());
    });

    小结

    Laravel 提供的三种访问类的方式:

    • 依赖注入:通过类型提示的方式实现自动依赖注入

    • 门面:通过代理来访问类

    • 辅助方法:通过方法的方式来访问类

    本质上,这三种方式都是借助于服务容器和服务提供者来实现。那么,服务容器本身有什么好处呢?我们接下来着重介绍下。

    IOC

    不好的实现

    我们来看另外一个例子(为了方便测试,该例子都写在路由文件中),假设有三种类型的插座:USB、双孔、三孔插座,分别提供插入充电的服务:

    class UsbsocketService
    {
        public function insert($deviceName){ return $deviceName." 正在插入 USB 充电"; } } class DoubleSocketService { public function insert($deviceName){ return $deviceName." 正在插入双孔插座充电"; } } class ThreeSocketService { public function insert($deviceName){ return $deviceName." 正在插入三孔插座充电"; } }

    设备要使用插座的服务来充电:

    class Device {
    
        protected $socketType; // 插座类型 public function __construct() { $this->socketType = new UsbSocketService(); } public function power($deviceName) { return $this->socketType->insert($deviceName); } }

    现在有一台手机要进行充电:

    Route::get('/charge',function(){
           
       $device = new Device(); return $device->power("手机"); });

    因为 Laravel 提供了自动依赖注入功能,因此可以写成:

    Route::get('/charge/{device}',function(Device $device){
           
       return $device->power("手机"); });

    访问 /charge/phone,页面显示 phone 正在插入 USB 充电

    假如,现在有一台电脑要充电,用的是三孔插座,那么我们就需要去修改 Device 类:

    $this->socketType = new ThreeSocketService();

    这真是糟糕的设计,设备类对插座服务类产生了依赖。更换设备类型时,经常就要去修改类的内部结构。

    好的实现

    为了解决上面的问题,可以参考「IOC」思路:即将依赖转移到外部。来看看具体怎么做。

    首先定义插座类型接口:

    interface SocketType {
        public function insert($deviceName); }

    让每一种插座都实现该接口:

    class UsbsocketService implements SocketType { public function insert($deviceName){ return $deviceName." 正在插入 USB 充电"; } } class DoubleSocketService implements SocketType { public function insert($deviceName){ return $deviceName." 正在插入双孔插座充电"; } } class ThreeSocketService implements SocketType { public function insert($deviceName){ return $deviceName." 正在插入三孔插座充电"; } }

    最后,设备中传入接口类型而非具体的类:

    class Device {
    
        protected $socketType; // 插座类型 public function __construct(SocketType $socketType) // 传入接口 { $this->socketType = $socketType; } public function power($deviceName) { return $this->socketType->insert($deviceName); } }

    实例化的时候再决定使用哪种插座类型,这样依赖就转移到了外部:

    Route::get('/charge',function(){
       
       $socketType = new ThreeSocketService(); $device = new Device($socketType); echo $device->power("电脑"); });

    我们现在可以再不修改类结构的情况下,方便的更换插座来满足不同设备的充电需求:

    Route::get('/charge',function(){
       
       $socketType = new DoubleSocketService(); $device = new Device($socketType); echo $device->power("台灯"); });

    自动依赖注入的失效

    上面举的例子,我们通过 Laravel 的自动依赖注入可以进一步简化:

    Route::get('/charge',function(Device $device){ 
           echo $device->power("电脑"); });

    这里的类型提示有两个,一个是 Device $device,一个是 Device 类内部构造函数传入的 SocketType $sockType。第一个没有问题,之前也试过。但是第二个 SocketType 是接口,而 Laravel 会将其当成类试图去匹配 SocketType 的类并将其实例化,因此访问 /charge 时候就会报错:

    Target [SocketType] is not instantiable while building [Device].

    错误原因很明显,Laravel 没法自动绑定接口。因此,我们就需要之前的 bind 方法来手动绑定接口啦:

    app()->bind('SocketType',ThreeSocketService::class);
    Route::get('/charge',function(Device $device){ echo $device->power("电脑"); });

    现在,如果要更换设备,我们只需要改变绑定的值就可以了:

    app()->bind('SocketType',DoubleSocketService::class);
    Route::get('/charge',function(Device $device){ echo $device->power("台灯"); });

    也就是说,我们将依赖转移到了外部之后,进一步由第三方容器来管理,这就是 IOC。

    契约

    契约,不是什么新奇的概念。其实就是上一个例子中,我们定义的接口:

    interface SocketType {
        public function insert($deviceName); }

    通过契约,我们就可以保持松耦合了:

    public function __construct(SocketType $socketType) // 传入接口而非具体的插座类型 { $this->socketType = $socketType; }

    然后服务容器再根据需要去绑定哪种服务即可:

    app()->bind('SocketType',UsbSocketService::class);
    app()->bind('SocketType',DoubleSocketService::class);
    app()->bind('SocketType',ThreeSocketService::class);
    
    
    展开全文
  • 深入理解Laravel容器概念,DI依赖注入,IOC控制反转 IOC - 控制反转 DI - 依赖注入 这两个存在的目的都是为了解耦! 解耦可以理解为,原本紧密结合的两个磁铁,现在我们在他们中间加一层木板,强行将他们分开,却不...

    深入理解Laravel容器概念,DI依赖注入,IOC控制反转

    IOC - 控制反转
    DI - 依赖注入

    这两个存在的目的都是为了解耦!

    解耦可以理解为,原本紧密结合的两个磁铁,现在我们在他们中间加一层木板,强行将他们分开,却不影响他们原有的功能于磁性。

    所谓依赖就是 Class A 对于功能function a() 的实现需要依赖于class B
    而注入就是在Class A实现功能 function a() 时,直接将class B注入到A

    举个例子,小明去买华为手机 买手机依赖华为
    代码实现 :

    class Huawei{
        public $goods = [
            'phone' => '手机:Mata30',
            'computer' => '笔记本:Mata12'
        ];
    }
    class Persion{
        public $huawei;
        public $name;
        //买手机依赖华为商城
        public function __construct($name){
            $this->huawei = new Huawei();
            $this->name = $name;
    	}
        public function buy($goodName){
            // 先查看华为有什么商品
            $goods = $this->huawei->goods;
            $str = '华为商城有:'.implode(',',$goods);
            echo $str.'</br>';
    		// 购买商品
            $this->account($goodName);
    	}
        // 商品结算
        public function account($goodName)
        {
            $goods = $this->huawei->goods;
            $good = $goods[$goodName];
            echo $this->name.'购买了商品'.$good;
        }
    }
    
    $xiaoming = new Persion('Xiaoming');
    $xiaoming->buy('phone');
    

    输出结果:
    华为商城有:手机:Mata30,笔记本:Mata12
    Xiaoming购买了商品手机:Mata30

    乍看一眼还是没问题,但是如果小明突然想去小米买手机。这时候你就得改里面的构造方法。每次有需求都要改构造方法,这样的是非常糟糕的体验。

    这时候就需要控制反转IOC
    通俗点说,控制反转就是将new Huawei() 这个操作由 Person 类去决定,即在构造方法中传递参数,决定去华为还是小米买手机;

    class Persion{
        public $huawei;
        public $name;
        //买手机依赖华为商城
        public function __construct($business,$name){
            $this->huawei = new $business();
            $this->name = $name;
    	}
    }
    

    所谓服务提供者就是为项目提供各种服务的
    他主要做两个工作:
    1.将服务实例类注册到服务容器中
    2.自己会执行boot引导方法,去加载自己这个服务需要的一些东西

    下面我以淘宝商城为例,实现降了N级别的Laravel IOC容器。

    淘宝可以称为一个IOC容器,有客户和商家两种类型。
    商家、客户都要注册进淘宝。
    客户再获取商家的实例购买商家的产品。

    下面代码实现:

    // 客户类
    class Customers{
        //顾客姓名
        private $name;
        //创建对象时创建人名
        public function __construct($name)
        {
            $this->name = $name;
        }
        // 获取客户实例类的时候会执行的方法
        public function boot()
        {
    
        }
        //购买商品方法
        // Huawei 即依赖,通过注入的方式注入到$huawei中
        public function buy(HuaWei $huawei,$goodName)
        {
           $str = '欢迎'.$this->name.'来到华为商城查看商品,我们的商品有:';
           foreach ($huawei->goods as $good)
           {
               $str .= $good.',';
           }
           echo rtrim($str,',').'</br>';
           $this->account($huawei,$goodName);
        }
        //商品结算方法
        public function account(HuaWei $huaWei,$goodName)
        {
            $goods = $huaWei->goods;
            $good = $goods[$goodName];
            echo $this->name.'购买了华为产品:'.$good;
        }
    }
    //华为商家类
    class HuaWei{
        //华为商品
        public $goods;
        //服务引导方法,上架商品
        public function boot()
        {
            $this->goods =  [
                'phone' => '手机:Mata30',
                'computer' => '笔记本:Mata12'
            ];
        }
    }
    // 淘宝即IOC容器
    class TaoBao
    {
        //存放各种商家
        private $shangjia = [];
        //存放各种客户
        private $customer = [];
        //往淘宝注册商家   参数1 商家名字, 参数2 闭包函数 商家实例
        public function register($name,$bibao)
        {
            $this->shangjia[$name] = $bibao;
        }
    
        // 通过商家名字商家实例
        public function getShangjia($name)
        {
            //执行闭包函数获取商家实例
            $object = ($this->shangjia[$name])();
            $object->boot();
            return $object;
        }
    
        //客户在淘宝登录 参数1 用户别名 参数2 闭包函数,客户实例
        public function login($name,$bibao){
            $this->customer[$name] = $bibao;
        }
    
        public function getCunstomer($name)
        {
            //执行闭包函数获取客户实例
            return ($this->customer[$name])();
        }
    }
    //创建出淘宝平台IOC容器
    $taobao = new TaoBao();
    //华为商城入驻淘宝
    $taobao->register('huawei',function (){
       return new HuaWei() ;
    });
    
    //用户小明登录淘宝
    $taobao->login('xiaoming',function (){
        return new Customers('小明');
    });
    
    //用户阿三登录淘宝
    $taobao->login('asan',function (){
        return new Customers('阿三');
    });
    //获取登录人小明的实例
    $xiaoming = $taobao->getCunstomer('xiaoming');
    //获取华为实例
    $huawei = $taobao->getShangjia('huawei');
    //小明买华为手机
    $xiaoming->buy($huawei,'phone');
    

    可以看得出,IOC的本质就是操作数组。
    当然Laravel 不是简单的通过 new 去获取注册的实例。而是通过反射的机制,获取类的构造方法,需要的参数等。然后再实例出对象。这个大家可以自己百度研究,实现过程比较复杂。

    以上就是我对Laravel 容器的概念。

    展开全文
  • 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

    展开全文
  • laravel 服务容器,容器概念

    千次阅读 2019-11-06 11:38:11
    Laravel 服务容器 发现一篇讲服务容器的文章,讲的很好,转载过来laravel 服务容器 实质是工厂模式的升级,的传递动态加载 ####以下内容转载 容器,字面上理解就是装东西的东西。常见的变量、对象属性等都...
  • Laravel 核心概念

    2021-01-28 17:50:31
    核心概念 简介、服务容器、服务提供者、facade、contract、生命周期。 我叫 Laravel。我是一个装了药的 药箱,专门处理人们的问题、治病。 人们喜欢把我的药箱叫做 service container 服务容器。 把我的药箱里面的一...
  • laravel 是一个小朋友。另一个小朋友叫Lighthouse ,Lighthouse 带了另一个小朋友叫 Graphql ,然后三个开开心心玩在一起。laravel 借助 graphql 去查询 database Lighthouse 针对 graphql 封装了很多东西。比方说...
  • Laravel—核心概念

    2019-03-20 13:01:55
    本文转自...确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Laravel时,会变得一目了然胸有成竹。 PHP的生命周期 万物皆有他的生命周期。...
  • Laravel这个框架,用起来方便,理解起来不简单。为什么不简单?因为包含了一大堆所谓“先进”的概念,其中...下面这篇文章主要给大家介绍了关于Laravel 5.4向IoC容器中添加自定义的相关资料,需要的朋友可以参考下。
  • 目录阅读Laravel Service Provider 概念详解概览过程分析1、首先,生成核心 Container : $app (实例化过程中还注册了一大堆基本的「绑定])2、接下来注册 `Http\Kernel , Console\Kernel , Debug\ExecptionHandler` ...
  • Laravel的核心概念

    2017-10-12 11:17:30
    确实如此,这篇文章读完你可能并不能从无到有写出一个博客,但知道Laravel的核心概念之后,当你再次写起Laravel时,会变得一目了然胸有成竹。 PHP的生命周期 万物皆有他的生命周期。熟悉Android的同学一定熟悉...
  • 第一次写技术博客,因为比较懒,至于作为一个懒人为何会写博客,因为记性比较差,常常当初灵光一闪理解的概念最后会忘记。所以还是用文字记录下来,以备自己后查,有缘人看到也可以做个参考,不同意见欢迎指正。...
  • 自动依赖注入 什么是依赖注入,用大白话将通过类型提示的...首先,定义一个: /routes/web.php class Bar {} 假如我们在其他地方要使用到Bar提供的功能(服务),怎么办,直接传入参数即可: /routes/web.php...
  • 主要介绍了为你的 Laravel 验证器加上多验证场景的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 原文发表在我的个人网站:深入理解 Laravel Eloquent(一)——基本概念及用法 在本系列文章中,我将跟大家一起学习 Eloquent 的基本用法,探索 Eloquent 的各种高级功能,理解 Eloquent 背后的运行原理,并最终...
  • 一个laravel service provider就是一个注册IoC container binding的。实际上,laravel本身就自包含了一堆管理核心框架组件的container binding的service provider. 一个service provider必须具有至少一个方法: ...
  • Laravel中的基本概念

    2020-08-02 10:35:04
    服务提供者本身也是一个,不过这个只有启动和注册两个函数。 /** * Bootstrap the application services. * * @return void */ public function boot() { // } /** * Register the application ...
  • laravel 框架以及关键概念重新理解,什么是服务容器,什么事服务提供者,如何绑定服务,门面和契约概念
  • Laravel核心概念学习

    2016-11-09 13:43:56
    一、Laravel请求过程 二、artisan命令 下面会以生成用户表为例(注意表名一般为复数): 1、生成迁移文件 Pro-3:mac$ php artisan make:migration create_users_table Migration: 2016_11_23_131412_create_users_...
  • 诸如Hijri日期和阿拉伯字符串之概念Laravel会讲阿拉伯语一个轻量的laravel包,它有助于使用一组和方法使Laravel讲阿拉伯语,从而在Laravel Framework中处理阿拉伯概念! 诸如回历日期和阿拉伯字符串之的...
  • 比如用户登录、登出其实都是用户的行为,假设使用$listen数组去注册的话,就要写2个监听器,代码太冗余,但用事件订阅者,就只要写一个,最后把用户行为在 subscribe方法中统一绑定,看源码就发现注册形式和写在...
  • app启动的时候kernel通过handle,触发了app中的bootstrapwith,并且触发了每个列表中实现中的bootstrap方法 bootstrapwith加载了所有启动需要的一个列表, 列表中的RegisterFacade中有个bootstrap被触发,然后...
  • 诸如回历日期和阿拉伯字符串之概念.. 代码示例 use Adnane \ Arabic \ Arabic ; echo Arabic :: tafkit ( 12078437 ); // اثنا عشر مليون و ثمان و سبعون ألف و أربع مئة ...
  • laravel创建全局公共函数,Helper类laravel创建公共函数,Helper提出问题:分析问题:知识储备providers (提供者)Helpers (助手)解决步骤自定义一个providers注册提供器编辑自定义的HelperServiceProvider创建...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,725
精华内容 1,090
关键字:

laravel类的概念