Swoft
: 首个基于 Swoole
原生协程的新时代 PHP
高性能协程全栈框架
首个基于 Swoole 原生协程的新时代 PHP 高性能协程全栈框架,内置协程网络服务器及常用的协程客户端, 常驻内存,不依赖传统的 PHP-FPM,全异步非阻塞 IO 实现,以类似于同步客户端的写法实现异步客户端的 使用,没有复杂的异步回调,没有繁琐的 yield, 有类似 Go 语言的协程、灵活的注解、强大的全局 依赖注入容器、完善的服务治理、灵活强大的 AOP、标准的 PSR 规范实现等等,可以用于构建高性能的Web系统 、API、中间件、基础服务等等。
特性
基于 Swoole
扩展
内置协程网络服务器
WebSocket
服务器
MVC
分层设计
高性能路由
强大的AOP
(面向切面编程)
灵活的注解功能
全局的依赖注入容器
基于 PSR-7
的 HTTP
消息实现
基于 PSR-11
的容器规范实现
基于 PSR-14
的事件管理器
基于 PSR-15
的中间件
基于 PSR-16
的缓存设计
可扩展的高性能 RPC
RESTful
支持
国际化(i18n
)支持
快速灵活的参数验证器
完善的服务治理,熔断、降级、负载、注册与发现
通用连接池 Mysql
、Redis
、RPC
数据库 ORM
协程、异步任务投递
自定义用户进程
协程和同步阻塞客户端无缝自动切换
别名机制
跨平台热更新自动 Reload
强大的日志系统
基础信息 环境要求 必须安装的
PHP > 7.0
, 推荐7.1+
Composer
Redis
的异步客户端 hiredis
连接迭代器依赖 pcre
库
Swoole
扩展, 版本>=2.1
PDO
扩展
有冲突的 下面列出一些已知的和swoole
有冲突的php
扩展,请使用swoft
时不要安装或禁用它们:
xdebug
xhprof
blackfire
zend
trace
uopz
推荐环境配置
可以查看 swoft 下 Dockerfile 文件
安装Swoft Composer安装 1 composer create-project swoft/swoft swoft
手动安装 1 2 3 4 5 git clone https: cd swoft composer install --no-dev cp .env.example .env vim .env
Docker安装 1 docker run -p 80 :80 swoft/swoft
Docker-Compose 安装 1 2 3 git clone https: cd swoft docker-compose up
开发准备
安装PHP7.1
, autoconf
, openssl
, redis
下载安装Hiredis
下载安装`Swoole
快速起步 服务启动与管理 帮助命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [root@caoxl swoft] ____ __ _ / ___|_ _____ / _| |_ \___ \ \ /\ / / _ \| |_| __| ___) \ V V / (_) | _| |_ |____/ \_/\_/ \___/|_| \__| Usage: php bin/swoft -h {command} [arguments] [options] Commands: app There are some help command for application[built-in] dev Some commands for application dev[built-in] entity The group command list of database entity gen Generate some common application template classes[built-in] rpc The group command list of rpc server server The group command list of HTTP-Server test Test command ws There are some commands for manage the webSocket server Options: -h, --help Display help information -v, --version Display version information
HTTP
服务器
是否同时启动RPC服务器取决于 .env
文件配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 php bin/swoft start php bin/swoft start -d php bin/swoft restart php bin/swoft reload php bin/swoft stop
WebSocket
服务器1 2 3 4 5 6 7 8 9 10 11 12 13 14 php bin/swoft ws:start php bin/swoft ws:start -d php bin/swoft ws:restart php bin/swoft ws:reload php bin/swoft ws:stop
RPC
服务器
使用独立的RPC服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 php bin/swoft rpc:start php bin/swoft rpc:start -d php bin/swoft rpc:restart php bin/swoft rpc:reload php bin/swoft rpc:stop
env
环境配置在执行 composer install
的时候程序会自动复制环境变量配置文件。 若没有,可手动复制项目根目录的 .env.example
并命名为 .env
可用配置项 下面是官方的 .env
文件支持的env配置项, 你也可以按需添加自己需要的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 TIME_ZONE=Asia/Shanghai LOG_ENABLE=false APP_DEBUG=false PFILE=/tmp/swoft.pid PNAME=php-swoft TCPABLE=true CRONABLE=false AUTO_RELOAD=true AUTO_REGISTER=false HTTP_HOST=0.0 .0.0 HTTP_PORT=80 HTTP_MODE=SWOOLE_PROCESS HTTP_TYPE=SWOOLE_SOCK_TCP WS_ENABLE_HTTP=true TCP_HOST=0.0 .0.0 TCP_PORT=8099 TCP_MODE=SWOOLE_PROCESS TCP_TYPE=SWOOLE_SOCK_TCP TCP_PACKAGE_MAX_LENGTH=2048 TCP_OPEN_EOF_CHECK=false CRONTAB_TASK_COUNT=1024 CRONTAB_TASK_QUEUE=2048 WORKER_NUM=1 MAX_REQUEST=100000 DAEMONIZE=0 DISPATCH_MODE=2 TASK_IPC_MODE=1 MESSAGE_QUEUE_KEY=1879052289 TASK_TMPDIR=/tmp/ LOG_FILE=@runtime/logs/swoole.log TASK_WORKER_NUM=1 PACKAGE_MAX_LENGTH=2048 OPEN_HTTP2_PROTOCOL=false SSL_CERT_FILE=/path/to/ssl_cert_file SSL_KEY_FILE=/path/to/ssl_key_file DB_NAME=dbMaster DB_URI=127.0 .0.1 :3306 /test?user=root&password=123456 &charset=utf8,127.0 .0.1 :3306 /test?user=root&password=123456 &charset=utf8 DB_MIN_ACTIVE=5 DB_MAX_ACTIVE=10 DB_MAX_WAIT=20 DB_MAX_WAIT_TIME=3 DB_MAX_IDLE_TIME=60 DB_TIMEOUT=2 DB_SLAVE_NAME=dbSlave DB_SLAVE_URI=127.0 .0.1 :3306 /test?user=root&password=123456 &charset=utf8,127.0 .0.1 :3306 /test?user=root&password=123456 &charset=utf8 DB_SLAVE_MIN_ACTIVE=5 DB_SLAVE_MAX_ACTIVE=10 DB_SLAVE_MAX_WAIT=20 DB_SLAVE_MAX_WAIT_TIME=3 DB_SLAVE_MAX_IDLE_TIME=60 DB_SLAVE_TIMEOUT=3 REDIS_NAME=redis REDIS_DB=2 REDIS_URI=127.0 .0.1 :6379 ,127.0 .0.1 :6379 REDIS_MIN_ACTIVE=5 REDIS_MAX_ACTIVE=10 REDIS_MAX_WAIT=20 REDIS_MAX_WAIT_TIME=3 REDIS_MAX_IDLE_TIME=60 REDIS_TIMEOUT=3 REDIS_SERIALIZE=1 REDIS_DEMO_REDIS_DB=6 REDIS_DEMO_REDIS_PREFIX=demo_redis_ USER_POOL_NAME=user USER_POOL_URI=127.0 .0.1 :8099 ,127.0 .0.1 :8099 USER_POOL_MIN_ACTIVE=5 USER_POOL_MAX_ACTIVE=10 USER_POOL_MAX_WAIT=20 USER_POOL_TIMEOUT=200 USER_POOL_MAX_WAIT_TIME=3 USER_POOL_MAX_IDLE_TIME=60 USER_POOL_USE_PROVIDER=false USER_POOL_BALANCER=random USER_POOL_PROVIDER=consul USER_BREAKER_FAIL_COUNT = 3 USER_BREAKER_SUCCESS_COUNT = 6 USER_BREAKER_DELAY_TIME = 5000 CONSUL_ADDRESS=http: CONSUL_PORT=8500 CONSUL_REGISTER_NAME=user CONSUL_REGISTER_ETO=false CONSUL_REGISTER_SERVICE_ADDRESS=127.0 .0.1 CONSUL_REGISTER_SERVICE_PORT=8099 CONSUL_REGISTER_CHECK_NAME=user CONSUL_REGISTER_CHECK_TCP=127.0 .0.1 :8099 CONSUL_REGISTER_CHECK_INTERVAL=10 CONSUL_REGISTER_CHECK_TIMEOUT=1
应用结构简介 一个完整的swoft应用可以包含:
HTTP服务(跟传统的框架差不多)
WebSocket服务
Rpc服务
swoft-cloud/swoft
即是一个完整应用的demo。当然,如果你只想使用一部分功能也是可以的
框架核心 生命周期 框架生命周期 Swoft
的一切都是建立在 Swoole
扩展之上运行的,想要了解整个生命周期就必须要了解 Swoole 的生命周期 ,此部分可查阅 Swoole 文档 获得更多的资料。
在 Swoft 服务启动阶段,我们主要关注 OnWorkerStart
事件,此事件会在 Worker
启动的时候触发,这个过程也是 Swoft
众多机制实现的关键,这时 Swoft
会
扫描目录
读取配置文件
收集注解信息
收集事件监听器
…
然后根据扫描到的注解信息执行对应的功能逻辑,并储存在与注解相对应的 Collector
容器内,包括但不限于注册路由信息,注册事件监听器,注册中间件,注册过滤器等等。
请求生命周期 每一个请求的开始到结束,都是由 Swoole
本身的 onRequest()
或 onReceive()
事件监听并委托给 Dispatcher
来处理并响应的,而 Dispatcher
的主要职责是负责调度请求生命周期内的各个参与者(组件)。
HTTP Server 在 HTTP Server
的情况下,将由 ServerDispatcher
来负责调度,参与者主要包括 RequestContext
, ExceptionHandler
, RequestHandler
。
RequestionContext(请求上下文)
: 作为当前的请求信息的容器将贯穿整个请求生命周期,负责信息的储存和传递;
ExceptionHandler(异常处理器)
: 则是在遇到异常的情况下出来收拾场面的,确保在各种异常情况下依旧能给客户端返回一个预期内的结果
RequestHandler(请求处理器)
: 则是整个请求生命周期的核心组件,其实也就是 Middleware(中间件)
,该组件实现了 PSR-15
协议
负责将 Request -> Router -> Controller -> Action -> Renderer -> Response
这整个请求流程贯穿起来,其实也就是从 Request
到 Response
的过程
只要在任意一个环节返回一个有效的 Response
对象便能对该请求做出响应并返回。
RPC Server 在 RPC Server
的情况下,由 ServiceDispatcher
来负责调度,与 HTTP Server
类似, 区别在于参与者只有 RequestContext
和 RequestHandler
,而 RequestHandler
内的 Middleware
也和 HTTP Server
的类似
比较明显的区别在于 RPC Server
下会有一个 ServicePacker(数据打包器)
来负责将服务方法或异常返回的数据打包成一个统一的数据格式 ,并返回给客户端。
配置 swoft
的配置与其他框架稍微有一些区别,有几份:
config/server.php
: swoft 服务器配置,主要是对swoole
的配置
config/beans/*
: swoft beans
配置,用于配置一些通过数组方式创建的bean
,关于bean的创建方式请查看相关章节。
config/properties/*
: 这里面就是通常的 应用配置 数据了
只会加载里面的 app.php
文件,其他文件都是在 app.php
内部 include
进来的
config/define.php
:定义了一些通用的常量和路径别名
1 2 3 4 5 ! defined ('DS' ) && define ('DS' , DIRECTORY_SEPARATOR); ! defined ('APP_NAME' ) && define ('APP_NAME' , 'swoft' ); ! defined ('BASE_PATH' ) && define ('BASE_PATH' , dirname (__DIR__ , 1 ));
配置的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $value = \config ('key' , 'default value' );$value = \config ('section.subkey' , 'default value' );$config = \Swoft ::getBean ('config' );$value = $config ->get ('key' , 'default value' );$value = $config ->get ('section.subkey' , 'default value' );$config ->set ('my-name' , 'tom' );echo $config ->get ('my-name' );
路径别名 路径别名 主要是配置了一些常用的路径,给他们取了一些别名以方便使用。
已有别名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $aliases = [ '@root' => BASE_PATH, '@env' => '@root' , '@app' => '@root/app' , '@res' => '@root/resources' , '@runtime' => '@root/runtime' , '@configs' => '@root/config' , '@resources' => '@root/resources' , '@beans' => '@configs/beans' , '@properties' => '@configs/properties' , '@console' => '@beans/console.php' , '@commands' => '@app/command' , '@vendor' => '@root/vendor' , ]; \Swoft\App ::setAliases ($aliases );
别名使用 1 2 3 4 5 6 7 $path = \alias ('@app' );$path = \alias ('@app/Controllers' );$path = \Swoft ::getAlias ('@app' );$path = \Swoft ::getAlias ('@app/Controllers' );
1 $aliaes = \Swoft ::getAliases ();
Bean容器 Swoft
中一个 Bean
就是一个类的一个对象实例。 容器就是一个巨大的工厂,用于存放和管理 Bean
生命周期。
注解 @Bean
命名空间:\Swoft\Bean\Annotation\Bean
name
定义Bean
别名,缺省默认类名
scope
注入Bean
类型,默认单例, Scope::SINGLETON/Scope::PROTOTYPE
(每次创建)
ref
指定引入Bean
,用于定义在接口上面,指定使用哪个接口实现.
@Inject
命名空间:\Swoft\Bean\Annotation\Inject
name
定义属性注入的bean
名称,缺省属性自动类型名称
定义Bean bean
有两种方式定义,注解和数组配置
数组定义 1 2 3 4 5 6 7 8 9 10 $beanConfig = [ 'class' => MyBean ::class , 'pro1' => 'v1' , 'pro2' => 'v2' , [ 'arg1' , '${beanName}' ] ];
数组中必须要有class
字段定义
pro1/pro1
和类面的成员变量名称是一一对应的
属性值和构造函数参数值,都可以通过 ${xxx}
和 ${config.xx}
, 注入Bean
和引用properties
配置信息
注解定义 注解定义使用PHP文档注解,在类上做一些标记,通过解析类注解,实现不同的功能。
操作Bean 1 2 3 4 App ::getBean ("name" );ApplicationContext ::getBean ('name' );BeanFactory ::getBean ('name' );BeanFactory ::hasBean ("name" );
App/AppplicaionContext/BeanFactory
都可从容器中得到Bean
hasBean
某个bean
是否存在
实例 别名定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class UserData { public function getData ( ) { return []; } } class UserLogic { private $userData ; private function getUser ( ) { return $this ->userData->getData (); } }
缺省定义 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class UserData { public function getData ( ) { return []; } } class UserLogic { private $userData ; private function getUser ( ) { return $this ->userData->getData (); } }
接口引用
接口上面指定了使用的实现bean
别名
接口使用处,无需指定使用那个别名,会根据接口上面的引用注入不同的实例bean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 interface UserInterface { public function getData ( ) ; } class UserBoy implements \UserInterface { public function getData ( ) { return 'boy' ; } } class UserGirl implements \UserInterface { public function getData ( ) { return 'girl' ; } } class UserLogic { private $userData ; private function getUser ( ) { return $this ->userData->getData (); } }
组件 swoft 应用由一个个组件构成,核心为 swoft-framework
组件。
组件注册 内部组件 app/
目录和 vendor/swoft
会被自动的扫描,收集注解信息。
自定义组件 在配置文件 config/properties/app.php
添加如下配置
1 2 3 4 5 6 'components' => [ 'custom' => [ 'Package\\Namespace' , ], ],
之后,swoft
启动时就会到对应的包里去扫描,收集信息
事件管理 在swoft
我们将事件分为三大类:
swoole server
的回调事件
swoft server
的事件,基于swoole
的回调处理,扩展了一些可用事件以增强自定义性
应用内的自定义事件管理和使用, 也是我们通常了解和使用的事件管理了
swoole
和server
级别的事件监听器,应当放置在boot
阶段。(即通常应放置于 App\Boot
空间下)
Swoole Server
事件
TAG: @SwooleListener("event name")
用注解tag @SwooleListener("event name")
来注册swoole
的回调事件监听, 支持所有swoole
官网列出来的事件回调名 具体请查看 SwooleEvent::class
以及 swoole
官网。
请谨慎使用 @SwooleListener
。 它是直接注册到 swoole server
上的(监听相同事件将会被覆盖 ),操作不当可能导致出现问题。
Swoft Server
事件
TAG: @ServerListener("event name")
用注解tag @ServerListener("event name")
来注册服务器级别的事件监听。
它是对 @SwooleListener
的补充扩展,除了支持 swoole
的事件以外,还增加了一些额外的可用事件监听。
两者的区别是:
SwooleListener
中一个事件的监听器只允许一个,并且是直接注册到 swoole server
上的(监听相同事件将会被覆盖 )
ServerListener
允许对swoole
事件添加多个监听器, 会逐个通知
ServerListener
不影响基础swoole
事件的监听
Examples 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php namespace App \Boot \Listener ;use Swoft \Bootstrap \Listeners \Interfaces \StartInterface ;use Swoft \Bean \Annotation \ServerListener ;use Swoft \Bootstrap \SwooleEvent ;use Swoole \Server ;class MyServerListener implements StartInterface { public function onStart (Server $server ) { \output ()->writeln ('TestStartListener' ); var_dump ('TestStartListener' ); } }
自定义事件 基本的事件注册与触发管理
implement the Psr 14 - Event dispatcher
支持设置事件优先级
支持快速的事件组注册
支持通配符事件的监听
作为核心服务组件,事件管理会自动启用
1 2 3 'eventManager' => [ 'class' => \Swoft\Event\EventManager ::class , ],
注册事件监听 用注解tag @Listener("event name")
来注册用户自定义的事件监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class ApplicationLoaderListener implements EventHandlerInterface { public function handle (EventInterface $event ) { } }
事件名称管理推荐放置在一个单独类的常量里面,方便管理和维护
1 2 \Swoft ::trigger ('event name' , null , $arg0 , $arg1 );
连接池 基础属性
name
连接池节点名称,用于服务发现
uri
连接地址信息
maxActive
最大活跃连接
maxWait
最大等待连接
minActive
最小活跃链接数
maxIdleTime
连接最大空闲时间,单位秒
maxWaitTime
连接最大等待时间,单位秒
timeout
超时时间,单位秒
具体使用
AOP切面编程
AOP 为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
AOP用途 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高开发的效率
组成部分 AOP 由 切面
、通知
、连接点
、切入点
,四部分组成。
切面 (Aspect) 其实就是共有功能的实现。如日志切面、权限切面、事务切面等。在实际应用中通常是一个存放共有功能实现的普通PHP类(切面类 ),之所以能被AOP容器识别成切面,是在配置中指定的。
通知 (Advice) 是切面的具体实现。以 目标方法
(要被代理的方法)为参照点,根据放置的地方不同, 可分为前置通知(Before)
、后置通知(AfterReturning)
、异常通知(AfterThrowing)
、最终通知(After)
与环绕通知(Around)
5种。 在实际应用中通常是指向切面类中的一个方法,具体属于哪类通知,同样是在配置中指定的。
连接点 (Joinpoint) 就是程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出或字段修改等,但Swoft只支持方法级的连接点。
切入点 (Pointcut) 用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。
注解Tag 定义切面类 @Aspect() 定义一个类为切面类
@PointBean() 定义bean
切入点 - 这个bean
类里的方法执行都会经过此切面类的代理
include
定义需要切入的实体名称集合
exclude
定义需要排除的实体名称集合
@PointAnnotation() 定义注解切入点 - 所有包含使用了对应注解的方法都会经过此切面类的代理
include
定义需要切入的注解名称集合
exclude
定义需要排除的注解集合
@PointExecution() 定义匹配切入点 - 指明要代理目标类的哪些方法
include
定义需要切入的匹配集合, 匹配的类方法,支持正则表达式
exclude
定义需要排序的匹配集合, 匹配的类方法,支持正则表达式
定义通知点 上面的几个tag,标明了切面类的作用范围。下面的几个tag则是进一步限制(或者说标记)要在那些点上进行切入
@Before()
标记方法为前置通知 - 在目标方法执行前先执行此方法
@After()
标记方法为后置通知 - 在目标方法执行后执行此方法
@AfterReturning()
标记方法为最终返回通知
@AfterThrowing()
标记方法为异常通知 - 在目标方法执行抛出异常时执行此方法
@Around()
标记方法为环绕通知 - 在目标方法执行前、后都执行此方法
如上所述,@Before()
@After()
就跟我们平常使用的 beforeAction
afterAction
功能类似。 :)
说明
定义切面后,框架会自动在对应的切入点,查询方法
@PointBean
、@PointAnnotation
、@PointExecution
三种定义的关系是并集 ,三种里面定义的排除也是并集后在排除
提示: 为了便于理解和使用,一个切面类尽量只使用上面三个中的一个。
使用实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 class AllPointAspect { public function before ( ) { var_dump (' before1 ' ); } public function after ( ) { var_dump (' after1 ' ); } public function afterReturn (JoinPoint $joinPoint ) { $result = $joinPoint ->getReturn (); return $result .' afterReturn1 ' ; } public function around (ProceedingJoinPoint $proceedingJoinPoint ) { $this ->test .= ' around-before1 ' ; $result = $proceedingJoinPoint ->proceed (); $this ->test .= ' around-after1 ' ; return $result .$this ->test; } public function afterThrowing ( ) { echo "aop=1 afterThrowing !\n" ; } }
AOP实现原理 AOP 框架底层是通过动态代理模式实现。代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。
静态代理: 由程序员创建代理类或特定工具自动生成源代码再对其编译
动态代理: 在程序运行时运用反射机制动态创建而成。
动态代理 Swoft
动态代理定义,继承Swoft\Proxy\Handler\HandlerInterface
接口,实现invoke
方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class TestHandler implements HandlerInterface { private $target ; public function __construct ($target ) { $this ->target = $target ; } public function invoke ($method , $parameters ) { $before = 'before' ; $result = $this ->target->$method (...$parameters ); $after = 'after' ; $result .= $before .$after ; return $result ; } }
使用 1 2 3 4 5 $object = new ProxyTest (1 , 2 );$handler = new TestHandler ($object );$proxy = Proxy ::newProxyInstance (ProxyTest ::class , $handler );
异常处理 1. 编写的代码 首先我们在 app
目录下创建一个 Exception
目录,建立一个异常捕获的处理控制器 SwoftExceptionHandler
用到的注解:@ExceptionHandler()
class注解,声明当前类是异常处理类 @Handler()
method注解,需要捕获的异常类; 例如Exception::class
为php自带或者自己定义的异常处理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class SwoftExceptionHandler { public function handlerException (Response $response , \Throwable $throwable ) { $file = $throwable ->getFile (); $line = $throwable ->getLine (); $code = $throwable ->getCode (); $exception = $throwable ->getMessage (); $data = ['msg' => $exception , 'file' => $file , 'line' => $line , 'code' => $code ]; App ::error (json_encode ($data )); return $response ->json ($data ); } }
2.配置能被Swoft扫描到 在config/properties/app.php
中 的beanScan
中增加App\Exception
, 配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 return [ 'version' => '1.0' , 'autoInitBean' => true , 'bootScan' => [ 'App\Commands' , ], 'beanScan' => [ 'App\Controllers' , 'App\Models' , 'App\Middlewares' , 'App\Exception' , ], 'env' => 'Base' , 'db' => require __DIR__ . DS . 'db.php' , 'cache' => require __DIR__ . DS . 'cache.php' , ];
修改完成后,重新启动swoft
即可。
组件列表 认证管理 权限控制 现在支持:
BasicAuth
BearerToken(JWT)
ACL
安装 1 composer require swoft/auth
使用 本组件目前实现了 BasicAuth
和 BearerToken
的验证,以及简单的 ACL
,使用方法简单, 在 config/beans/base.php
中的 serverDispatcher.middlewares
里 添加 \Swoft\Auth\Middleware\AuthMiddleware::class
中间件,如下
1 2 3 4 5 'serverDispatcher' => [ 'middlewares' => [ \Swoft\Auth\Middleware\AuthMiddleware ::class , ] ],
然后在配置文件 config/properties/app.php
中添加
1 2 3 4 5 6 'auth' => [ 'jwt' => [ 'algorithm' => 'HS256' , 'secret' => '1231231' ], ],
注意 secret
不要使用上述值,修改为你自己的值
配置验证管理 AuthManagerInterface
AuthManager
是登录验证的核心,本类实现了 Token
的验证及缓存,你可以继承这个类实现多种方式登录(配合accountType
实现),下面就是一个 basicAuth
的 Demo
首先实现一个 Swoft\Auth\Mapping\AccountTypeInterface
作为我们登录的通道
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 use Swoft \Auth \Mapping \AccountTypeInterface ;use Swoft \Auth \Bean \AuthResult ;class AdminNormalAccount implements AccountTypeInterface { protected $dao ; const ROLE = 'role' ; public function login (array $data ) : AuthResult { $identity = $data ['identity' ]; $credential = $data ['credential' ]; $user = $this ->dao::findOneByUsername ($identity ); $result = new AuthResult (); if ($user instanceof AdminUserBean && $user ->verify ($credential )){ $result ->setExtendedData ([self ::ROLE => $user ->getIsAdministrator ()]); $result ->setIdentity ($user ->getId ()); } return $result ; } public function authenticate (string $identity ) : bool { return $this ->dao::issetUserById ($identity ); } }
然后在我们自己的 AuthManagerService
实现这个登录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 se Swoft\Auth\AuthManager; use Swoft \Auth \Mapping \AuthManagerInterface ;use Swoft \Auth \Bean \AuthSession ;class AuthManagerService extends AuthManager implements AuthManagerInterface { protected $cacheClass = Redis ::class ; protected $cacheEnable = true ; public function adminBasicLogin (string $identity , string $credential ) : AuthSession { return $this ->login (AdminNormalAccount ::class , [ 'identity' => $identity , 'credential' => $credential ]); } }
然后在 config/beans/base.php
中把系统默认的 AuthManager Bean
替换为我们自己的 AuthManagerService
,添加如下代码进行替换
1 2 3 \Swoft\Auth\Mapping\AuthManagerInterface ::class => [ 'class' =>App\Domain\User\Service\AuthManagerService ::class ],
现在我们就可以在一个 Controller
中使用刚才实现的登录方式了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 use Swoft \Auth \Constants \AuthConstants ;use Swoft \Http \Message \Server \Request ;use Swoft \Http \Server \Bean \Annotation \Controller ;use Swoft \Http \Server \Bean \Annotation \RequestMapping ;use Swoft \Http \Server \Bean \Annotation \RequestMethod ;use Swoft \Auth \Mapping \AuthManagerInterface ;class AuthorizationsResource { public function oauth (Request $request ) : array { $identity = $request ->getAttribute (AuthConstants ::BASIC_USER_NAME ) ?? '' ; $credential = $request ->getAttribute (AuthConstants ::BASIC_PASSWORD ) ?? '' ; if (!$identity || !$credential ){ return [ "code" => 400 , "message" => "Identity and Credential are required." ]; } $manager = App ::getBean (AuthManagerInterface ::class ); $session = $manager ->adminBasicLogin ($identity , $credential ); $data = [ 'token' => $session ->getToken (), 'expire' => $session ->getExpirationTime () ]; return $data ; } }
现在可以通过 Postman 或 其它请求方式 请求我们的登录接口了
// 待续…
命令行 HTTP服务 WebSocket服务 RPC服务 缓存 数据库 视图 Session会话 RPC客户端 HTTP客户端 任务 进程 国际化 日志 内存操作 服务治理 开发者工具