diff --git a/.env.example b/.env.example index e09949b..61fc08b 100644 --- a/.env.example +++ b/.env.example @@ -47,3 +47,8 @@ password = easyphp [log_path] path = /runtime/logs/ + +[swoole] +worker_num = 5 +max_request = 10000 +log_file = /runtime/logs/easy_swoole.log diff --git a/README-CN.md b/README-CN.md index fd42a16..e6661ee 100644 --- a/README-CN.md +++ b/README-CN.md @@ -3,10 +3,8 @@

Build Status Code Coverage +Version PHP Version -Version -Framework Size -Framework Phar Size License

@@ -55,6 +53,7 @@ app [PHP应用目录] │ │ └── route.php [模块自定义路由] │ ├── common.php [公共配置] │ ├── database.php [数据库配置] +│ ├── swoole.php [swoole配置] │ └── nosql.php [nosql配置] docs [接口文档目录] ├── apib [Api Blueprint] @@ -65,12 +64,14 @@ framework [Easy PHP核心框架目录] │ ├── CoreHttpException.php[核心http异常] ├── handles [框架运行时挂载处理机制类目录] │ ├── Handle.php [处理机制接口] +│ ├── EnvHandle.php [环境变量处理机制类] │ ├── ErrorHandle.php [错误处理机制类] │ ├── ExceptionHandle.php [未捕获异常处理机制类] │ ├── ConfigHandle.php [配置文件处理机制类] │ ├── NosqlHandle.php [nosql处理机制类] │ ├── LogHandle.php [log机制类] │ ├── UserDefinedHandle.php[用户自定义处理机制类] +│ ├── RouterSwooleHan... [swoole模式路由处理机制类] │ └── RouterHandle.php [路由处理机制类] ├── orm [对象关系模型] │ ├── Interpreter.php [sql解析器] @@ -85,6 +86,7 @@ framework [Easy PHP核心框架目录] │ ├── Userdefined.php [自定义路由] │ ├── Micromonomer.php [微单体路由] │ ├── Job.php [脚本任务路由] +│ ├── EasySwooleRouter.php [swoole模式路由策略入口类] │ └── EasyRouter.php [路由策略入口类] ├── nosql [nosql类目录] │ ├── Memcahed.php [Memcahed类文件] @@ -97,6 +99,7 @@ framework [Easy PHP核心框架目录] ├── Request.php [请求类] ├── Response.php [响应类] ├── run.php [框架应用启用脚本] +├── swoole.php [swoole模式框架应用启用脚本] frontend [前端源码和资源目录] ├── src [资源目录] │ ├── components [vue组件目录] @@ -116,6 +119,7 @@ public [公共资源目录,暴露到万维网] │ └── ... ├── index.html [前端入口文件,build生成的文件,不是发布分支忽略该文件] ├── index.php [后端入口文件] +├── server.php [swoole模式后端入口文件] runtime [临时目录] ├── logs [日志目录] ├── build [php打包生成phar文件目录] @@ -226,7 +230,7 @@ password = easyphp ##### 请求参数校验,目前提供必传,长度,数字类型校验,使用如下 ``` -$request = App::$container->getSingle('request'); +$request = App::$container->get('request'); $request->check('username', 'require'); $request->check('password', 'length', 12); $request->check('code', 'number'); @@ -350,7 +354,7 @@ $checkArguments->setNext($checkAppkey) // 启动网关 $checkArguments->start( - APP::$container->getSingle('request') + APP::$container->get('request') ); ``` @@ -554,7 +558,7 @@ App::$container->setSingle('request', function () { return new Request(); }); // 获取Request对象 -App::$container->getSingle('request'); +App::$container->get('request'); ``` [[file: framework/Container](https://github.com/TIGERB/easy-php/blob/master/framework/Container.php)] @@ -576,7 +580,17 @@ App::$container->getSingle('mongodb'); [[file: framework/nosql/*](https://github.com/TIGERB/easy-php/tree/master/framework/nosql)] -## Job Support +## Swoole模式 + +支持swoole扩展下运行 + +``` +cd public && php server.php +``` + +[[file: framework/nosql/*](https://github.com/TIGERB/easy-php/tree/master/framework/swoole.php)] + +## Job模式 我们可以在jobs目录下直接编写我们的任务脚本,如下 @@ -735,11 +749,17 @@ php cli --method= --= ... 例如, php cli --method=demo.index.get --username=easy-php ``` +**Swoole模式:** + +``` +cd public && php server.php +``` + 获取帮助: 使用命令 php cli 或者 php cli --help -# 性能 +# 性能-fpm > ab -c 100 -n 10000 "http://easy-php.local/Demo/Index/hello" @@ -777,6 +797,41 @@ Percentage of the requests served within a certain time (ms) 100% 68 (longest request) ``` +# 性能-Swoole + +> ab -c 100 -n 10000 "http://easy-php.local/Demo/Index/hello" + +``` +Concurrency Level: 100 +Time taken for tests: 1.319 seconds +Complete requests: 10000 +Failed requests: 0 +Total transferred: 1870000 bytes +HTML transferred: 160000 bytes +Requests per second: 7580.84 [#/sec] (mean) +Time per request: 13.191 [ms] (mean) +Time per request: 0.132 [ms] (mean, across all concurrent requests) +Transfer rate: 1384.39 [Kbytes/sec] received + +Connection Times (ms) + min mean[+/-sd] median max +Connect: 0 5 10.6 3 172 +Processing: 1 9 13.4 7 177 +Waiting: 0 7 11.7 6 173 +Total: 3 13 16.9 11 179 + +Percentage of the requests served within a certain time (ms) + 50% 11 + 66% 12 + 75% 13 + 80% 14 + 90% 15 + 95% 17 + 98% 28 + 99% 39 + 100% 179 (longest request) +``` + # 问题和贡献 不足的地方还有很多,如果大家发现了什么问题,可以给我提[issue](https://github.com/TIGERB/easy-php/issues)或者PR。 @@ -795,7 +850,6 @@ cp ./.git-hooks/* ./git/hooks # TODO -- 集成swoole - 增加数据库变更辅助 - 集成swagger - 提供更友善的开发api帮助 @@ -808,6 +862,10 @@ cp ./.git-hooks/* ./git/hooks # DONE +- v0.8.0(2017/12/31) + - 支持swoole扩展 + - 修复微单体路由无限递归问题 + - v0.7.1(2017/08/29) - 重构路由模块 diff --git a/README.md b/README.md index 973bd40..d07e870 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,8 @@

