thinkphp-容器和依赖注入、门面Facade

3273次阅读 78人点赞 作者: WuBin 发布时间: 2024-05-21 14:03:54
扫码到手机查看

容器和依赖注入

依赖注入

依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于访问控制器的参数都来自于URL请求,普通变量就是通过参数绑定自动获取,对象变量则是通过依赖注入生成。

通过一个例子来辅助理解

首先创建一个model/One.php这个模型

namespace app\model;
use think\Model;

class One extends Model
{
    public $username = 'Mr 5';
}

然后再在controller/Inject.php中,调用模型中的数据

namespace app\controller;
use app\model\One;

class Inject 
{
    protected $one;

    // One就是对应model对象
    public function __construct(One $one)
    {
        // 通过依赖注入 这里的$one相当于One这个类
        $this->one = $one;
    }

    public function index()
    {
        return $this->one->username;
    }
}

依赖注入:即允许通过类的方法传递对象的能力,并且限制了对象的类型(约束);例子中就是One,传递的对象背后的那个类被自动绑定并且实例化了,这就是依赖注入

容器

依赖注入的类统一由容器管理的,大多数情况下是自动绑定和自动实例化的,如果想手动来完成绑定和实例化,可以使用bind()和app()助手函数来实现。

在controller/Inject.php这个控制器中,创建新方法实现手动实例化

public function bind()
{
        // 手动绑定一个对象,第一个参数随便起名, 第二个参数通过命名空间的路径
        bind('one', 'app\model\One');    
        // 通过app方法进行实例化
        return app('one')->username;
}
bind('one','...')绑定类库标识,这个标识具有唯一性,以便快速调用,app('one')快速调用,并自动实例化对象,标识严格保持一致包括大小写;

自动实例化对象的方式,是采用单例模式实现。如果每次都是想重新实例化一个对象:

//每次调用总是会重新实例化
$one = app('one',[], true);
return $one->name;

加一个第三个参数,true,而第二个方法是构造方法的传参。app('one',[])中第二参数,方法实例化对象的时候,传递参数,比如,修改一下模型类:

namespace app\model;
use think\Model;

class One extends Model
{
    public $username = 'Mr 5';

    public function __construct(array $data = [])
    {
        parent::__construct($data);
        print_r($data);
    }
}

控制器中

public function bind()
    {
        bind('one', 'app\model\One');    
        // 通过app方法进行实例化,相当于 new One
        $one = app('one', ['file'], true);
        return $one->username;
    }

这里运行就会报错:One::__construct() must be of the type array, string given

这是因为 app('one', ['file'],true); 第二个参数['file']相当于一个字符串!所以正确写法:

$one = app('one', [ ['file'] ], true);

当然,你也可以直接通过app()绑定一个类到容器中并自动实例化;

return app('app\model\One')->username;

使用bind([])可以实现批量绑定

bind([
            'one' => 'app\model\One',
            'user' => 'app\model\User'
]);
return app('one')->username;

或者使用::class 模式,注意,不需要单引号,而且需要在最前面加上\,如果不加\那么就会提示路径错误!

bind([
            'one' => \app\model\One::class
]);
return app('one')->username;

系统提供了app/provider.php 文件,用于批量绑定类到容器中,这样公共区域就可以用了,上面的方法,只能是在某个控制器或者控制器的方法中使用。 这里app路径前加不加\都正常

<?php
use app\ExceptionHandle;
use app\Request;

// 容器Provider定义文件
return [
    'think\Request'          => Request::class,
    'think\exception\Handle' => ExceptionHandle::class,
    // 上面是系统默认的
    // 下面是新添加的 注意 这里的app前面就不需要\了
    'one'                    => app\model\One::class
];

然后在控制器中,直接使用即可

public function bind()
    {
        return app('one')->username;
    }

系统内置了很多常用的类库,以便开发者快速调用,具体如下:

系统类库容器绑定标识
think\Appapp

think\Cache

cache

think\Config

config

think\Cookie

cookie

thinkConsole

console

think\Db

db

think\Debug

debug

think\Env

env

think\Event

event

think\Http

http

think\Lang

lang

thinkLog

log

think\Middleware

middleware

think\Request

request

think\Response

response

think\Filesystem

flesystem

think\Route

route

think\Session

session

tink\Validate

validate

thinklView

view
实现同一个效果可以由容器的bind()和app()实现,也可以使用依赖注入实现,还有Facade实现,以及助手函数实现

