框架实现简洁、功能强大、覆盖全面,正如她的名字:Shy——纤细身形、不漏内秀。
The framework is simple, powerful, and comprehensive, just like her name: Shy - slender figure, not leaking show.
#默认master分支,包含最新特性,可能不稳定
git clone https://github.com/lynnclub/shy.git MyProjectName
#获取指定的发行版本
git clone -b 1.4.0 https://github.com/lynnclub/shy.git MyProjectName
推荐使用稳定的 发行版本。
#进入项目目录
cd MyProjectName
#执行composer依赖包安装
composer install
恭喜!!!接下来,只需要配置Web站点,或者启动常驻内存模式,就可以运行框架了。
php command http_workerman start
分为大中小三级版本号,1.x版本兼容php>=7.0,2.x版本兼容php>=7.4。
完善session,注释翻译为中文,其它优化。
完善session,注释翻译为中文,其它优化。
框架内置了丰富的组件(Component),例如配置、日志、门面、缓存、流水线、进程管理等等。这些组件按照拼积木的方式灵活组合,形成了面向不同使用场景的 Web框架、CLI框架、Socket框架、API框架,并且可以多入口独立运行。
所有内置组件都抽象出了契约(Contract),拥有规范约束、可以自由替换。
容器(Container)作为其中最核心的组件,提供了操作便捷的实例(Instance)复用池。需要复用的实例,包括内置组件,都可以在容器中创建、获取、销毁或替换。
框架还提供了一种革新 PHP传统Web框架 的运行模式——常驻内存模式(PHP-CLI)。
在该模式下,由于避免了代码重复编译导致的性能开销,框架的Web服务性能得以大幅提升!!!
框架全力遵守 PHP-FIG组织 制定的PSR(PHP Standards Recommendations)系列规范,与遵守相同规范的框架互相兼容。
shy 框架根目录
|
| phpunit.php 单元测试入口
| command 命令模式入口
| server.php Http服务调试入口(仅供调试使用,不建议将整个项目目录暴露在web服务器下)
| gulpfile.js Gulp前端构建服务
|
|___app 开发目录
| |
| |___Command 命令服务开发目录
| |___Function 函数开发目录
| |___Http Http服务开发目录
| |___Socket Socket服务开发目录
|
|___bootstrap 服务启动目录
| |
| |___command.php 命令服务启动程序
| |___http.php Http服务启动程序
| |___http_workerman.php 基于workerman的常驻内存Http服务启动程序
|
|___cache 缓存目录
| |
| |___app 系统缓存目录
| |___log 日志目录
|
|___config 配置目录
| |
| |___ develop 开发环境配置目录
| |___ testing 测试环境配置目录
| |___ production 生产环境配置目录
|
|___public Http服务开放目录
| |
| | index.php Http服务入口
| |
| |___upload 上传文件目录
| |___vendor 前端第三方资源包目录
|
|___shy 框架目录
| |
| | Command.php 命令服务
| | Config.php 配置组件
| | Container.php 容器组件
| | Facade.php 门面组件
| | Hook.php 钩子组件
| | Pipeline.php 流水线组件
| | Process.php 进程组件
| | HttpInWorkerMan.php 基于workerman的常驻内存Http服务
| | SocketInWorkerMan.php 基于workerman的Socket服务
| |
| |___Cache 缓存目录
| |___Command 命令模式目录
| |___Contract 契约目录
| |___Exception 异常类目录
| |___Http Web服务目录
| |___Library 类库目录
| |___Socket Socket服务目录
|
|___tests 单元测试目录
|
|___vendor composer依赖包安装目录
契约是比接口(interface)更广义的概念,意义相似,但是不局限于接口的形式。契约可以是接口、抽象类,甚至是非硬性约束的惯例。
各种组件都按照契约的规范实现,比如容器、缓存、配置、日志、门面等,部分组件的契约还兼容PSR规范。
契约在容器中的使用方式:在容器中注册契约类名,绑定实现了该契约的实体类。遵守同一契约的实体类,可以在容器中替换。
bootstrap程序中,契约类与实体类的绑定:
$container->binds([
ConfigContract::class => Config::class,
LoggerContract::class => File::class,
ExceptionHandlerContract::class => Handler::class,
PipelineContract::class => Pipeline::class,
CacheContract::class => Memory::class,
DataBaseContract::class => Illuminate::class,
ResponseContract::class => Response::class,
SessionContract::class => Session::class,
RouterContract::class => Router::class,
ViewContract::class => View::class,
]);
框架的容器类,遵守PSR(PHP Standards Recommendations)中的《PSR-11: Container interface》接口规范。并且,实现了PHP的ArrayAccess、Countable接口,可以当作数组使用。
容器是对实例集中管理的实例池,可以创建、绑定、使用、替换或者移除实例。
此外,框架拓展了容器的概念,支持把字符、数组等任意内容当作实例管理。即容器是实例与数据的集中管理池。
注意事项:
支持绑定实例或者数据,绑定内容为闭包,将在 加入与获取实例 时执行该闭包。
/**
* 绑定类名
*/
bind(Shy\Http::class);
/**
* 直接绑定实例
*/
bind(Shy\Http::class, new Shy\Http());
bind('Shy\Http', new Shy\Http());
/**
* 绑定匿名函数(可用于延迟传参、即执行闭包时再传参,支持任意个参数)
*/
bind(Shy\Http::class, function ($param1, $param2) {
return new Shy\Http($param1, $param2);
});
/**
* 链式调用:绑定实例->加入容器然后获取实例->执行实例的run方法
*
* getOrMake方法等同于shy函数
*/
bind(Shy\Http::class, new Shy\Http())->getOrMake(Shy\Http::class)->run();
/**
* 链式调用:绑定匿名函数->带参执行,加入容器然后获取实例->执行实例的run方法
*/
bind(Shy\Http::class, function ($param1, $param2) {
return new Shy\Http($param1, $param2);
})->getOrMake(Shy\Http::class, $param1, $param2)->run();
如上所述,bind函数是对容器类的封装,会返回容器实例以便链式调用。
bind函数的功能只是绑定实例,并没有将实例加入到容器的实例池。将实例加入容器、获取容器中实例,是shy函数的功能。
/**
* 实例化Http类,并加入容器
*/
shy(Shy\Http::class);
/**
* 带参数实例化(未绑定)
*/
shy(Shy\Http::class, null, $param1, $param2);
/**
* 先绑定,再带参数实例化
*/
bind(Shy\Http::class);
shy(Shy\Http::class, $param1, $param2);
/**
* 带参数实例化File类,契约为Logger
*/
shy(Shy\Contract\Logger::class, Shy\Logger\File::class, $param1, $param2);
// 获取契约为Logger的File实例(需要已绑定或已加入容器)
shy(Shy\Contract\Logger::class);
/**
* 直接将实例加入容器
*/
shy(Shy\Http::class, new Shy\Http());
/**
* 设置类名的别名
*/
shy()->alias('config', Shy\Contract\Config::class);
// 使用别名获取实例
shy('config');
shy函数是框架的核心函数,代表对容器的操作。
使用shy函数时,如果容器内已经存在指定类名的实例,则直接返回该实例。如果不存在,会将实例加入到容器中,然后返回被加入的实例。
该函数会自动尝试上述所有用法模式来获取实例。比如,从绑定的实例中获取、执行绑定的匿名函数获取实例、或者通过反射实例化类。
实例加入容器之后,会清除绑定以免占用内存。
更多操作请直接使用容器类。通过使用shy函数、不传参数,可以获取到容器实例。
/**
* 无参数、返回容器本身
*/
shy();
/**
* 是否存在实例
*/
shy()->has(Shy\Http::class);
/**
* 创建实例、已存在实例会替换实例
*/
shy()->make(Shy\Http::class);
/**
* 移除实例
*/
shy()->remove(Shy\Http::class);
容器执行闭包、或者通过反射实例化类的时候,会自动注入构造方法的依赖,无需手动实例化。
use Shy\Http\Contract\Request;
use Shy\Contract\Config;
/**
* Logger constructor.
*
* @param Request $request
* @param Config $config
*/
public function __construct(Config $config, Request $request = null)
{
$this->config = $config;
$this->request = $request;
}
如上所述,Logger类的构造方法依赖Config和Request契约类参数。容器通过反射感知变量类型,可以自动注入契约绑定的实体类。
配置类继承了内存缓存类Shy\Cache\Memory::class
,无依赖。在app.cache开启时,配置会被持久化缓存到本地文件。
/**
* 读取配置文件app.php的配置
*/
$appConfig = config('app');
/**
* 读取配置文件app.php中的,cache配置
*/
$isCache = config('app.cache');
/**
* 读取配置文件workerman.php中的,socket配置
*/
$socketConfig = config('workerman.socket');
框架预设了三种环境,develop开发环境、testing测试环境、production生产环境。如果未设置环境值,默认为develop开发环境。
将优先使用环境目录下的配置文件,当环境目录下不存在该文件时,使用通用的配置文件。
Nginx fastcgi配置环境值:
fastcgi_param SHY_ENV 'testing';
Linux系统配置环境值:
// .bash_profile文件
export SHY_ENV=production
环境配置可以自由拓展,框架按照配置的环境值,读取config目录下的同名环境目录。
框架在各个服务的入口处,注册了异常(Exception)与错误(Error)捕获,能够捕获并处理所有未被捕获的异常、错误,甚至是Shut Down。
错误与Shut Down会被转化成异常,统一按异常处理。
框架为每个服务提供了异常处理类(Handler)。你也可以实现Handler接口来自定义异常处理,在启动器的服务入口中替换绑定关系,使其生效。
替换异常处理契约绑定的实体类:
// MyProjectName/bootstrap/http.php文件
$container->bind(Shy\Contract\ExceptionHandler::class, Shy\Http\Exception\Handler::class);
对于需要返回Http Code的错误,可以抛出HttpException。该错误的响应会输出errors/common.php
模版:
use Shy\Http\Exception\HttpException;
throw new HttpException(403, lang(5000));
门面提供了便捷的静态调用方式。实现门面类需要继承框架的门面抽象类,并且重写父类的getInstance()
方法,以便向父类传递实体类。实现代码示例如下:
namespace Shy\Facade;
use Shy\Facade;
use Shy\Contract\Cache as CacheContract;
class Cache extends Facade
{
/**
* 获取实例
* Get the instance.
*
* @return object
*/
protected static function getInstance()
{
return shy(CacheContract::class);
}
}
门面类的父类——门面抽象类,通过魔术方法__callStatic()
调用实体类中的方法。可参考 容器与依赖注入 章节,以便理解框架如何获取实体类的实例。
框架的缓存类,遵守PSR(PHP Standards Recommendations)中的《PSR-16: Common Interface for Caching Libraries》接口规范。
并且,实现了PHP的ArrayAccess接口,可以当作数组使用。由于phpredis拓展不完全兼容PSR-16,所以框架对缓存的PSR规范无硬性约束、仅建议遵守。
框架默认使用无依赖的 Memory 内存缓存,通过文件做持久化储存,每次GC最多回收10条。在常驻内存模式下,由于该缓存只在关闭、启动服务的时候执行文件持久化,所以性能开销较小。
框架还提供了基于phpredis拓展实现的Redis缓存,推荐有条件时优先使用。可以在bootstrap目录下的服务启动文件中,替换缓存契约绑定的实体类:
$container->bind(Shy\Contract\Cache::class, Shy\Cache\Redis::class);
调用缓存门面的方法:
use Shy\Facade\Cache;
Cache::set('test', 123);
Cache::get('test');
框架的日志类,遵守PSR(PHP Standards Recommendations)中的《PSR-3: Logger Interface》接口规范。
框架实现了本地文件日志Shy\Logger\File
,以及阿里云日志Shy\Logger\Aliyun
(阿里云日志类继承了本地文件日志类,使用的时候也会保存本地文件日志)。
如果不需要记录日志,日志契约可以更换绑定Psr\Log\NullLogger
类。
可以在bootstrap目录下的服务启动文件中,替换日志契约绑定的实体类:
$container->bind(Shy\Contract\Logger::class, Shy\Logger\Aliyun::class);
自定义日志需要实现Shy\Contract\Logger
接口,并且继承PSR的Psr\Log\AbstractLogger
。
流水线是一种连贯的流程调度工具,使用流水线执行的对象或函数,可以享受容器的依赖注入服务。流水线连通了包括中间件、控制器在内的运行流程。
Pipeline类的方法:
开发者可使用流水线来执行自己的调度,代码实例如下:
use Shy\Contract\Pipeline;
/**
* 执行一组中间件,带回调执行
*/
$response = shy(Pipeline::class)
->send(...$this->pathParam)
->through($this->middleware)
->then(function () {
return $this->runController();
});
/**
* 执行单个控制器,不带回调执行
*/
$response = shy(Pipeline::class)
->through($this->controller)
->via($this->method)
->run();
通过门面类使用:
// 引入门面类
use Shy\Http\Facade\Request;
// 是否初始化(常驻内存模式使用)
Request::initialized();
// 获取全部请求
Request::all();
// 获取数据流 php://input
Request::getContent();
// 获取GET请求参数
Request::get('key');
// 获取POST请求参数
Request::post('key');
通过契约的依赖注入使用:
// 引入契约类
use Shy\Http\Contract\Request;
// 控制器通过依赖注入使用实体类
public function test(Request $request)
{
return 'controller echo test ' . json_encode($request->all());
}
中间件是控制器请求与响应的中间步骤,是流水线(Pipeline)的一种特例。流水线传入的第一个参数$next
,是用于运行控制器的闭包。
中间件在控制器之前执行,称为“前置中间件”。如下,是有IP白名单功能的前置中间件:
namespace Shy\Http\Middleware;
use Closure;
use Shy\Contract\Middleware;
use Shy\Http\Facade\Request;
use Shy\Facade\Logger;
use Shy\Http\Exception\HttpException;
class IpWhitelist implements Middleware
{
/**
* Handle
*
* @param Closure $next
* @param array ...$passable
* @return mixed|string
*/
public function handle(Closure $next, ...$passable)
{
$hit = FALSE;
$whitelist = config('ip_whitelist');
if (is_array($whitelist)) {
$userIps = Request::getClientIps();
foreach ($userIps as $userIp) {
if (in_array($userIp, $whitelist)) {
$hit = TRUE;
}
}
}
if (!$hit) {
Logger::info('Ip whitelist block request', Request::all());
if (Request::expectsJson()) {
return get_response_json(5000);
} else {
throw new HttpException(403, lang(5000));
}
}
return $next();
}
}
use Shy\Contract\Middleware;
use Closure;
class Test implements Middleware
{
/**
* Handle
*
* @param Closure $next
* @param array ...$passable
* @return mixed|string
*/
public function handle(Closure $next, ...$passable)
{
// run controller
$response = $next();
// do something
$response = json_encode($response);
return $response;
}
}
中间件需要在配置文件middleware.php
中定义别名或者别名组,然后在路由中填写别名使用。
return [
'IpWhitelist' => Shy\Http\Middleware\IpWhitelist::class,
'Throttle' => Shy\Http\Middleware\Throttle::class,
'Example' => App\Http\Middleware\Example::class,
'GroupExample' => [
Shy\Http\Middleware\CSRF::class,
]
];
csrf_token()
使用;ip_whitelist.php
管理白名单;Throttle:10,5
。对于控制器,只需要return数据或者模版,Response组件会自动输出响应。建议不要手动输出,而是交给框架去处理响应。
/**
* 返回字符串
*/
return 'controller echo';
/**
* 返回内置模版
*/
return view('home', compact('title', 'info'))->layout('main');
/**
* 返回Smarty模版
*/
return smarty('smarty.tpl', $params);
路由通过请求(Request)组件获取到请求路径,然后解析出对应控制器及其方法,最终调度执行中间件与控制器。
路由支持”路径模式”和”配置模式”,可以在配置文件app.php
中关闭或启用。路径模式是直接把请求路径当成控制器及其方法,比较简单;配置模式根据请求路径查找路由配置,得到控制器及其方法,支持中间件、路径前缀、命令空间、指定域名的功能。
两种模式同时启用时,配置模式优先。推荐使用配置模式,以便使用中间件等功能。
配置模式的路由配置文件router.php
示例:
return [
'group' => [
['middleware' => ['Example', 'Throttle:10'], 'path' => [
'/echo/string/with/middleware' => 'test2@test2',
'/return/string/with/middleware' => 'test2@test3',
]],
['prefix' => 'test/prefix', 'middleware' => ['Throttle:10,5'], 'path' => [
'/home' => 'home@index',
'/return/string/with/get/param' => 'home@test',
]],
['prefix' => 'controller_2', 'namespace' => 'App\\Http\\Controller_2', 'path' => [
'/home' => 'home@index',
'/return/string/without/get/param' => 'home@test',
'/smarty' => 'home@smarty',
]],
['middleware' => ['GroupExample'], 'path' => [
'/test4' => 'test2@test2',//echo string with middleware
]],
['middleware' => ['Stop'], 'path' => [
'/middleware_stop/?' => 'test2@test2',//echo string with middleware
]],
['host' => 'www.test.com', 'middleware' => ['Throttle:10,5'], 'path' => [
'/home' => 'home@index',
'/return/string/with/get/param' => 'home@test',
]],
],
'path' => [
'/' => 'home@index',//view home
'/test/url/func' => 'home@test2',//return string
'test/path/param/?' => 'home@test3',
'/smarty' => 'home@smarty',
'/not/found' => 'home@home3',//404
'/test/error/500' => 'home@test4',//500
'/home/path/test' => 'home@index',//view home
'/testLang' => 'test2@testLang',//zh-CN
'/testLangUS' => 'test2@testLang2'//en-US
]
];
配置的功能点:
路由配置文件在debug关闭的时候(一般是生产环境),会自动缓存路由的索引,可能导致对路由的修改不生效,建议开启debug,或者手动删除路由缓存文件cache/app/router.cache
。
控制器方法中应该返回(return)数据、以便交由框架响应组件输出,不应该直接在控制器内输出。
在控制器内使用实例,建议通过门面,或者契约的依赖注入。
可以在bootstrap目录下的服务启动文件中,替换数据库契约绑定的实体类:
/**
* 默认使用Pdo
*/
$container->bind(Shy\Contract\DataBase::class, Shy\DataBase\Illuminate::class);
框架兼容laravel的DB包,你可以通过下面的命令安装此包:
composer require illuminate/database 5.8
在配置文件database.php
中配置数据库,然后在启动文件中替换DataBase实体类,便可使用了。
使用方式如下:
use Shy/Core/Facades/DB;
DB::table('users')->where('id', 2)->get();
Illuminate Database的更多用法,可以查看该项目的文档
框架自带模版没有采用字符解析这种复杂的设计,因为这种方式不仅实现复杂、还制定了一套模版规则需要用户学习。
框架的模版需要使用原生PHP语法开发,并且只提供了必须少量函数,学习成本较低。
但是,要求开发者做好isset()
、empty()
、is_array()
等预防报错处理。
此外,为了满足开发者的需求,框架支持了Smarty模版系统。
在控制器方法中使用view函数:
public function index()
{
$info = 'Hello World';
$title = 'Shy Framework';
return view('home', compact('title', 'info'))->layout('main');
return view('home', compact('title', 'info'), 'main');//等价方法
}
include_view函数用于在布局页中输出子模版,或者引入模版组件;param函数输出变量和常量:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<meta name="renderer" content="webkit">
<title><?php param('title') ?></title>
<link type="text/css" rel="stylesheet" href="<?php url() ?>css/app.css">
<?php push_resource('header-css') ?>
</head>
<body>
<?php include_view() ?>
<?php include_view('component/footer') ?>
<?php push_resource('footer-js') ?>
</body>
</html>
布局页的子页:
<?php
push_resource('footer-js', [url() . 'vendor/jquery/dist/jquery.js', ''], 'js');
?>
<div id="hello-world">
<?php param('info') ?>
<?php param('not_exist_param', true) ?>
</div>
<div id="system">
<p>Container Start Id: <?php echo shy()->startId(); ?></p>
<p>Memory Peak: <?php echo memory_get_peak_usage() / 1024; ?> kb</p>
<p>Running Time: <?php echo microtime(true) - shy()->startTime(); ?> second</p>
<?php
if (shy()->has('HTTP_LOOP_START_TIME')) { ?>
<p>Recycling Time: <?php echo microtime(true) - shy()->get('HTTP_LOOP_START_TIME'); ?> second</p>
<?php
}
?>
<br>
<p>Loaded instances memory used: </p>
<ul>
<?php
$instanceCount = 0;
foreach (shy()->memoryUsed() as $abstract => $instances) {
foreach ($instances as $key => $memoryUsed) {
$instanceCount++;
?>
<li><?php echo '[' . $instanceCount . '] ' . $abstract . '(' . ($key + 1) . ') ' . $memoryUsed / 1024 . ' kb'; ?></li>
<?php }
} ?>
</ul>
</div>
框架提供了对Smarty模版的支持,需要先安装Smarty包。
composer require smarty/smarty
return smarty('smarty.tpl', $params);
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"/>
<meta name="renderer" content="webkit">
<title>{$title}</title>
<link type="text/css" rel="stylesheet" href="{BASE_URL}css/app.css">
</head>
<body>
<div id="hello-world">
{$info}
</div>
<div id="system">
<p>Container Start Id: {$shy->startId()}</p>
<p>Memory Peak:{memory_get_peak_usage()/1024} kb</p>
<p>Running Time: {microtime(true) - $shy->startTime()} second</p>
{if $shy->has('HTTP_LOOP_START_TIME')}
<p>Recycling Time: {microtime(true) - $shy->get('HTTP_LOOP_START_TIME')} second</p>
{/if}
<br>
<p>Loaded instance's abstract: </p>
<ol>
{foreach $shy->memoryUsed() as $abstract => $instances}
{foreach $instances as $key => $memoryUsed}
<li>{$abstract}({$key + 1}) {$memoryUsed/1024} kb</li>
{/foreach}
{/foreach}
</ol>
</div>
{include file='component/footer.php'}
</body>
</html>
框架支持命令模式。在项目根目录执行下述命令可以查看所有命令:
php command list
如果你需要拓展命令,可以在app\Command目录下编写命令,并在配置文件command.php
中配置命令名称、对象和方法。
拓展命令的代码示例:
namespace App\Command;
class Example
{
public function test()
{
return 'Just for fun';
}
}
常驻内存模式是以PHP-CLI方式执行Web框架。
该模式相对与PHP传统的Web服务运行方式,做到了进程复用不销毁,避免了代码重复加载、重复编译导致的消耗,所以框架性能得到大幅度提升。
框架基于WorkerMan提供的socket服务,实现了通过命令模式运行的、常驻内存的Web服务框架。传统Web方式与常驻内存模式可以同时运行。
安装WorkerMan包:
composer require workerman/workerman
你可以在配置文件workerman.php
中,配置服务端口、工作进程数:
/*
| http in socket
*/
'http' => [
'port' => 2348,
'worker' => 2
],
由于常驻内存模式不依赖nginx、apache等服务器程序,框架本身可作为服务器,port端口可以直接占用80端口。
如果你希望框架配合nginx、apache等使用,也可以使用其它端口运行框架、然后配置服务器程序的端口代理。
nginx转发配置:
location / {
root /usr/share/nginx/shy/pulic;
if (!-e $request_filename) {
proxy_pass http://127.0.0.1:2348;
}
}
在项目根目录执行下面的命令即可管理服务:
/**
* 启动
*/
php command http_workerman start
/**
* 后台运行模式启动
*/
php command http_workerman start -d
/**
* 关闭|重启|平滑重启|查看状态|查看链接
*/
php command http_workerman stop|restart|reload|status|connections
PHP-CLI + Socket运行环境,相对于传统Web运行环境有根本差异,所以有很多需要注意的地方。
最需要注意的是,实例循环复用积累的运行状态。比如:某实例带着 上一个请求的状态 执行新的请求。在实例复用之前必须将实例恢复初始状态,否则难以保证不会出现复用混乱的情况。
框架各部分已经做好了初始化处理,但是框架无法顾及到开发者实现的业务逻辑部分。
开发者注意事项:
目前只是简单的复用框架实例,计划实现”基于使用历史统计的容器实例智能调度系统”。
系统会自动判断实例是否可复用、并且基于统计数据动态判断是否自动销毁实例或者预先载入实例。本功能可以简化开发者的操作,同时可以平衡内存与时间占用、提升运行效率。
框架封装了基于WorkerMan的Socket服务。你可以在配置文件workerman.php
中配置服务端口、工作进程数。支持配置多组服务,并且支持同时运行多组服务。
启动对应服务:
/**
* 启动
*/
php command workerman chat start
上述命令中,chat是服务名。更多操作请查看常驻内存模式章节。
框架可使用phpunit做单元测试。在tests文件夹中编写测试代码,在框架根目录执行下面的命令即可执行测试。
由于框架支持php7.0及以上版本,适配phpunit版本为phpunit 6.x。
安装phpunit 6.5:
wget https://phar.phpunit.de/phpunit-6.5.phar
php phpunit-6.5.phar --version
chmod +x phpunit-6.5.phar
mv phpunit-6.5.phar /usr/local/bin/phpunit
执行单元测试:
phpunit tests/containerTest
框架提供了一些常量可供使用: