首页 > 作文

ThinkPHP6 核心分析:系统服务

更新时间:2023-04-07 21:43:25 阅读: 评论:0

什么是系统服务?系统服务是对于程序要用到的类在使用前先进行类的标识的绑定,以便容器能够对其进行解析(通过服务类的register方法),还有就是初始化一些参数、注册路由等(不限于这些操作,主要是看一个类在使用之前的需要,进行一些配江阴学院置,使用的是服务类的boot方法)。以下面要介绍到的modelrvice为例,modelrvice类提供服务,modelrvice类主要对model类的一些成员变量进行初始化(在boot方法中),为后面model类的「出场」布置好「舞台」。

下面先来看看系统自带的服务,看看服务是怎么实现的。

内置服务

系统内置的服务有:modelrvicepaginatorrvicevalidatervice类,我们来看看它们是怎么被注册和初始化的。

app::initialize()有这么一段:

1 foreach ($this->initializers as $initializer) {2     $this->make($initializer)->init($this);3 }

这里通过循环app::initializers的值,并使用容器类的make方法获取每个$initializer的实例,然后调用实例对应的init方法。app::initializers成员变量的值为:

1 protected $initializers = [2     error::class,3     registerrvice::class,4     bootrvice::class,5 ];

这里重点关注后面两个:服务注册和服务初始化。

服务注册

