PHP异步编程: 基于 PHP 实(chao)现(xi) NODEJS web框架 KOA

Posted 掘金开发者社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHP异步编程: 基于 PHP 实(chao)现(xi) NODEJS web框架 KOA相关的知识,希望对你有一定的参考价值。

php异步编程: 基于 PHP 实(chao)现(xi) NODEJS web框架KOA

说明

偶然间在 GITHUB 上看到有赞官方仓库的 手把手教你实现co与Koa 。由于此前用过 KOA ,对于 KOA 的洋葱模型叹为观止。不由得心血来潮的看完了整个文档,接着 CTRL+C、 CTRL+V 让代码跑了起来。 文档中是基于 swoole 扩展进行开发,而 swoole 对 WINDOWS 并不友好,向来习惯在 WINDOWS 下开发的我一鼓作气,将Workerman 改写并兼容了此项目。

体验

PHPKoa Demo 是使用 PHPKoa 开发 HTTP SERVER 的一个简单示例!

安装

 
   
   
 
  1. composer require naka1205/phpkoa

使用

Hello World

 
   
   
 
  1. <?php

  2. require __DIR__ . '/vendor/autoload.php';


  3. use Naka507\Koa\Application;

  4. use Naka507\Koa\Context;


  5. $app = new Application();


  6. $app->υse(function(Context $ctx) {

  7.    $ctx->status = 200;

  8.    $ctx->body = "<h1>Hello World</h1>";

  9. });


  10. $app->listen(3000);

Error

 
   
   
 
  1. <?php

  2. require __DIR__ . '/vendor/autoload.php';


  3. use Naka507\Koa\Application;

  4. use Naka507\Koa\Context;

  5. use Naka507\Koa\Error;

  6. use Naka507\Koa\Timeout;

  7. use Naka507\Koa\Router;

  8. use Naka507\Koa\NotFound;


  9. $app = new Application();


  10. $app->υse(new Error());

  11. $app->υse(new NotFound());

  12. $app->υse(new Timeout(3)); //设置3秒超时


  13. $router = new Router();


  14. //正常访问

  15. $router->get('/hello', function(Context $ctx, $next) {

  16.    $ctx->status = 200;

  17.    $ctx->body = "<h1>Hello World</h1>";

  18. });


  19. //访问超时

  20. $router->get('/timeout', function(Context $ctx, $next) {

  21.    yield async_sleep(5);

  22. });


  23. //访问出错

  24. $router->get('/error', function(Context $ctx, $next) {

  25.    $ctx->thrοw(500, "Internal Error");

  26.    yield;

  27. });


  28. $app->υse($router->routes());


  29. $app->listen(3000);

