在我看来,swoole的优点是性能高,可定制性强,应用场景广(支持http服务,socket服务,或者自己手撸个tcp服务)。但对于日常使用TP或laravel这类框架的开发者来说说,使用原生的swoole框架来做开发并不是很方便,于是产生了很多以swoole为核心的swoole框架,如easyswoole,Swoft ,SwooleDistributed 等,具体介绍可以看swoole的衍生开源项目。这次使用easyswoole来做一个http服务。
easyswoole目前有三个版本:v1, v2, v3。如果你不需要用到协程,建议用v1,否则建议用v3,这次我用v2。easyswoole的安装,路由配置就不多介绍了,请看官方文档:EasySwoole V2 中文手册。
在日常开发中,最少都会有两个环境:开发环境和生产环境,常见的方法是使用不同配置文件来区分这两个环境(如数据库的连接配置,Redis的连接配置等)。easyswoole v2默认没这个功能(v3有),为了实现这个功能,我使用vlucas/phpdotenv
来做。
1.安装phpdotenv
composer require vlucas/phpdotenv
2.在根目录下添加Config目录,在该目录下添加database.php文件,并将数据库的配置信息移到该文件中,内容参考如下:
[
'driver' => 'mysql',
'host' => env('DB_HOST','127.0.0.1'),
'database' => env('DB_DATABASE','park_new'),
'username' => env('DB_USERNAME','root'),
'password' => env('DB_PASSWORD','123456'),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => ''
],
'redis' => [
'master' => [
'host' => env('REDIS_MASTER_HOST','127.0.0.1'),
'port' => env('REDIS_MASTER_PORT',6379),
'password' => env('REDIS_MASTER_PASSWORD',''),
],
'slave' => [
'host' => env('REDIS_SLAVE_HOST','127.0.0.1'),
'port' => env('REDIS_SLAVE_PORT',6379),
'password' => env('REDIS_SLAVE_PASSWORD',''),
],
],
];
当然不是一定要放在这里,只需保证在swoole启动时能加载到.env配置,并在后面mysql,redis等读取配置时使用到它即可。
3.在根目录增加.env配置
和laravel的.env配置一样,比如
REDIS_MASTER_HOST=172.16.88.101
REDIS_MASTER_PASSWORD=888999
REDIS_MASTER_PORT=6379
REDIS_SLAVE_HOST=172.16.88.102
REDIS_SLAVE_PASSWORD=888999
REDIS_SLAVE_PORT=6379
4.在EasySwooleEvent的frameInitialize中加载配置,内容如下
// 载入项目 Conf 文件夹中所有的配置文件
// 载入env配置
$dotenv = new \Dotenv\Dotenv('./');
$dotenv->load();
$files = File::scanDir('./Config');
if($files){
foreach ($files as $file) {
$fileNameArr= explode('.',$file);
$fileSuffix = end($fileNameArr);
// 目前只支持php结尾的配置文件
if($fileSuffix !='php'){
continue;
}
if (!is_file($file)) {
continue;
}
$confData = require_once $file;
if (is_array($confData) && !empty($confData)) {
foreach ($confData as $key=>$datum){
Config::getInstance()->setConf($key,$datum);
}
}
}
}
5.tips
假如使用git开发,一般都会排除vendor目录,但在使用easyswoole的过程中,可能会需要去修改下源码。此时我们需要保留vendor中的easyswoole目录,排除其他目录,可在.gitignore中做如下配置:
vendor/*
!vendor/easyswoole/
之前使用laravel比较多,习惯了illuminate/database
。
1.安装illuminate/database
composer require illuminate/database
2.加载illuminate/database
在 \EasySwoole\EasySwooleEvent 的 框架初始化完成 事件中初始化数据库类配置
use Illuminate\Database\Capsule\Manager as Capsule;//如果你不喜欢这个名称,as DB;就好
// 初始化完成
function static frameInitialize()
{
// 初始化数据库
$dbConf = Config::getInstance()->getConf('database');
$capsule = new Capsule;
// 创建链接
$capsule->addConnection($dbConf);
// 设置全局静态可访问
$capsule->setAsGlobal();
// 启动Eloquent
$capsule->bootEloquent();
}
3.增加Model配置
在App目录下增加一个Models目录,用于model层,定义下表这些,方便使用。比如增加一个订单信息表OrderInfo.php,内容如下:
4.愉快的使用
做好这些工作后,就可以方便的操作数据库了,如增加一个订单:
use App\Models\OrderInfo;
$order = new OrderInfo();
$order->order_sn = date("YmdHis", time()) . $car->user_id . rand(000, 999);
$order->user_id = $car->user_id;
$order->car_number = $data['carID'];
$order->save();
本次使用predis/predis
1.安装
composer require predis/predis
2.在App目录下创建Libs\Redis目录,在里面增加redis封装RedisTool.php,内容如下:
namespace App\Libs\Redis;
use EasySwoole\Config;
class RedisTool
{
const REDIS_MAIN = 'master';
const REDIS_SLAVE = 'slave';
private static $ins = null;
public static function getInstance($redisType=self::REDIS_MAIN, $extras=[])
{
// 获取配置
$redisConf = Config::getInstance()->getConf('redis');
$redisConf = array_merge($redisConf[$redisType], $extras);
if(is_null(self::$ins)){
self::$ins = new self($redisConf);
}
return self::$ins;
}
/*
* 构造函数
*
*/
private function __construct($config)
{
$redis = new \Predis\Client($config);
$this->ser = $redis;
}
/*
* 结束时关闭连接
*/
private function __destruct()
{
$this->ser->disconnect();
}
public function produce($key, array $data)
{
return $this->ser->lpush($key, $data);
}
public function lpush($key, $data)
{
if (is_string($data)) {
$data = (array)$data;
}
return $this->ser->lpush($key, $data);
}
3.使用redis
use App\Libs\Redis\RedisTool;
RedisTool::getInstance()->lpush('CAR_OUT',$carOut->order_sn);
一般项目中都会有些小函数,小方法,这里我统一把它们放到App\Libs\Base目录下(默认没这个目录,需手动创建)。如BaseService.php:
class BaseService
{
public static function withResult($state, $message = '', $data = null)
{
return [
'state' => $state,
'message' => $message,
'data' => $data
];
}
public static function withJson(string $retuslt,Response $response)
{
$response->withHeader('Content-type','application/json; charset=utf-8');
$response->write($retuslt);
$response->end();
}
public static function withHtml(string $retuslt,Response $response)
{
$response->withHeader('Content-type','text/html; charset=utf-8');
$response->write($retuslt);
$response->end();
}
}
这些准备完成后,就可以愉快的撸代码了。最终我的整个项目规划如下:
APP
|---- HttpController:默认的http控制器,里面写路由等
|---- Libs:基础方法的封装,自定义的SDK等
|---- Models:model层
|---- Services:各种服务的封装,业务逻辑的处理等
|---- Tasks:easyswoole的异步任务(很好用,很方便)
|---- Utility:easyswoole的封装,如redis连接池,mysql连接池