PHP code example of bingcool / swoolefy
1. Go to this page and download the library: Download bingcool/swoolefy library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
bingcool / swoolefy example snippets 8.1+,swoole > 5.1.x, 推荐 swoole-6.x.x+ 以上最新版本
7.3 ~ php7.4, swoole-4.8.x, 推荐直接swoole-v4.8.13
7.3 ~ php7.4
// 独立物理机或者云主机配置系统环境变量
vi /etc/profile
在/etc/profile末尾添加一行,标识环境变量,下面是支持的4个环境,框架将通过这个环境变量区分环境,加载不同的配置
export SWOOLEFY_CLI_ENV='dev' // 开发环境
export SWOOLEFY_CLI_ENV='test' // 测试环境
export SWOOLEFY_CLI_ENV='gra' // 灰度环境
export SWOOLEFY_CLI_ENV='prd' // 生产环境
// 最后是配置生效
source /etc/profile
// 在myproject目录下添加cli.php, 这个是启动项目的入口文件
pName);
// 启动目录
defined('START_DIR_ROOT') or define('START_DIR_ROOT', __DIR__);
// 应用父目录
defined('ROOT_PATH') or define('ROOT_PATH',__DIR__);
// 应用目录
defined('APP_PATH') or define('APP_PATH',__DIR__.'/'.$appName);
registerNamespace(APP_PATH);
define('IS_WORKER_SERVICE', 0);
define('IS_DAEMON_SERVICE', 0);
define('IS_SCRIPT_SERVICE', 0);
define('IS_CRON_SERVICE', 0);
define('PHP_BIN_FILE','/usr/bin/php');
define('WORKER_START_SCRIPT_FILE', str_contains($_SERVER['SCRIPT_FILENAME'], $_SERVER['PWD']) ? $_SERVER['SCRIPT_FILENAME'] : $_SERVER['PWD'].'/'.$_SERVER['SCRIPT_FILENAME']);
define('WORKER_SERVICE_NAME', makeServerName($appName));
define('WORKER_PID_FILE_ROOT', '/tmp/workerfy/log/'.WORKER_SERVICE_NAME);
define('SERVER_START_LOG', WORKER_PID_FILE_ROOT.'/start.log');
date_default_timezone_set('Asia/Shanghai');
// 你的项目命名为App,对应协议为http协议服务器,支持多个项目的,只需要在这里添加好项目名称与对应的协议即可
define('APP_META_ARR', [
'Test' => [
'protocol' => 'http',
'worker_port' => 9501,
],
'App' => [
'protocol' => 'http',
'worker_port' => 9502,
]
]);
// 启动前处理,比如加载.env
//$beforeFunc = function () {
// try {
// \Test\LoadEnv::load('192.168.1.101:8848','swoolefy','test','nacos-test','123456');
// }catch (\Throwable $exception) {
//
// }
//};
// 终端启动 ctl+c 停止进程
php cli.php start App
或者
swoole-cli cli.php start App
// 守护进程方式启动,添加-D参数控制
php cli.php start App --daemon=1
或者
swooole-cli cli.php start App --daemon=1
// 停止进程
php cli.php stop App
或者
swooole-cli cli.php stop App --force=1
// 查看进程状态
swooole-cli cli.php status App
// 完全重启服务
php cli.php restart App
或者
swooole-cli cli.php restart App
// 创建生成Cron定时计划任务服务,默认生成WorkerCron目录
php script.php start App --c=gen:cron:service
// 启动Cron服务, CTRL+C 停止进程
php cron.php start App
// --daemon=1 以守护进程启动
php cron.php start App --daemon=1
// 重启Cron服务
php cron.php restart App
// 停止Cron服务,终端交互询问需要输入`yes` or `no` 再次确认是否需要停止服务
php cron.php stop App
// --force=1 强制停止Cron服务,不询问直接停止服务
php cron.php stop App --force=1
// 创建生成Daemon常驻进程消费服务,默认生成WorkerDaemon目录
php script.php start App --c=gen:daemon:service
// 启动Daemon服务,CTRL+C 停止进程
php daemon.php start App
// --daemon=1 以守护进程启动
php daemon.php start App --daemon=1
// 重启Daemon服务
php daemon.php restart App
// 停止Daemon服务, 终端交互询问是否需要输入`yes` or `no` 再次确认是否需要停止服务
php daemon.php stop App
// --force=1 强制停止Daemon服务,不询问直接停止服务
php daemon.php stop App --force=1
namespace App\Controller;
use Swoolefy\Core\Application;
use Swoolefy\Core\Controller\BController;
// 默认生成的IndexController
class IndexController extends BController {
public function index() {
// 最简单的协程单例,goApp()即可创建一个协程,在单例中的db,redis等其他注册的组件都是单例的,不同协程单例相互隔离
goApp(function() {
var_dump('this is a coroutine single app test');
});
Application::getApp()->response->write('<h1>Hello, Welcome to Swoolefy Framework! <h1>');
}
}
return [
// db|redis连接池
'component_pools' => [
// 取components的`DB`组件名称相对应
'db' => [
'max_pool_num' => 5, // db实例数
'max_push_timeout' => 2, // db实例进入channel池最长等待时间,单位s
'max_pop_timeout' => 1, // db实例出channel池最长等待时间,单位s.在规定时间内获取不到db对象,将降级为实时创建db实例
'max_life_timeout' => 10, // db实例的有效期,单位s.过期后将被掉弃,重新创建新DB实例
'enable_tick_clear_pool' => 0 // 是否每分钟定时清空pool,防止长时间一直占用链接,max_pool_num设置很大的时候需要设置,否则不需要设置
],
// 取components的`redis`组件名称相对应
'redis' => [
'max_pool_num' => 5,
'max_push_timeout' => 2,
'max_pop_timeout' => 1,
'max_life_timeout' => 10,
'enable_tick_clear_pool' => 0 // 是否每分钟定时清空pool,防止长时间一直占用链接,max_pool_num设置很大的时候需要设置,否则不需要设置
]
],
// default_db
'default_db' => 'db',
// 加载组件配置
'components' => \Swoolefy\Core\SystemEnv::loadComponent()
// 其他配置
......
]
$dc = \Swoolefy\Core\SystemEnv::loadDcEnv();
return [
// 用户行为记录的日志
'log' => function($name) {
$logger = new Log($name);
$logger->setChannel('application');
if(SystemEnv::isDaemonService()) {
$logFilePath = LOG_PATH.'/daemon/info.log';
}else if (SystemEnv::isScriptService()) {
$logFilePath = LOG_PATH.'/script/info.log';
}else if (SystemEnv::isCronService()) {
$logFilePath = LOG_PATH.'/cron/info.log';
} else {
$logFilePath = LOG_PATH.'/cli/info.log';
}
$logger->setLogFilePath($logFilePath);
return $logger;
},
// 用户行为记录错误日志
'error_log' => function($name) {
$logger = new Log($name);
$logger->setChannel('application');
if(SystemEnv::isDaemonService()) {
$logFilePath = LOG_PATH.'/daemon/error.log';
}else if (SystemEnv::isScriptService()) {
$logFilePath = LOG_PATH.'/script/error.log';
}else if (SystemEnv::isCronService()) {
$logFilePath = LOG_PATH.'/cron/error.log';
} else {
$logFilePath = LOG_PATH.'/cli/error.log';
}
$logger->setLogFilePath($logFilePath);
return $logger;
},
// 系统捕捉抛出异常错误日志
'system_error_log' => function($name) {
$logger = new \Swoolefy\Util\Log($name);
$logger->setChannel('application');
if(SystemEnv::isDaemonService()) {
$logFilePath = LOG_PATH.'/daemon/system_error.log';
}else if (SystemEnv::isScriptService()) {
$logFilePath = LOG_PATH.'/script/system_error.log';
}else if (SystemEnv::isCronService()) {
$logFilePath = LOG_PATH.'/cron/system_error.log';
} else {
$logFilePath = LOG_PATH.'/cli/system_error.log';
}
$logger->setLogFilePath($logFilePath);
return $logger;
}
// Redis Cache
'redis' => function() use($dc) {
$redis = new \Common\Library\Redis\Redis();
$redis->connect($dc['redis']['host'], $dc['redis']['port']);
return $redis;
},
// Predis Cache
'predis' => function() use($dc) {
$predis = new \Common\Library\Redis\predis([
'scheme' => $dc['predis']['scheme'],
'host' => $dc['predis']['host'],
'port' => $dc['predis']['port'],
]);
return $predis;
}
use Swoolefy\Core\Application;
class TestController extends BController {
/**
* 控制器
*/
public function test() {
// 获取组件,组件就是配置回调中定义的组件
$redis = Application::getApp()->redis;
//或者通过get指明组件名获取(推荐)
// $redis = Application::getApp()->get('redis');
// swoole hook 特性,这个过程会发生协程调度
$redis->set('name', swoolefy);
// predis组件
$predis = Application::getApp()->predis;
//或者通过get指明组件名获取(推荐)
// $predis = Application::getApp()->get('predis');
// 这个过程会发生协程调度
$predis->set('predis','this is a predis instance');
$predis->get('predis');
// PDO的mysql实例,这个过程会发生协程调度
$db = Application::getApp()->db;
// 或者
// $mysql = Application::getApp()->get('db');
// 添加一条数据
$sql = "INSERT INTO `user` (`username` ,`sex`) VALUES (:username, :sex)";
$numRows = $db->createCommand($sql)->insert([
':username'=>'bingcool-test',
':sex' => 1
]);
var_dump($numRows)
// DB Query查询
$db = Application::getApp()->db;
$db->newQuery()->table('user')->where([
'user_id' => 10000
])->select()
// DB 插入单条数据
$data = [
'username'=>'bingcool-test',
'sex' => 1
]
$db = Application::getApp()->db;
$db->newQuery()->table('user')->insert($data);
// DB 插入多条数据
$data =
[
[
'username'=>'bingcool-test1111',
'sex' => 1
],
[
'username'=>'bingcool-test2222',
'sex' => 1
]
]
$db = Application::getApp()->db;
$db->newQuery()->table('user')->insertAll($data);
// 查询
$result = $db->createCommand('select * from user where id>:id')->queryOne([':id'=>100]);
var_dump($result);
// pg实例
$pg = Application::getApp()->get('pg');
// 添加一条数据
$sql = "INSERT INTO `user` (username ,sex) VALUES (:username, :sex)";
$pg->createCommand($sql)->insert([
':username'=>'bingcool-test',
':sex' => 1
]);
}
}
use Swoolefy\Http\Route;
use Swoolefy\Http\RequestInput;
// 直接路由-不分组
Route::get('/index/index', [
'beforeHandle' => function(RequestInput $requestInput) {
Context::set('name', 'bingcool');
$name = $requestInput->getPostParams('name');
},
// 这里需要替换长对应的控制器命名空间
'dispatch_route' => [\Test\Controller\IndexController::class, 'index'],
'afterHandle' => function(RequestInput $requestInput) {
},
'afterHandle1' => function(RequestInput $requestInput) {
},
]);
// 分组路由
Route::group([
// 路由前缀
'prefix' => 'api',
// 路由中间件,多个按顺序执行
'middleware' => [
\Test\Middleware\Route\ValidLoginMiddleware::class,
]
], function () {
Route::get('/', [
// 前置路由,闭包函数形式
'beforeHandle' => function(RequestInput $requestInput) {
var_dump('beforeHandle');
},
// 前置路由,中间件类形式(推荐)
'beforeHandle2' => \Test\Middleware\Route\ValidLoginMiddleware::class,
// 前置路由,中间件数组类形式(推荐)
'beforeHandle3' => [
\Test\Middleware\Route\ValidLoginMiddleware::class,
\Test\Middleware\Route\ValidLoginMiddleware::class,
],
// 控制器action
'dispatch_route' => [\Test\Controller\IndexController::class, 'index'],
// 后置路由
'afterHandle1' => function(RequestInput $requestInput) {
var_dump('afterHandle');
},
// 前置路由,中间件类形式(推荐)
'afterHandle2' => \Test\Middleware\Route\ValidLoginMiddleware::class,
// 前置路由,中间件数组类形式(推荐)
'afterHandle3' => [
\Test\Middleware\Route\ValidLoginMiddleware::class,
\Test\Middleware\Route\ValidLoginMiddleware::class
],
]);
});
// 协程并发-协程并发迭代数组处理数据(针对数据量大,无需关注返回数据)
$list = [
[
'name' => ’name-1'
],
[
'name' => ’name-2'
],
[
'name' => ’name-3'
],
[
'name' => ’name-4'
],
[
'name' => ’name-5'
]
];
// 并发2个协程-循环迭代数组-回调函数处理
Parallel::run(2, $list, function ($item) {
var_dump($item['name']);
}, 0.01);
// 协程并发-协程并发处理并等待结果(针对并发量少,并且需要返回数据的)
$parallel = new Parallel();
$parallel->add(function () {
sleep(2);
return "阿里巴巴";
},'ali');
$parallel->add(function () {
sleep(2);
return "腾讯";
},'tengxu');
$parallel->add(function () {
sleep(2);
return "百度";
},'baidu');
$parallel->add(function () {
sleep(5);
return "字节跳动";
},'zijie');
// 并发等待返回数据
$result = $parallel->runWait(10);
array(4) {
["ali"]=>
string(12) "阿里巴巴"
["tengxu"]=>
string(6) "腾讯"
["baidu"]=>
string(6) "百度"
["zijie"]=>
string(12) "字节跳动"
}
namespace Test\Module\Order\Validation;
use OpenApi\Attributes as OA;
use Test\Module\Swag;
class UserOrderValidation
{
// Post请求的参数
#[OA\Post(
path: '/user/user-order/userList',
summary:'订单保存',
description:'保存订单',
tags: [Swag::MODULE_TAG_ORDER], // 根据Swag.php的注册的tag值来设置,相同的tag的接口将汇集在同一个模块下
security: [['apiKeyAuth' => []], ['appId' => []]], //指定了在哪些接口上应用SecurityScheme中已经定义的安全方案
requestBody: new OA\RequestBody(
// 整型
new OA\Property(property: 'product_num', type: 'integer', description:'产品数量'
),
// 数组 phone => [1111, 22222]
new OA\Property(property: 'phone', type: 'array', description:'电话', items: new OA\Items(
type: 'integer'
)),
// 一维关联数组(对象) address = ['sheng' => '广东省', 'city' => '深圳市','area'=>'宝安区'],
new OA\Property(property: 'address', type: 'object', description:'居住地址',
properties:[
// sheng
new OA\Property(property: 'sheng', type: 'string', description:'省份'
),
// city
new OA\Property(property: 'city', type: 'string', description:'城市'
),
// area
new OA\Property(property: 'area', type: 'string', description:'县/区'
),
]
),
// 二维关联数组 addressList => [
// ['sheng' => '广东省', 'city' => '深圳市','area'=>'宝安区'],
// ['sheng' => '广东省', 'city' => '深圳市','area'=>'宝安区']
// ]
new OA\Property(property: 'addressList', type: 'array', description:'地址列表', items: new OA\Items(
type: 'object',
properties:[
// sheng
new OA\Property(property: 'sheng', type: 'string', description:'省份'
),
// city
new OA\Property(property: 'city', type: 'string', description:'城市'
),
// area
new OA\Property(property: 'area', type: 'string', description:'县/区'
),
]
)),
]
)
)
)
)]
#[OA\Response(
response: 200,
description: '操作成功'
)]
public function userList(): array
{
return [
'rules' => [
'name' => '