Router

 
   
   
 
  1. <?php

  2. require __DIR__ . '/vendor/autoload.php';


  3. define('DS', DIRECTORY_SEPARATOR);


  4. use Naka507\Koa\Application;

  5. use Naka507\Koa\Context;

  6. use Naka507\Koa\Error;

  7. use Naka507\Koa\Timeout;

  8. use Naka507\Koa\Router;


  9. $app = new Application();

  10. $app->υse(new Error());

  11. $app->υse(new Timeout(5));


  12. $router = new Router();

  13. $router->get('/demo1', function(Context $ctx, $next) {

  14.    $ctx->body = "demo1";

  15. });

  16. $router->get('/demo2', function(Context $ctx, $next) {

  17.    $ctx->body = "demo2";

  18. });

  19. $router->get('/demo3/(\d+)', function(Context $ctx, $next, $vars) {

  20.    $ctx->status = 200;

  21.    $ctx->body = "demo3={$vars[0]}";

  22. });

  23. $router->get('/demo4', function(Context $ctx, $next) {

  24.    $ctx->redirect("/demo2");

  25. });


  26. //RESTful API

  27. $router->post('/demo3/(\d+)', function(Context $ctx, $next, $vars) {

  28.    //设置 session

  29.    $ctx->setSession('demo3',$vars[0]);

  30.    //设置 cookie

  31.    $ctx->setCookie('demo3',$vars[0]);

  32.    $ctx->status = 200;

  33.    $ctx->body = "post:demo3={$vars[0]}";

  34. });

  35. $router->put('/demo3/(\d+)', function(Context $ctx, $next, $vars) {


  36.    //获取单个 cookie

  37.    $cookie_demo3 = $ctx->getCookie('demo3');

  38.    //或者

  39.    $cookies = $ctx->cookies['demo3'];


  40.    //获取单个 session

  41.    $session_demo3 = $ctx->getSession('demo3');

  42.    //或者

  43.    $session = $ctx->session['demo3'];


  44.    $ctx->status = 200;

  45.    $ctx->body = "put:demo3={$vars[0]}";

  46. });

  47. $router->delete('/demo3/(\d+)', function(Context $ctx, $next, $vars) {

  48.    //清除所有 cookie

  49.    $ctx->clearCookie();

  50.    //清除所有 session

  51.    $ctx->clearSession();

  52.    $ctx->status = 200;

  53.    $ctx->body = "delete:demo3={$vars[0]}";

  54. });


  55. //文件上传

  56. $router->post('/files/(\d+)', function(Context $ctx, $next, $vars) {

  57.    $upload_path = __DIR__ . DS .  "uploads" . DS;

  58.    if ( !is_dir($upload_path) ) {

  59.        mkdir ($upload_path , 0777, true);

  60.    }

  61.    $files = [];

  62.    foreach ( $ctx->request->files as $key => $value) {

  63.        if ( !$value['file_name'] || !$value['file_data'] ) {

  64.            continue;

  65.        }

  66.        $file_path = $upload_path . $value['file_name'];

  67.        file_put_contents($file_path, $value['file_data']);

  68.        $value['file_path'] = $file_path;

  69.        $files[] = $value;

  70.    }


  71.    $ctx->status = 200;

  72.    $ctx->body = json_encode($files);

  73. });



  74. $app->υse($router->routes());


  75. $app->listen(3000);

 
   
   
 
  1. <?php

  2. //此处已省略 ...


  3. //使用第三方 HTTP 客户端类库,方便测试

  4. use GuzzleHttp\Client;


  5. $router = new Router();


  6. //路由分组

  7. //http://127.0.0.1:5000/curl/get

  8. //http://127.0.0.1:5000/curl/post

  9. //http://127.0.0.1:5000/curl/put

  10. //http://127.0.0.1:5000/curl/delete

  11. $router->mount('/curl', function() use ($router) {

  12.    $client = new Client();

  13.    $router->get('/get', function( Context $ctx, $next ) use ($client) {

  14.        $r = (yield $client->request('GET', 'http://127.0.0.1:3000/demo3/1'));

  15.        $ctx->status = $r->getStatusCode();

  16.        $ctx->body = $r->getBody();

  17.    });


  18.    $router->get('/post', function(Context $ctx, $next ) use ($client){

  19.        $r = (yield $client->request('POST', 'http://127.0.0.1:3000/demo3/2'));

  20.        $ctx->status = $r->getStatusCode();

  21.        $ctx->body = $r->getBody();

  22.    });


  23.    $router->get('/put', function( Context $ctx, $next ) use ($client){

  24.        $r = (yield $client->request('PUT', 'http://127.0.0.1:3000/demo3/3'));

  25.        $ctx->status = $r->getStatusCode();

  26.        $ctx->body = $r->getBody();

  27.    });


  28.    $router->get('/delete', function( Context $ctx, $next ) use ($client){

  29.        $r = (yield $client->request('DELETE', 'http://127.0.0.1:3000/demo3/4'));

  30.        $ctx->status = $r->getStatusCode();

  31.        $ctx->body = $r->getBody();

  32.    });

  33. });


  34. //http://127.0.0.1:5000/files

  35. $router->get('/files', function(Context $ctx, $next ) {

  36.    $client = new Client();

  37.    $r = ( yield $client->request('POST', 'http://127.0.0.1:3000/files/2', [

  38.        'multipart' => [

  39.            [

  40.                'name'     => 'file_name',

  41.                'contents' => fopen( __DIR__ . '/file.txt', 'r')

  42.            ],

  43.            [

  44.                'name'     => 'other_file',

  45.                'contents' => 'hello',

  46.                'filename' => 'filename.txt',

  47.                'headers'  => [

  48.                    'X-Foo' => 'this is an extra header to include'

  49.                ]

  50.            ]

  51.        ]

  52.    ]));


  53.    $ctx->status = $r->getStatusCode();

  54.    $ctx->body = $r->getBody();

  55. });


  56. // $router->get('/curl/(\w+)', function(Context $ctx, $next, $vars) {

  57. //     $method = strtoupper($vars[0]);

  58. //     $client = new Client();

  59. //     $r = (yield $client->request($method, 'http://127.0.0.1:3000/demo3/123'));

  60. //     $ctx->status = $r->getStatusCode();

  61. //     $ctx->body = $r->getBody();

  62. // });


  63. $app->υse($router->routes());

  64. $app->listen(5000);