Build Status Code Coverage +Version PHP Version -Version -Framework Size -Framework Phar Size License

@@ -54,6 +52,7 @@ app [application backend directory] │ │ └── route.php [module-defined router] │ ├── common.php [common config] │ ├── database.php [database config] +│ ├── swoole.php [swoole config] │ └── nosql.php [nosql config] docs [api document directory] ├── apib [Api Blueprint] @@ -70,6 +69,7 @@ framework [easy-php framework directory] │ ├── NosqlHandle.php [nosql handle class] │ ├── LogHandle.php [log handle class] │ ├── UserDefinedHandle.php[user defined handle class] +│ ├── RouterSwooleHan... [router handle class for swoole mode] │ └── RouterHandle.php [router handle class] ├── orm [datebase object relation map class directory] │ ├── Interpreter.php [sql Interpreter class] @@ -84,6 +84,7 @@ framework [easy-php framework directory] │ ├── Userdefined.php [userdefined strategy class] │ ├── Micromonomer.php [micromonomer strategy class] │ ├── Job.php [job strategy class] +│ ├── EasySwooleRouter.php [router strategy entrance class for swoole mode] │ └── EasyRouter.php [router strategy entrance class] ├── nosql [nosql directory] │ ├── Memcahed.php [memcahed class file] @@ -96,6 +97,7 @@ framework [easy-php framework directory] ├── Request.php [request object class file] ├── Response.php [response object class file] ├── run.php [run this application script file] +├── swoole.php [init the framework && swoole server] frontend [application frontend source code directory] ├── src [source folder] │ ├── components [vue components] @@ -115,6 +117,7 @@ public [this is a resource directory to expose service │ └── ... ├── index.html [entrance html file] ├── index.php [entrance php script file] +├── server.php [init the server with swoole] runtime [temporary file such as log] ├── logs [log directory] ├── build [phar directory build by build script] @@ -223,7 +226,7 @@ All output is json in the framework, neithor framework's core error or business ##### Request param check, Support require/length/number check at present. Use as follows: ``` -$request = App::$container->getSingle('request'); +$request = App::$container->get('request'); $request->check('username', 'require'); $request->check('password', 'length', 12); $request->check('code', 'number'); @@ -349,7 +352,7 @@ $checkArguments->setNext($checkAppkey) // start gateway $checkArguments->start( - APP::$container->getSingle('request') + APP::$container->get('request') ); ``` @@ -553,7 +556,7 @@ App::$container->setSingle('request', function () { return new Request(); }); // get Request instance -App::$container->getSingle('request'); +App::$container->get('request'); ``` [[file: framework/Container](https://github.com/TIGERB/easy-php/blob/master/framework/Container.php)] @@ -573,7 +576,15 @@ App::$container->getSingle('memcahed'); App::$container->getSingle('mongodb'); ``` -[[file: framework/nosql/*](https://github.com/TIGERB/easy-php/tree/master/framework/nosql)] +## Swoole Support + +This framework support swoole mode with the php extension swoole, just: + +``` +cd public && php server.php +``` + +[[file: framework/nosql/*](https://github.com/TIGERB/easy-php/tree/master/framework/swoole.php)] ## Job Support @@ -734,18 +745,21 @@ php cli --method= --= ... For example, php cli --method=demo.index.get --username=easy-php ``` +**Swoole Mode:** + +``` +cd public && php server.php +``` + Get Help: Use php cli OR php cli --help -# Performance +# Performance with php-fmp > ab -c 100 -n 10000 "http://easy-php.local/Demo/Index/hello" ``` -Document Path: / -Document Length: 53 bytes - Concurrency Level: 100 Time taken for tests: 3.259 seconds Complete requests: 10000 @@ -776,6 +790,41 @@ Percentage of the requests served within a certain time (ms) 100% 68 (longest request) ``` +# Performance with Swoole + +> ab -c 100 -n 10000 "http://easy-php.local/Demo/Index/hello" + +``` +Concurrency Level: 100 +Time taken for tests: 1.319 seconds +Complete requests: 10000 +Failed requests: 0 +Total transferred: 1870000 bytes +HTML transferred: 160000 bytes +Requests per second: 7580.84 [#/sec] (mean) +Time per request: 13.191 [ms] (mean) +Time per request: 0.132 [ms] (mean, across all concurrent requests) +Transfer rate: 1384.39 [Kbytes/sec] received + +Connection Times (ms) + min mean[+/-sd] median max +Connect: 0 5 10.6 3 172 +Processing: 1 9 13.4 7 177 +Waiting: 0 7 11.7 6 173 +Total: 3 13 16.9 11 179 + +Percentage of the requests served within a certain time (ms) + 50% 11 + 66% 12 + 75% 13 + 80% 14 + 90% 15 + 95% 17 + 98% 28 + 99% 39 + 100% 179 (longest request) +``` + # Question&Contribution If you find some question,please launch a [issue](https://github.com/TIGERB/easy-php/issues) or PR。 @@ -791,7 +840,6 @@ project address: [https://github.com/TIGERB/easy-php](https://github.com/TIGERB/ # TODO -- Use swoole - Add database sql helper - Integrate swagger - Provide much friendly help for user @@ -805,6 +853,10 @@ project address: [https://github.com/TIGERB/easy-php](https://github.com/TIGERB/ # DONE +- v0.8.0(2017/12/31) + - use swoole + - fix infinite recursion for micromonomer router + - v0.7.1(2017/08/29) - refactor router by the strategy design pattern diff --git a/app/demo/controllers/Index.php b/app/demo/controllers/Index.php index 1af3c89..83c14b1 100644 --- a/app/demo/controllers/Index.php +++ b/app/demo/controllers/Index.php @@ -48,7 +48,7 @@ public function hello() */ public function test() { - $request = App::$container->getSingle('request'); + $request = App::$container->get('request'); $request->check('username', 'require'); $request->check('password', 'length', 12); $request->check('code', 'number'); @@ -82,7 +82,7 @@ public function micro() public function getInstanceFromContainerDemo() { // 请求对象 - App::$container->getSingle('request'); + App::$container->get('request'); // 配置对象 App::$container->getSingle('config'); // 日志对象 diff --git a/app/demo/logics/gateway/Entrance.php b/app/demo/logics/gateway/Entrance.php index f137d8d..b5b0c10 100644 --- a/app/demo/logics/gateway/Entrance.php +++ b/app/demo/logics/gateway/Entrance.php @@ -59,7 +59,7 @@ public function __construct() // 启动网关 $checkArguments->start( - APP::$container->getSingle('request') + APP::$container->get('request') ); } } diff --git a/cli b/cli index cc27d9f..21fb784 100644 --- a/cli +++ b/cli @@ -98,7 +98,7 @@ foreach ($argv as $v) { } // 设置cli模式 -putenv('IS_CLI=yes'); +putenv('EASY_MODE=cli'); if (isset($input['method'])) { $method = $input['method']; $method = explode('.', $method); diff --git a/config/swoole.php b/config/swoole.php new file mode 100644 index 0000000..d1fdbee --- /dev/null +++ b/config/swoole.php @@ -0,0 +1,16 @@ + * + * * + ********************************************/ + +use Framework\Helper; + +return [ + 'swoole' => env('swoole') +]; diff --git a/framework/App.php b/framework/App.php index 042b851..5a3990e 100644 --- a/framework/App.php +++ b/framework/App.php @@ -55,11 +55,18 @@ class App private $responseData; /** - * cli模式 + * 运行模式 + * 目前支持fpm/cli/swoole模式 + * 默认为fpm + * + * app running mode + * support fpm/cli/swoole + * default value is fpm * * @var string */ - private $isCli = 'false'; + private $runningMode = 'fpm'; + /** * 框架实例 @@ -94,8 +101,8 @@ class App */ public function __construct($rootPath, Closure $loader) { - // cli模式 - $this->isCli = getenv('IS_CLI'); + // 运行模式 + $this->runningMode = getenv('EASY_MODE'); // 根目录 $this->rootPath = $rootPath; @@ -213,12 +220,12 @@ public function callSelf($method = '', $uri = '', $argus = array()) if (count($requestUri) !== 3) { throw new CoreHttpException(400); } - $request = self::$container->getSingle('request'); + $request = self::$container->get('request'); $request->method = $method; $request->requestParams = $argus; $request->getParams = $argus; $request->postParams = $argus; - $router = self::$container->getSingle('router'); + $router = self::$container->get('router'); $router->moduleName = $requestUri[0]; $router->controllerName = $requestUri[1]; $router->actionName = $requestUri[2]; @@ -229,17 +236,17 @@ public function callSelf($method = '', $uri = '', $argus = array()) /** * 运行应用 + * + * fpm mode * * @param Request $request 请求对象 * @return void */ public function run(Closure $request) { - self::$container->setSingle('request', $request); + self::$container->set('request', $request); foreach ($this->handlesList as $handle) { - $instance = $handle(); - // self::$container->setSingle(get_class($instance), $instance); - $instance->register($this); + $handle()->register($this); } } @@ -255,7 +262,7 @@ public function response(Closure $closure) if ($this->notOutput === true) { return; } - if ($this->isCli === 'yes') { + if ($this->runningMode === 'cli') { $closure()->cliModeSuccess($this->responseData); return; } @@ -268,4 +275,18 @@ public function response(Closure $closure) } $closure()->response($this->responseData); } + + /** + * 生命周期结束 + * + * 响应请求 + * @param Closure $closure 响应类 + * @return json + */ + public function responseSwoole(Closure $closure) + { + $closure()->header('Content-Type', 'Application/json'); + $closure()->header('Charset', 'utf-8'); + $closure()->end(json_encode($this->responseData)); + } } diff --git a/framework/Container.php b/framework/Container.php index d19a8f9..3d9861d 100644 --- a/framework/Container.php +++ b/framework/Container.php @@ -73,6 +73,9 @@ public function get($alias = '') if (is_callable($this->classMap[$alias])) { return $this->classMap[$alias](); } + if (is_object($this->classMap[$alias])) { + return $this->classMap[$alias]; + } return new $this->classMap[$alias]; } throw new CoreHttpException( diff --git a/framework/Request.php b/framework/Request.php index 94e5975..e035f21 100644 --- a/framework/Request.php +++ b/framework/Request.php @@ -21,25 +21,11 @@ class Request { /** - * 请求模块 + * 请求header参数 * - * @var string - */ - private $module = ''; - - /** - * 请求控制器 - * - * @var string - */ - private $controller = ''; - - /** - * 请求操作 - * - * @var string + * @var array */ - private $action = ''; + private $headerParams = []; /** * 请求server参数 @@ -57,16 +43,32 @@ class Request /** * 请求GET参数 + * * @var array */ private $getParams = []; /** * 请求POST参数 + * * @var array */ private $postParams = []; + /** + * cookie + * + * @var array + */ + private $cookie = []; + + /** + * file + * + * @var array + */ + private $file = []; + /** * http方法名称 * @@ -129,21 +131,40 @@ class Request */ public function __construct(App $app) { + // swoole mode + if ($app->runningMode === 'swoole') { + $swooleRequest = $app::$container->get('request-swoole'); + $this->headerParams = $swooleRequest->header; + $this->serverParams = $swooleRequest->server; + $this->method = $this->serverParams['request_method']; + $this->serverIp = $this->serverParams['remote_addr']; + $this->clientIp = $this->serverParams['remote_addr']; + $this->beginTime = $this->serverParams['request_time_float']; + $this->getParams = isset($swooleRequest->get)? $swooleRequest->get: []; + $this->postParams = isset($swooleRequest->post)? $swooleRequest->post: []; + $this->cookie = isset($swooleRequest->cookie)? $swooleRequest->cookie: []; + $this->file = isset($swooleRequest->files)? $swooleRequest->files: []; + $this->requestParams = array_merge($this->getParams, $this->postParams); + return; + } + $this->serverParams = $_SERVER; $this->method = isset($_SERVER['REQUEST_METHOD'])? strtolower($_SERVER['REQUEST_METHOD']) : 'get'; $this->serverIp = isset($_SERVER['REMOTE_ADDR'])? $_SERVER['REMOTE_ADDR'] : ''; $this->clientIp = isset($_SERVER['SERVER_ADDR'])? $_SERVER['SERVER_ADDR'] : ''; - $this->beginTime = isset($_SERVER['REQUEST_TIME_FLOAT'])? $_SERVER['REQUEST_TIME_FLOAT'] : time(true); - if ($app->isCli === 'yes') { + $this->beginTime = isset($_SERVER['REQUEST_TIME_FLOAT'])? $_SERVER['REQUEST_TIME_FLOAT'] : microtime(true); + if ($app->runningMode === 'cli') { // cli 模式 $this->requestParams = isset($_REQUEST['argv'])? $_REQUEST['argv']: []; $this->getParams = isset($_REQUEST['argv'])? $_REQUEST['argv']: []; $this->postParams = isset($_REQUEST['argv'])? $_REQUEST['argv']: []; - } else { - $this->requestParams = $_REQUEST; - $this->getParams = $_GET; - $this->postParams = $_POST; + return; } + + $this->requestParams = $_REQUEST; + $this->getParams = $_GET; + $this->postParams = $_POST; + } /** @@ -302,3 +323,54 @@ public function check($paramName = '', $rule = '', $length = 0) } } } + +/** +object(Swoole\Http\Request)#26 (3) { + ["fd"]=> + int(1) + ["header"]=> + array(9) { + ["host"]=> + string(14) "127.0.0.1:8888" + ["connection"]=> + string(10) "keep-alive" + ["pragma"]=> + string(8) "no-cache" + ["cache-control"]=> + string(8) "no-cache" + ["user-agent"]=> + string(121) "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" + ["accept"]=> + string(39) "image/webp,image/apng,image;q=0.8" + ["referer"]=> + string(37) "http://127.0.0.1:8888/demo/index/test" + ["accept-encoding"]=> + string(17) "gzip, deflate, br" + ["accept-language"]=> + string(23) "zh-CN,zh;q=0.8,en;q=0.6" + } + ["server"]=> + array(10) { + ["request_method"]=> + string(3) "GET" + ["request_uri"]=> + string(12) "/favicon.ico" + ["path_info"]=> + string(12) "/favicon.ico" + ["request_time"]=> + int(1514357716) + ["request_time_float"]=> + float(1514357716.1488) + ["server_port"]=> + int(8888) + ["remote_port"]=> + int(64729) + ["remote_addr"]=> + string(9) "127.0.0.1" + ["server_protocol"]=> + string(8) "HTTP/1.1" + ["server_software"]=> + string(18) "swoole-http-server" + } +} +*/ diff --git a/framework/exceptions/CoreHttpException.php b/framework/exceptions/CoreHttpException.php index fd5cca1..ef69302 100644 --- a/framework/exceptions/CoreHttpException.php +++ b/framework/exceptions/CoreHttpException.php @@ -82,6 +82,35 @@ public function reponse() die(json_encode($data, JSON_UNESCAPED_UNICODE)); } + /** + * rest 风格http响应 + * + * @return json + */ + public function reponseSwoole() + { + $data = [ + '__coreError' => [ + 'code' => $this->getCode(), + 'message' => $this->getMessage(), + 'infomations' => [ + 'file' => $this->getFile(), + 'line' => $this->getLine(), + 'trace' => $this->getTrace(), + ] + ] + ]; + + // log + App::$container->getSingle('logger')->write($data); + + // response + $reponse = App::$container->get('response-swoole'); + $reponse->header('Content-Type', 'Application/json'); + $reponse->header('Charset', 'utf-8'); + $reponse->end(json_encode($data)); + } + /** * rest 风格http异常响应 * @@ -107,4 +136,32 @@ public static function reponseErr($e) header('Content-Type:Application/json; Charset=utf-8'); die(json_encode($data)); } + + /** + * rest 风格http异常响应 + * + * @param array $e 异常 + * @return json + */ + public static function reponseErrSwoole($e) + { + $data = [ + '__coreError' => [ + 'code' => 500, + 'message' => $e, + 'infomations' => [ + 'file' => $e['file'], + 'line' => $e['line'], + ] + ] + ]; + + // log + App::$container->getSingle('logger')->write($data); + + $reponse = App::$container->get('response-swoole'); + $reponse->header('Content-Type', 'Application/json'); + $reponse->header('Charset', 'utf-8'); + $reponse->end(json_encode($data)); + } } diff --git a/framework/handles/ConfigHandle.php b/framework/handles/ConfigHandle.php index f77432d..9a70c1e 100644 --- a/framework/handles/ConfigHandle.php +++ b/framework/handles/ConfigHandle.php @@ -34,7 +34,7 @@ class ConfigHandle implements Handle * * @var array */ - private $config; + private $config = []; /** * 构造函数 @@ -102,8 +102,9 @@ public function loadConfig(App $app) $defaultCommon = require($app->rootPath . '/config/common.php'); $defaultNosql = require($app->rootPath . '/config/nosql.php'); $defaultDatabase = require($app->rootPath . '/config/database.php'); + $defaultSwoole = require($app->rootPath . '/config/swoole.php'); - $this->config = array_merge($defaultCommon, $defaultNosql, $defaultDatabase); + $this->config = array_merge($defaultCommon, $defaultNosql, $defaultDatabase, $defaultSwoole); /* 加载模块自定义配置 */ $module = $app::$container->getSingle('config')->config['module']; diff --git a/framework/handles/EnvHandle.php b/framework/handles/EnvHandle.php index fd59deb..36ca68d 100644 --- a/framework/handles/EnvHandle.php +++ b/framework/handles/EnvHandle.php @@ -56,7 +56,7 @@ public function register(App $app) // 加载环境参数 $this->loadEnv($app); - $app::$container->setSingle('env', $this); + App::$container->setSingle('envt', $this); } /** diff --git a/framework/handles/ErrorHandle.php b/framework/handles/ErrorHandle.php index 48f0357..efbe6e2 100644 --- a/framework/handles/ErrorHandle.php +++ b/framework/handles/ErrorHandle.php @@ -22,6 +22,22 @@ */ class ErrorHandle implements Handle { + /** + * 运行模式 + * + * fpm/swoole + * + * @var string + */ + private $mode = 'fmp'; + + /** + * 错误信息 + * + * @var array + */ + private $info = []; + /** * 构造函数 */ @@ -39,6 +55,8 @@ public function __construct() */ public function register(App $app) { + $this->mode = $app->runningMode; + set_error_handler([$this, 'errorHandler']); register_shutdown_function([$this, 'shutdown']); @@ -55,14 +73,14 @@ public function shutdown() if (empty($error)) { return; } - $errorInfo = [ + $this->info = [ 'type' => $error['type'], 'message' => $error['message'], 'file' => $error['file'], 'line' => $error['line'], ]; - CoreHttpException::reponseErr($errorInfo); + $this->end(); } /** @@ -82,7 +100,7 @@ public function errorHandler( $errorLine, $errorContext) { - $errorInfo = [ + $this->info = [ 'type' => $errorNumber, 'message' => $errorMessage, 'file' => $errorFile, @@ -90,7 +108,24 @@ public function errorHandler( 'context' => $errorContext, ]; - CoreHttpException::reponseErr($errorInfo); + $this->end(); } + /** + * 脚本结束 + * + * @return mixed + */ + private function end() + { + switch ($this->mode) { + case 'swoole': + CoreHttpException::reponseErrSwoole($this->info); + break; + + default: + CoreHttpException::reponseErr($this->info); + break; + } + } } diff --git a/framework/handles/ExceptionHandle.php b/framework/handles/ExceptionHandle.php index eb17385..f6de24f 100644 --- a/framework/handles/ExceptionHandle.php +++ b/framework/handles/ExceptionHandle.php @@ -22,6 +22,22 @@ */ class ExceptionHandle implements Handle { + /** + * 运行模式 + * + * fpm/swoole + * + * @var string + */ + private $mode = 'fmp'; + + /** + * 错误信息 + * + * @var array + */ + private $info = []; + /** * 构造函数 */ @@ -49,7 +65,7 @@ public function register(App $app) */ public function exceptionHandler($exception) { - $exceptionInfo = [ + $this->info = [ 'code' => $exception->getCode(), 'message' => $exception->getMessage(), 'file' => $exception->getFile(), @@ -58,6 +74,24 @@ public function exceptionHandler($exception) 'previous' => $exception->getPrevious() ]; - CoreHttpException::reponseErr($exceptionInfo); + $this->end(); + } + + /** + * 脚本结束 + * + * @return mixed + */ + private function end() + { + switch ($this->mode) { + case 'swooole': + CoreHttpException::reponseErrSwoole($this->info); + break; + + default: + CoreHttpException::reponseErr($this->info); + break; + } } } diff --git a/framework/handles/RouterSwooleHandle.php b/framework/handles/RouterSwooleHandle.php new file mode 100644 index 0000000..bf56f40 --- /dev/null +++ b/framework/handles/RouterSwooleHandle.php @@ -0,0 +1,38 @@ + * + * * + *************************************************/ + +namespace Framework\Handles; + +use Framework\App; +use Framework\Exceptions\CoreHttpException; +use Closure; +use Framework\Router\EasySwooleRouter; + +/** + * 路由处理机制. + * + * @author TIERGB + */ +class RouterSwooleHandle implements Handle +{ + /** + * 注册路由处理机制. + * + * @param App $app 框架实例 + * @param void + */ + public function register(App $app) + { + App::$container->set('router', function () { + return new EasySwooleRouter(); + }); + } +} diff --git a/framework/helper.php b/framework/helper.php index 56d6f07..dbacb3e 100644 --- a/framework/helper.php +++ b/framework/helper.php @@ -31,7 +31,7 @@ function env($paramName = '') // if (array_key_exists($paramName, self::$envCache)) { // return self::$envCache[$paramName]; // } - return App::$container->getSingle('env')->env($paramName); + return App::$container->getSingle('envt')->env($paramName); } /** diff --git a/framework/router/EasyRouter.php b/framework/router/EasyRouter.php index bdd49a9..03d8bd8 100644 --- a/framework/router/EasyRouter.php +++ b/framework/router/EasyRouter.php @@ -12,19 +12,24 @@ namespace Framework\Router; use Framework\App; +use Framework\Router\Router; use Framework\Exceptions\CoreHttpException; // use ReflectionClass; use Closure; /** - * 路由入口. + * 路由入口 + * + * the router entrance * * @author TIERGB */ -class EasyRouter +class EasyRouter implements Router { /** - * 框架实例. + * 框架实例 + * + * the framework instance * * @var App */ @@ -32,6 +37,8 @@ class EasyRouter /** * 配置实例 + * + * the config instance * * @var */ @@ -39,6 +46,8 @@ class EasyRouter /** * 请求对象实例 + * + * the request instance * * @var */ @@ -47,19 +56,25 @@ class EasyRouter /** * 默认模块. * + * default module + * * @var string */ private $moduleName = ''; /** - * 默认控制器. - * + * 默认控制器 + * + * default controller + * * @var string */ private $controllerName = ''; /** * 默认操作. + * + * default action * * @var string */ @@ -67,13 +82,17 @@ class EasyRouter /** * 类文件路径. + * + * class path * * @var string */ private $classPath = ''; /** - * 类文件路径. + * 类文件执行类型. + * + * ececute type * * @var string */ @@ -81,6 +100,8 @@ class EasyRouter /** * 请求uri. + * + * the request uri * * @var string */ @@ -88,6 +109,8 @@ class EasyRouter /** * 路由策略. + * + * the current router strategy * * @var string */ @@ -95,6 +118,8 @@ class EasyRouter /** * 路由策略映射 + * + * the router strategy map * * @var array */ @@ -102,7 +127,7 @@ class EasyRouter 'general' => 'Framework\Router\General', 'pathinfo' => 'Framework\Router\Pathinfo', 'user-defined' => 'Framework\Router\Userdefined', - 'micromonemer' => 'Framework\Router\Micromonomer', + 'micromonomer' => 'Framework\Router\Micromonomer', 'job' => 'Framework\Router\Job' ]; @@ -139,26 +164,26 @@ public function __set($name = '', $value = '') */ public function init(App $app) { - // 注入当前对象到容器中 - $app::$container->setSingle('router', $this); + // 注入当前对象到容器中 register this object to the service container + $app::$container->set('router', $this); // request uri - $this->request = $app::$container->getSingle('request'); + $this->request = $app::$container->get('request'); $this->requestUri = $this->request->server('REQUEST_URI'); // App $this->app = $app; - // 获取配置 + // 获取配置 get config $this->config = $app::$container->getSingle('config'); - // 设置默认模块 + // 设置默认模块 set default module $this->moduleName = $this->config->config['route']['default_module']; - // 设置默认控制器 + // 设置默认控制器 set default controller $this->controllerName = $this->config->config['route']['default_controller']; - // 设置默认操作 + // 设置默认操作 set default action $this->actionName = $this->config->config['route']['default_action']; - // 路由决策 + // 路由决策 judge the router strategy $this->strategyJudge(); - // 路由策略 + // 路由策略 the current router strategy (new $this->routeStrategyMap[$this->routeStrategy])->route($this); // 判断是app还是job @@ -173,6 +198,32 @@ public function init(App $app) $this->start(); } + /** + * 路由策略决策 + * + * @param void + */ + public function strategyJudge() + { + // 路由策略 + if (! empty($this->routeStrategy)) { + return; + } + + // 任务路由 + if ($this->app->runningMode === 'cli' && $this->request->get('router_mode') === 'job') { + $this->routeStrategy = 'job'; + return; + } + + // 普通路由 + if (strpos($this->requestUri, 'index.php') || $this->app->runningMode === 'cli') { + $this->routeStrategy = 'general'; + return; + } + $this->routeStrategy = 'pathinfo'; + } + /** * 判断是app还是job * @@ -197,34 +248,6 @@ public function isAppOrJob() $this->executeType = 'controller'; } - /** - * 路由策略决策 - * - * @param void - */ - public function strategyJudge() - { - // 路由策略 - if (! empty($this->routeSrategy)) { - return; - } - - // 任务路由 - if ($this->app->isCli === 'yes' && $this->request->get('router_mode') === 'job') { - $this->routeStrategy = 'job'; - return; - } - - // 普通路由 - if (strpos($this->requestUri, 'index.php') || $this->app->isCli === 'yes') { - $this->routeStrategy = 'general'; - return; - } else { - $this->routeStrategy = 'pathinfo'; - return; - } - } - /** * 路由机制 * @@ -258,6 +281,7 @@ public function start() // 调用操作 $actionName = $this->actionName; + // 获取返回值 $this->app->responseData = $controller->$actionName(); } diff --git a/framework/router/EasySwooleRouter.php b/framework/router/EasySwooleRouter.php new file mode 100644 index 0000000..29de6fc --- /dev/null +++ b/framework/router/EasySwooleRouter.php @@ -0,0 +1,246 @@ + * + * * + *************************************************/ + +namespace Framework\Router; + +use Framework\App; +use Framework\Router\Router; +use Framework\Exceptions\CoreHttpException; +// use ReflectionClass; +use Closure; + +/** + * 路由入口. + * + * @author TIERGB + */ +class EasySwooleRouter implements Router +{ + /** + * 框架实例. + * + * @var App + */ + private $app; + + /** + * 配置实例 + * + * @var + */ + private $config; + + /** + * 请求对象实例 + * + * @var + */ + private $request; + + /** + * 响应对象实例 + * + * @var + */ + // private $response; + + /** + * 默认模块. + * + * @var string + */ + private $moduleName = ''; + + /** + * 默认控制器. + * + * @var string + */ + private $controllerName = ''; + + /** + * 默认操作. + * + * @var string + */ + private $actionName = ''; + + /** + * 类文件路径. + * + * @var string + */ + private $classPath = ''; + + /** + * 类文件路径. + * + * @var string + */ + private $executeType = ''; + + /** + * 请求uri. + * + * @var string + */ + private $requestUri = ''; + + /** + * 路由策略. + * + * @var string + */ + private $routeStrategy = ''; + + /** + * 路由策略映射 + * + * @var array + */ + private $routeStrategyMap = [ + 'general' => 'Framework\Router\General', + 'pathinfo' => 'Framework\Router\Pathinfo', + 'user-defined' => 'Framework\Router\Userdefined', + 'micromonomer' => 'Framework\Router\Micromonomer', + ]; + + /** + * 魔法函数__get. + * + * @param string $name 属性名称 + * + * @return mixed + */ + public function __get($name = '') + { + return $this->$name; + } + + /** + * 魔法函数__set. + * + * @param string $name 属性名称 + * @param mixed $value 属性值 + * + * @return mixed + */ + public function __set($name = '', $value = '') + { + $this->$name = $value; + } + + /** + * 注册路由处理机制. + * + * @param App $app 框架实例 + * @param void + */ + public function init(App $app) + { + // 注入当前对象到容器中 + $app::$container->set('router', $this); + + // App + $this->app = $app; + + $this->request = $app::$container->get('request'); + $this->requestUri = $this->request->server('request_uri'); + + // 获取配置 + $this->config = $app::$container->getSingle('config'); + // 设置默认模块 + $this->moduleName = $this->config->config['route']['default_module']; + // 设置默认控制器 + $this->controllerName = $this->config->config['route']['default_controller']; + // 设置默认操作 + $this->actionName = $this->config->config['route']['default_action']; + + // 路由决策 + $this->strategyJudge(); + + // 路由策略 + (new $this->routeStrategyMap[$this->routeStrategy])->route($this); + + // 获取控制器类 + $controllerName = ucfirst($this->controllerName); + $folderName = ucfirst($this->config->config['application_folder_name']); + $this->classPath = "{$folderName}\\{$this->moduleName}\\Controllers\\{$controllerName}"; + $this->executeType = 'controller'; + + // 自定义路由判断 + if ((new $this->routeStrategyMap['user-defined'])->route($this)) { + return; + } + + // 启动路由 + $this->start(); + } + + /** + * 路由策略决策 + * + * @param void + */ + public function strategyJudge() + { + // 路由策略 + if (! empty($this->routeStrategy)) { + return; + } + + // 普通路由 + if (strpos($this->requestUri, 'index.php') || $this->app->runningMode === 'cli') { + $this->routeStrategy = 'general'; + return; + } + + $this->routeStrategy = 'pathinfo'; + } + + /** + * 路由机制 + * + * @param void + */ + public function start() + { + // 判断模块存不存在 + if (! in_array(strtolower($this->moduleName), $this->config->config['module'])) { + throw new CoreHttpException(404,'Module:'.$this->moduleName); + } + + // 判断控制器存不存在 + if (! class_exists($this->classPath)) { + throw new CoreHttpException(404, "{$this->executeType}:{$this->classPath}"); + } + + // 反射解析当前控制器类  + // 判断是否有当前操作方法 + // 不使用反射 + // $reflaction = new ReflectionClass($controllerPath); + // if (!$reflaction->hasMethod($this->actionName)) { + // throw new CoreHttpException(404, 'Action:'.$this->actionName); + // } + + // 实例化当前控制器 + $controller = new $this->classPath(); + if (! method_exists($controller, $this->actionName)) { + throw new CoreHttpException(404, 'Action:'.$this->actionName); + } + + // 调用操作 + $actionName = $this->actionName; + + // 获取返回值 + $this->app->responseData = $controller->$actionName(); + } +} diff --git a/framework/router/General.php b/framework/router/General.php index 0ce9de2..f7aa1ba 100644 --- a/framework/router/General.php +++ b/framework/router/General.php @@ -12,7 +12,7 @@ namespace Framework\Router; use Framework\Router\RouterInterface; -use Framework\Router\EasyRouter; +use Framework\Router\Router; /** * 普通路由策略. @@ -26,10 +26,10 @@ class General implements RouterInterface * * @param void */ - public function route(EasyRouter $entrance) + public function route(Router $entrance) { - $app = $entrance->app; - $request = $app::$container->getSingle('request'); + $app = $entrance->app; + $request = $app::$container->get('request'); $moduleName = $request->request('module'); $controllerName = $request->request('controller'); $actionName = $request->request('action'); @@ -44,7 +44,7 @@ public function route(EasyRouter $entrance) } // CLI 模式不输出 - if (empty($actionName) && $entrance->app->isCli === 'yes') { + if (empty($actionName) && $entrance->app->runningMode === 'cli') { $entrance->app->notOutput = true; } } diff --git a/framework/router/Job.php b/framework/router/Job.php index 83363d4..c2f17d3 100644 --- a/framework/router/Job.php +++ b/framework/router/Job.php @@ -13,7 +13,7 @@ use Framework\App; use Framework\Router\RouterInterface; -use Framework\Router\EasyRouter; +use Framework\Router\Router; use Framework\Exceptions\CoreHttpException; use ReflectionClass; use Closure; @@ -45,12 +45,12 @@ class Job implements RouterInterface * @param App $app 框架实例 * @param void */ - public function route(EasyRouter $entrance) + public function route(Router $entrance) { $entrance->app->notOutput = true; $app = $entrance->app; - $request = $app::$container->getSingle('request'); + $request = $app::$container->get('request'); $moduleName = $request->request('module'); $jobName = $request->request('job'); $actionName = $request->request('action'); diff --git a/framework/router/Micromonomer.php b/framework/router/Micromonomer.php index 1cfe75e..a6cd57e 100644 --- a/framework/router/Micromonomer.php +++ b/framework/router/Micromonomer.php @@ -12,7 +12,7 @@ namespace Framework\Router; use Framework\Router\RouterInterface; -use Framework\Router\EasyRouter; +use Framework\Router\Router; /** * 微单体路由策略. @@ -28,7 +28,7 @@ class Micromonomer implements RouterInterface * * @param void */ - public function route(EasyRouter $entrance) + public function route(Router $entrance) { # do nothing... } diff --git a/framework/router/Pathinfo.php b/framework/router/Pathinfo.php index c2dc334..e882217 100644 --- a/framework/router/Pathinfo.php +++ b/framework/router/Pathinfo.php @@ -12,7 +12,7 @@ namespace Framework\Router; use Framework\Router\RouterInterface; -use Framework\Router\EasyRouter; +use Framework\Router\Router; /** * pathinfo路由策略. @@ -26,7 +26,7 @@ class Pathinfo implements RouterInterface * * @param void */ - public function route(EasyRouter $entrance) + public function route(Router $entrance) { /* 匹配出uri */ if (strpos($entrance->requestUri, '?')) { @@ -38,7 +38,7 @@ public function route(EasyRouter $entrance) // 使用默认模块/控制器/操作逻辑 if (!isset($uri[1][0]) || empty($uri[1][0])) { // CLI 模式不输出 - if ($entrance->app->isCli === 'yes') { + if ($entrance->app->runningMode === 'cli') { $entrance->app->notOutput = true; } return; diff --git a/framework/router/Router.php b/framework/router/Router.php new file mode 100644 index 0000000..02c81d9 --- /dev/null +++ b/framework/router/Router.php @@ -0,0 +1,19 @@ + * + * * + ********************************************/ + +namespace Framework\Router; + +use Framework\App; + +Interface Router +{ + +} diff --git a/framework/router/RouterInterface.php b/framework/router/RouterInterface.php index fd033dd..53b9127 100644 --- a/framework/router/RouterInterface.php +++ b/framework/router/RouterInterface.php @@ -11,7 +11,7 @@ namespace Framework\Router; -use Framework\Router\EasyRouter; +use Framework\Router\Router; /** * 路由策略接口. @@ -25,5 +25,5 @@ * * @param void */ - public function route(EasyRouter $entrance); + public function route(Router $entrance); } diff --git a/framework/router/Userdefined.php b/framework/router/Userdefined.php index 90769c6..0615219 100644 --- a/framework/router/Userdefined.php +++ b/framework/router/Userdefined.php @@ -12,7 +12,8 @@ namespace Framework\Router; use Framework\Router\RouterInterface; -use Framework\Router\EasyRouter; +use Framework\Router\Router; +use Framework\Exceptions\CoreHttpException; /** * 自定义路由策略. @@ -118,7 +119,7 @@ public function delete($uri = '', $function = '') * * @param void */ - public function route(EasyRouter $entrance) + public function route(Router $entrance) { if ($entrance->routeStrategy === 'job') { return; @@ -134,8 +135,8 @@ public function route(EasyRouter $entrance) } $uri = "{$entrance->moduleName}/{$entrance->controllerName}/{$entrance->actionName}"; $app = $entrance->app; - $request = $app::$container->getSingle('request'); - $method = $request->method . 'Map'; + $request = $app::$container->get('request'); + $method = strtolower($request->method) . 'Map'; if (! isset($this->$method)) { throw new CoreHttpException( 404, @@ -149,7 +150,7 @@ public function route(EasyRouter $entrance) // 执行自定义路由匿名函数 $map = $this->$method; $entrance->app->responseData = $map[$uri]($app); - if ($entrance->app->isCli === 'yes') { + if ($entrance->app->runningMode === 'cli') { $entrance->app->notOutput = false; } return true; diff --git a/framework/swoole.php b/framework/swoole.php new file mode 100644 index 0000000..224f649 --- /dev/null +++ b/framework/swoole.php @@ -0,0 +1,114 @@ + * + * * + ********************************************/ + +use Framework\Handles\ErrorHandle; +use Framework\Handles\ExceptionHandle; +use Framework\Handles\EnvHandle; +use Framework\Handles\RouterSwooleHandle; +use Framework\Handles\ConfigHandle; +use Framework\Handles\LogHandle; +use Framework\Handles\NosqlHandle; +use Framework\Handles\UserDefinedHandle; +use Framework\Exceptions\CoreHttpException; +use Framework\Request; +use Framework\Response; + +/** + * 引入框架文件 + * + * Require framework + */ +require(__DIR__ . '/App.php'); + +try { + //------------------------------------------------------------------------// + // INIT // + //------------------------------------------------------------------------// + + /** + * 初始化应用 + * + * Init framework + */ + $app = new Framework\App(__DIR__ . '/..', function () { + return require(__DIR__ . '/Load.php'); + }); + // set the app running mode + $app->runningMode = 'cli'; + + //-----------------------------------------------------------------------// + // LOADING HANDLE MODULE // + //-----------------------------------------------------------------------// + + /** + * 挂载handles + * + * Load all kinds of handles + */ + $app->load(function () { + // 加载预环境参数机制 Loading env handle + return new EnvHandle(); + }); + + $app->load(function () { + // 加载预定义配置机制 Loading config handle + return new ConfigHandle(); + }); + + $app->load(function () { + // 加载日志处理机制 Loading log handle + return new LogHandle(); + }); + + $app->load(function () { + // 加载错误处理机制 Loading error handle + return new ErrorHandle(); + }); + + $app->load(function () { + // 加载异常处理机制 Loading exception handle. + return new ExceptionHandle(); + }); + + $app->load(function () { + // 加载nosql机制 Loading nosql handle + return new NosqlHandle(); + }); + + $app->load(function () { + // 加载用户自定义机制 Loading user-defined handle + return new UserDefinedHandle(); + }); + + $app->load(function () { + // 加载路由机制 Loading route handle + return new RouterSwooleHandle(); + }); + + /** + * 启动应用 + * + * Start framework + */ + $app->run(function () use ($app) { + return new Request($app); + }); + + return $app; + +} catch (CoreHttpException $e) { + /** + * 捕获异常 + * + * Catch exception + */ + $e->reponse(); +} diff --git a/public/server.php b/public/server.php new file mode 100644 index 0000000..a2700a9 --- /dev/null +++ b/public/server.php @@ -0,0 +1,68 @@ + * + * * + *************************************************/ + +use Framework\Handles\ErrorHandle; +use Framework\Handles\ExceptionHandle; +use Framework\Handles\RouterHandle; +use Framework\Handles\ConfigHandle; +use Framework\Handles\LogHandle; +use Framework\Handles\NosqlHandle; +use Framework\Handles\UserDefinedHandle; +use Framework\Exceptions\CoreHttpException; +use Framework\Request; +use Framework\Response; + +/** + * 引入框架文件 + * + * Require framework + */ +$easy = require('../framework/swoole.php'); +$config = $easy::$container->getSingle('config'); +$swooleConfig = $config->config['swoole']; +$easy->runningMode = 'swoole'; // set the app running mode + +/** + * 启动swoole http服务 + * + * Start the http server + */ +$http = new swoole_http_server('127.0.0.1', 8888); +$http->set($swooleConfig); + +/** + * 监听请求 + * + * monitor + */ +$http->on('request', function ($request, $response) use ($easy) { + try { + // reject context + $easy::$container->set('request-swoole', $request); + $easy::$container->set('response-swoole', $response); + // init router + $easy::$container->get('router')->init($easy); + // response + $easy->responseSwoole(function () use ($response) { + return $response; + }); + } catch (CoreHttpException $e) { + // exception + $e->reponseSwoole(); + } +}); + +/** + * 启动 + * + * start + */ +$http->start();