门面Facade

创建静态调用

Facade,即门面设计模式,为容器的类提供了一种静态的调用方式;比如请求Request::?,路由Route::?,数据库Db::?等等,均来自Facade;

手工来创建一个自己的静态调用类库,来了解一下流程

首先,在应用目录下创建app/common 公共类库文件夹,并创建Test.php;

namespace app\common;

class Test
{
    public function hello($name)
    {
        return "hello, {$name}";
    }
}

再在同一个目录下创建app/facade 文件夹,并创建Test.php,用于生成静态调用

namespace app\facade;
use think\Facade;

class Test extends Facade
{
    protected static function getFacadeClass()
    {
        return 'app\common\Test';
    }
}

如此就绑定好了,然后在控制器中试验一下:

public function test()
    {
        return \app\facade\Test::hello('world');
    }

如此即调用了app\facade目录下Test.php,然后将其实例化了。

即通过静态方法,实例化了类,然后实现静态调用类中的方法。

或者换一种写法

<?php
namespace app\controller;
use app\facade\Test;

class Url
{
    public function test()
    {
       // return \app\facade\Test::hello('world');
       return Test::hello('world');
    }
}

点赞 支持一下 觉得不错?客官您就稍微鼓励一下吧!
关键词:thinkphp
推荐阅读
  • uniapp实现被浏览器唤起的功能

    当用户打开h5链接时候,点击打开app若用户在已经安装过app的情况下直接打开app,若未安装过跳到应用市场下载安装这个功能在实现上主要分为两种场景,从普通浏览器唤醒以及从微信唤醒。

    9603次阅读 623人点赞 发布时间: 2022-12-14 16:34:53 立即查看
  • Vue

    盘点Vue2和Vue3的10种组件通信方式

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异;本文将通过选项式API组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式。

    4297次阅读 317人点赞 发布时间: 2022-08-19 09:40:16 立即查看
  • JS

    几个高级前端常用的API

    推荐4个前端开发中常用的高端API,分别是MutationObserver、IntersectionObserver、getComputedstyle、getBoundingClientRect、requ...

    14452次阅读 948人点赞 发布时间: 2021-11-11 09:39:54 立即查看
  • PHP

    【正则】一些常用的正则表达式总结

    在日常开发中,正则表达式是非常有用的,正则表达式在每个语言中都是可以使用的,他就跟JSON一样,是通用的。了解一些常用的正则表达式,能大大提高你的工作效率。

    13504次阅读 491人点赞 发布时间: 2021-10-09 15:58:58 立即查看
  • 【中文】免费可商用字体下载与考证

    65款免费、可商用、无任何限制中文字体打包下载,这些字体都是经过长期验证,经得住市场考验的,让您规避被无良厂商起诉的风险。

    12024次阅读 964人点赞 发布时间: 2021-07-05 15:28:45 立即查看
  • Vue

    Vue3开发一个v-loading的自定义指令

    在vue3中实现一个自定义的指令,有助于我们简化开发,简化复用,通过一个指令的调用即可实现一些可高度复用的交互。

    16384次阅读 1307人点赞 发布时间: 2021-07-02 15:58:35 立即查看
  • JS

    关于手机上滚动穿透问题的解决

    当页面出现浮层的时候,滑动浮层的内容,正常情况下预期应该是浮层下边的内容不会滚动;然而事实并非如此。在PC上使用css即可解决,但是在手机端,情况就变的比较复杂,就需要禁止触摸事件才可以。

    15187次阅读 1234人点赞 发布时间: 2021-05-31 09:25:50 立即查看
  • Vue

    Vue+html2canvas截图空白的问题

    在使用vue做信网单页专题时,有海报生成的功能,这里推荐2个插件:一个是html2canvas,构造好DOM然后转canvas进行截图;另外使用vue-canvas-poster(这个截止到2021年3月...

    29876次阅读 2349人点赞 发布时间: 2021-03-02 09:04:51 立即查看
  • Vue

    vue-router4过度动画无效解决方案

    在初次使用vue3+vue-router4时候,先后遇到了过度动画transition进入和退出分别无效的情况,搜遍百度没没找到合适解决方法,包括vue-route4有一些API都进行了变化,以前的一些操...

    25924次阅读 1995人点赞 发布时间: 2021-02-23 13:37:20 立即查看
交流 收藏 目录