Template

 
   
   
 
  1. <body>

  2.    <h1>{title}</h1>

  3.    <p>{time}</p>

  4. </body>

 
   
   
 
  1. <?php

  2. require __DIR__ . '/vendor/autoload.php';


  3. use Naka507\Koa\Application;

  4. use Naka507\Koa\Context;

  5. use Naka507\Koa\Error;

  6. use Naka507\Koa\Timeout;

  7. use Naka507\Koa\Router;


  8. $app = new Application();

  9. $app->υse(new Error());

  10. $app->υse(new Timeout(5));


  11. $router = new Router();

  12. $router->get('/hello', function(Context $ctx) {

  13.    $ctx->status = 200;

  14.    $ctx->state["title"] = "HELLO WORLD";

  15.    $ctx->state["time"] = date("Y-m-d H:i:s", time());;

  16.    yield $ctx->render(__DIR__ . "/hello.html");

  17. });

  18. $app->υse($router->routes());


  19. $app->listen(3000);

 
   
   
 
  1. <body>

  2.    <p>{title}</p>

  3.    <table border=1>

  4.      <tr><td>Name</td><td>Age</td></tr>


  5.      <!-- BEGIN INFO -->

  6.      <tr>

  7.        <td> {name} </td>

  8.        <td> {age} </td>

  9.      </tr>

  10.      <!-- END INFO -->


  11.    </table>

  12. </body>

 
   
   
 
  1. <?php

  2. //此处已省略 ...


  3. //一维数组

  4. $router->get('/info', function(Context $ctx) {

  5.    $info = array("name" => "小明", "age" => 15);

  6.    $ctx->status = 200;

  7.    $ctx->state["title"] = "这是一个学生信息";

  8.    $ctx->state["info"] = $info;

  9.    yield $ctx->render(__DIR__ . "/info.html");

  10. });

 
   
   
 
  1. <body>

  2.    <p>{title}</p>

  3.    <table border=1>

  4.      <tr><td>Name</td><td>Age</td></tr>


  5.      <!-- BEGIN TABLE -->

  6.      <tr>

  7.        <td> {name} </td>

  8.        <td> {age} </td>

  9.      </tr>

  10.      <!-- END TABLE -->


  11.    </table>

  12. </body>

 
   
   
 
  1. <?php

  2. //此处已省略 ...


  3. //二维数组

  4. $router->get('/table', function(Context $ctx) {

  5.    $table = array(

  6.        array("name" => "小明", "age" => 15),

  7.        array("name" => "小花", "age" => 13),

  8.        array("name" => "小刚", "age" => 17)

  9.    );

  10.    $ctx->status = 200;

  11.    $ctx->state["title"] = "这是一个学生名单";

  12.    $ctx->state["table"] = $table;

  13.    yield $ctx->render(__DIR__ . "/table.html");

  14. });

中间件

静态文件处理 中间件 PHPKoa Static

 
   
   
 
  1. <!DOCTYPE html>

  2. <html lang="en">

  3. <head>

  4.    <meta charset="UTF-8">

  5.    <title>PHPkoa Static</title>

  6.    <link rel="stylesheet" href="/css/default.css">

  7. </head>

  8. <body>

  9.    <img src="/images/20264902.jpg" />

  10. </body>

  11. </html>

 
   
   
 
  1. <?php

  2. require __DIR__ . '/vendor/autoload.php';


  3. defined('DS') or define('DS', DIRECTORY_SEPARATOR);


  4. use Naka507\Koa\Application;

  5. use Naka507\Koa\Context;

  6. use Naka507\Koa\Error;

  7. use Naka507\Koa\Timeout;

  8. use Naka507\Koa\NotFound;

  9. use Naka507\Koa\Router;

  10. //静态文件处理 中间件

  11. use Naka507\Koa\StaticFiles;


  12. $app = new Application();

  13. $app->υse(new Error());

  14. $app->υse(new Timeout(5));

  15. $app->υse(new NotFound());

  16. $app->υse(new StaticFiles(__DIR__ . DS .  "static" ));


  17. $router = new Router();


  18. $router->get('/index', function(Context $ctx, $next) {

  19.    $ctx->status = 200;

  20.    yield $ctx->render(__DIR__ . "/index.html");

  21. });


  22. $app->υse($router->routes());


  23. $app->listen(3000);


以上是关于PHP异步编程: 基于 PHP 实(chao)现(xi) NODEJS web框架 KOA的主要内容,如果未能解决你的问题,请参考以下文章

PHP中实现异步调用多线程程序代码

5分钟了解PHP异步编程

PHP Swoole 异步并行编程(韩天峰)

php 异步上传图片几种方法总结

Atitit. Async await 优缺点 异步编程的原理and实现 java c# php

异步 celery 任务完成后自动调用 PHP 代码(celery-php)