执行$this->make($initializer)->init($this)$initializer等于registerrvice::class时,调用该类中的init方法,该方法代码如下:

 1 public function init(app $app) 2 { 3     // 加载扩展包的服务 4     $file = $app->getrootpath() . 'vendor/rvices.php'; 5  6     $rvices = $this->rvices; 7  8     //合并,得到所有需要注册的服务 9     if (is_file($file)) {10         $rvices = array_merge($rvices, include $file);11     }12     // 逐个注册服务13     foreach ($rvices as $rvice) {14         if (class_exists($rvice)) {15             $app->register($rvice);16         }17     }18 }

服务注册类中,定义了系统内置服务的值:

1 protected $rvices = [2     paginatorrvice::class,3     validatervice::class,4     modelrvice::class,5 ];

这三个服务和扩展包定义的服务将逐一被注册,其注册的方法register代码如下:

 1 public function register($rvice, bool $force = fal) 2 { 3     // 比如 think\rvice\paginatorrvice 4     // getrvice方法判断服务的实例是否存在于app::$rvices成员变量中 5     // 如果是则直接返回该实例 6     $registered = $this->getrvice($rvice); 7     // 如果服务已注册且不强制重新注册,直接返回服务实例 8     if ($registered && !$force) { 9         return $registered;10     }11     // 实例化该服务12     // 比如 think\rvice\paginatorrvice,13     // 该类没有构造函数,其父类rvice类有构造函数,需要传入一个app类的实例14     // 所以这里传入$this(app类的实例)进行实例化15     if (is_string($rvice)) {16         $rvice = new $rvice($this);17     }18     // 如果存在「register」方法,则调用之19     if (method_exists($rvice, 'register')) {20         $rvice->register()党课新闻稿;21     }22     // 如果存在「bind」属性,添加容器标识绑定23     if (property_exists($rvice, 'bind')) {24         $this->bind($rvice->bind);25     }26     // 保存服务实例27     $this->rvices[] = $rvice;28 }

详细分析见代码注释。如果服务类定义了register方法,在服务注册的时候会被执行,该方法通常是用于将服务绑定到容器;此外,也可以通过定义bind属性的值来将服务绑定到容器。

服务逐个注册之后,得到app::rvices的值大概是这样的:

每个服务的实例都包含一个app类的实例。

服务初始化

执行$this->make($initializer)->init($this)$initializer等于bootrvice::class时,调用该类中的init方法,该方法代码如下:

 1 public function init(app $app) 2 { 3     $app->boot(); 4 } 5 实际上是执行 app::boot(): 6  7 public function boot(): void 8 { 9     array_walk($this->rvices, function ($rvice) {10         $this->bootrvice($rvice);11     });12 }

这里是将每个服务实例传入 bootrvice 方法中。重点关注bootrvice方法:

1 public function bootrvice($rvice)2 {3     if (method_exists($rvice, 'boot')) {4         return $this->invoke([$rvice, 'boot']);5     }6 }

这里调用服务实例对应的boot方法。接下来,我们以modelrviceboot方法为例,看看boot方法大概可以做哪些工作。modelrviceboot方法代码如下:

 1 public function boot() 2 { 3     // 设置db对象 4     model::tdb($this->app->db); 5     // 设置event对象 6     mo祝福彩信del::tevent($this->app->event); 7     // 设置容器对象的依赖注入方法 8     model::tinvoker([$this->app, 'invoke']); 9     // 保存闭包到model::maker10     model::maker(function (model $model) {11         //保存db对象12         $db     = $this->app->db;13         //保存$config对象14         $config = $this->app->config;15         // 是否需要自动写入时间戳 如果设置为字符串 则表示时间字段的类型16         $isautowritetimestamp = $model->getautowritetimestamp();17 18         if (is_null($isautowritetimestamp)) {19             // 自动写入时间戳 (从配置文件获取)20             $model->isautowritetimestamp($config->get('databa.auto_timestamp', 'timestamp'));21         }22         // 时间字段显示格式23         $dateformat = $model->getdateformat();24 25         if (is_null($dateformat)) {26             // 设置时间戳格式 (从配置文件获取)27             $model->tdateformat($config->get('databa.datetime_format', 'y-m-d h:i:s'));28         }29 30     });31 }

可以看出,这里都是对model类的静态成员进行初始化。这些静态成员变量的访问属性为protected,所以,可以在model类的子类中使用这些值。

自定义系统服务

接着,我们自己动手来写一个简单的系统服务。

定义被服务的对象(类)

创建一个文件:app\common\myrvicedemo.php,写入代码如下:

 1 <?php 2 n淘宝不能正常显示amespace app\common; 3 class myrvicedemo 4 { 5     //定义一个静态成员变量 6     protected static $mystaticvar = '123'; 7     // 设置该变量的值 8     public static function tvar($value){ 9         lf::$mystaticvar = $value;10     }11     //用于显示该变量12     public function showvar()13     {14         var_dump(lf::$mystaticvar);15     }16 }

定义服务提供者

在项目根目录,命令行执行php think make:rvice myrvice,将会生成一个app\rvice\myrvice.php文件,在其中写入代码:

 1 <?php 2 namespace app\rvice; 3 u think\rvice; 4 u app\common\myrvicedemo; 5 class myrvice  extends rvice 6 { 7     // 系统服务注册的时候,执行register方法 8     public function register() 9     {10         // 将绑定标识到对应的类11         $this->app->bind('my_rvice', myrvicedemo::class);12     }13     // 系统服务注册之后,执行boot方法14     public function boot()15     {16         // 将被服务类的一个静态成员设置为另一个值17         myrvicedemo::tvar('456');18     }19 }

配置系统服务

app\rvice.php文件(如果没有该文件则创建之),写入:

1 <?php2     return [3         '\app\rvice\myrvice'4     ];

在控制器中调用
创建一个控制器文件app\controller\demo.php,写入代码:

 1 <?php 2 namespace app\controller; 3 u app\bacontroller; 4 u app\common\myrvicedemo; 5 class demo extends bacontroller 6 { 7     public function testrvice(myrvicedemo $demo){ 8         // 因为在服务提供类app\rvice\myrvice的boot方法中设置了$mystaticvar=‘456’\ 9         // 所以这里输出'456'10         夏季婚礼$demo->showvar();11     }12 13     public function testrvicedi(){14         // 因为在服务提供类的register方法已经绑定了类标识到被服务类的映射15         // 所以这里可以使用容器类的实例来访问该标识,从而获取被服务类的实例16         // 这里也输出‘456’17         $this->app->my_rvice->showvar();18     }19 }

执行原理和分析见代码注释。另外说说自定义的服务配置是怎么加载的:app::initialize()中调用了app::load()方法,该方法结尾有这么一段:

1 if (is_file($apppath . 'rvice.php')) {2     $rvices = include $apppath . 'rvice.php';3     foreach ($rvices as $rvice) {4         $this->register($rvice);5     }6 }

正是在这里将我们自定义的服务加载进来并且注册。

在 compor 扩展包中使用服务

这里以think-captcha扩展包为例,该扩展使用了系统服务,其中,服务提供者为think\captcha\captcharvice类,被服务的类为think\captcha\captcha

首先,项目根目录先运行compor require topthink/think-captcha安装扩展包;安装完成后,我们查看vendor\rvices.php文件,发现新增一行:

1 return array (2   0 => 'think\\captcha\\captcharvice',  //新增3 );

这是怎么做到的呢?这是因为在vendor\topthink\think-captcha\compor.json文件配置了:

 1 "extra": { 2     "think": { 3         "rvices": [ 4             "think\\captcha\\captcharvice" 5         ] 6     } 7 }, 8 而在项目根目录下的 compor.json,有这样的配置: 9 10 "scripts": {11     "post-autoload-dump": [12         "@php think rvice:discover",13         "@php think vendor:publish"14     ]15 }

扩展包安装后,会执行这里的脚本,其中,跟这里的添加系统服务配置相关的是:php think rvice:discover。该指令执行的代码在vendor\topthink\framework\src\think\console\command\rvicediscover.php,相关的代码如下:

 1 foreach ($packages as $package) { 2     if (!empty($package['extra']['think']['rvices'])) { 3         $rvices = array_merge($rvices, (array) $package['extra']['think']['rvices']); 4     } 5 } 6  7 $header = '// this file is automatically generated at:' . date('y-m-d h:i:s') . php_eol . 'declare (strict_types = 1);' . php_eol; 8  9 $content = '<?php ' . php_eol . $header . "return " . var_export($rvices, true) . ';';10 11 file_put_contents($this->app->getrootpath() . 'vendor/rvices.php', $content);

可以看出,扩展包如果有配置['extra']['think']['rvices'],也就是系统服务配置,都会被写入到vendor\rvices.php文件,最终,所有服务在系统初始化的时候被加载、注册和初始化。

分析完了扩展包中服务配置的实现和原理,接着我们看看captcharvice服务提供类做了哪些初始化工作。该类只有一个boot方法,其代码如下:

 1 public function boot(route $route) 2 { 3     // 配置路由 4     $route->get('captcha/[:config]', "\\think\\captcha\\captchacontroller@index"); 5     // 添加一个验证器 6     validate::maker(function ($validate) { 7         $validate->extend('captcha', function ($value) { 8             return captcha_check($value); 9         }, ':attribute错误!');10     });11 }

有了以上的先行配置,我们就可以愉快地使用captcha类了。

总结

使用系统服务有大大的好处和避免了直接修改类的坏处。从以上分析来看,个人觉得,使用系统服务,可以对一个类进行非入侵式的「配置」,如果哪天一个类的某些设定需要修改,我们不用直接修改这个类,只需要修改服务提供类就好了。对于扩展包来说,系统服务使其可以在扩展中灵活配置程序,达到开箱即用的效果。不过,有个缺点是系统服务类都要在程序初始化是进行实例化,如果一个系统的服务类很多,势必影响程序的性能。

本文发布于:2023-04-07 21:43:23,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/1948b0518b65567ba8a4625e6f7f4005.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:ThinkPHP6 核心分析:系统服务.doc

本文 PDF 下载地址:ThinkPHP6 核心分析:系统服务.pdf

标签:方法   实例   系统   初始化
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图