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

说明

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

体验

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

安装

composer require naka1205/phpkoa
复制代码

使用

Hello World

<?php
require __DIR__ . '/vendor/autoload.php';

use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Application;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Context;

$app = new Application();

$app->υse(function(Context $ctx) {
$ctx->status = 200;
$ctx->body = “<h1>Hello World</h1>”;
});

$app->listen(3000);

复制代码

Error

<?php
require __DIR__ . '/vendor/autoload.php';

use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Application;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Context;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Error;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Timeout;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Router;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>NotFound;

$app = new Application();

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

$router = new Router();

// 正常访问
$router->get(‘/hello’, function(Context $ctx, $next) {
$ctx->status = 200;
$ctx->body = “<h1>Hello World</h1>”;
});

// 访问超时
$router->get(‘/timeout’, function(Context $ctx, $next) {
yield async_sleep(5);
});

// 访问出错
$router->get(‘/error’, function(Context $ctx, $next) {
$ctx->thrοw(500, “Internal Error”);
yield;
});

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

$app->listen(3000);

复制代码

Router

<?php
require __DIR__ . '/vendor/autoload.php';

define(‘DS’, DIRECTORY_SEPARATOR);

use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Application;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Context;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Error;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Timeout;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Router;

$app = new Application();
$app->υse(new Error());
$app->υse(new Timeout(5));

$router = new Router();
$router->get(‘/demo1’, function(Context $ctx, $next) {
$ctx->body = “demo1”;
});
$router->get(‘/demo2’, function(Context $ctx, $next) {
$ctx->body = “demo2”;
});
$router->get(‘/demo3/(\d+)’, function(Context $ctx, $next, $vars) {
$ctx->status = 200;
$ctx->body = “demo3={$vars[0]}”;
});
$router->get(‘/demo4’, function(Context $ctx, $next) {
$ctx->redirect(“/demo2”);
});

//RESTful API
$router->post(‘/demo3/(\d+)’, function(Context $ctx, $next, $vars) {
$ctx->status = 200;
$ctx->body = “post:demo3={$vars[0]}”;
});
$router->put(‘/demo3/(\d+)’, function(Context $ctx, $next, $vars) {
$ctx->status = 200;
$ctx->body = “put:demo3={$vars[0]}”;
});
$router->delete(‘/demo3/(\d+)’, function(Context $ctx, $next, $vars) {
$ctx->status = 200;
$ctx->body = “delete:demo3={$vars[0]}”;
});

// 文件上传
$router->post(‘/files/(\d+)’, function(Context $ctx, $next, $vars) {
$upload_path = DIR . DS . “uploads” . DS;
if (!is_dir($upload_path) ) {
mkdir ($upload_path , 0777, true);
}
$files = [];
foreach ( $ctx->request->files as $key => $value) {
if ( !$value[‘file_name’] || !$value[‘file_data’] ) {
continue;
}
$file_path = $upload_path . $value[‘file_name’];
file_put_contents($file_path, $value[‘file_data’]);
$value[‘file_path’] = $file_path;
$files[] = $value;
}

$ctx-&gt;status = <span class="hljs-number">200</span>;
$ctx-&gt;body = json_encode($files);

});

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

$app->listen(3000);

复制代码
<?php
// 此处已省略 ... 

// 此处使用第三方 HTTP 客户端类库,方便测试
use GuzzleHttp<span class=“hljs-title”>Client;

$router = new Router();

// 路由分组
//http://127.0.0.1:5000/curl/get
//http://127.0.0.1:5000/curl/post
//http://127.0.0.1:5000/curl/put
//http://127.0.0.1:5000/curl/delete
$router->mount(‘/curl’, function() use ($router) {
$client = new Client();
$router->get(‘/get’, function(Context $ctx, $next) use ($client) {
$r = (yield $client->request(‘GET’, http://127.0.0.1:3000/demo3/1));
$ctx->status = $r->getStatusCode();
$ctx->body = $r->getBody();
});

$router-&gt;get(<span class="hljs-string">'/post'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(Context $ctx, $next )</span> <span class="hljs-title">use</span> <span class="hljs-params">($client)</span></span>{
    $r = (<span class="hljs-keyword">yield</span> $client-&gt;request(<span class="hljs-string">'POST'</span>, <span class="hljs-string">'http://127.0.0.1:3000/demo3/2'</span>));
    $ctx-&gt;status = $r-&gt;getStatusCode();
    $ctx-&gt;body = $r-&gt;getBody();
});

$router-&gt;get(<span class="hljs-string">'/put'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">( Context $ctx, $next )</span> <span class="hljs-title">use</span> <span class="hljs-params">($client)</span></span>{
    $r = (<span class="hljs-keyword">yield</span> $client-&gt;request(<span class="hljs-string">'PUT'</span>, <span class="hljs-string">'http://127.0.0.1:3000/demo3/3'</span>));
    $ctx-&gt;status = $r-&gt;getStatusCode();
    $ctx-&gt;body = $r-&gt;getBody();
});

$router-&gt;get(<span class="hljs-string">'/delete'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">( Context $ctx, $next )</span> <span class="hljs-title">use</span> <span class="hljs-params">($client)</span></span>{
    $r = (<span class="hljs-keyword">yield</span> $client-&gt;request(<span class="hljs-string">'DELETE'</span>, <span class="hljs-string">'http://127.0.0.1:3000/demo3/4'</span>));
    $ctx-&gt;status = $r-&gt;getStatusCode();
    $ctx-&gt;body = $r-&gt;getBody();
});

});

//http://127.0.0.1:5000/files
$router->get(‘/files’, function(Context $ctx, $next) {
$client = new Client();
$r = ( yield $client->request(‘POST’, http://127.0.0.1:3000/files/2, [
‘multipart’ => [
[
‘name’ => ‘file_name’,
‘contents’ => fopen( DIR . ‘/file.txt’, ‘r’)
],
[
‘name’ => ‘other_file’,
‘contents’ => ‘hello’,
‘filename’ => ‘filename.txt’,
‘headers’ => [
‘X-Foo’ => ‘this is an extra header to include’
]
]
]
]));

$ctx-&gt;status = $r-&gt;getStatusCode();
$ctx-&gt;body = $r-&gt;getBody();

});

// $router->get(‘/curl/(\w+)’, function(Context $ctx, $next, $vars) {
// $method = strtoupper($vars[0]);
// $client = new Client();
// $r = (yield $client->request($method, ‘http://127.0.0.1:3000/demo3/123’));
// $ctx->status = $r->getStatusCode();
// $ctx->body = $r->getBody();
// });

$app->υse($router->routes());
$app->listen(5000);

复制代码

Template

<body>
    <h1>{title}</h1>
    <p>{time}</p>
</body>
复制代码
<?php
require __DIR__ . '/vendor/autoload.php';

use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Application;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Context;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Error;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Timeout;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Router;

$app = new Application();
$app->υse(new Error());
$app->υse(new Timeout(5));

$router = new Router();
$router->get(‘/hello’, function(Context $ctx) {
$ctx->status = 200;
$ctx->state[“title”] = “HELLO WORLD”;
$ctx->state[“time”] = date(“Y-m-d His”, time());;
yield $ctx->render(DIR . “/hello.html”);
});
$app->υse($router->routes());

$app->listen(3000);

复制代码
<body>
    <p>{title}</p>
    <table border=1>
      <tr><td>Name</td><td>Age</td></tr>
  <span class="hljs-comment">&lt;!-- BEGIN INFO --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span> {name} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span> {age} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- END INFO --&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>

</body>

复制代码
<?php
// 此处已省略 ... 

// 一维数组
$router->get(‘/info’, function(Context $ctx) {
$info = array(“name” => “小明”, “age” => 15);
$ctx->status = 200;
$ctx->state[“title”] = “这是一个学生信息”;
$ctx->state[“info”] = $info;
yield $ctx->render(DIR . “/info.html”);
});

复制代码
<body>
    <p>{title}</p>
    <table border=1>
      <tr><td>Name</td><td>Age</td></tr>
  <span class="hljs-comment">&lt;!-- BEGIN TABLE --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span> {name} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span> {age} <span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- END TABLE --&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">table</span>&gt;</span>

</body>

复制代码
<?php
// 此处已省略 ... 

// 二维数组
$router->get(‘/table’, function(Context $ctx) {
$table = array(
array(“name” => “小明”, “age” => 15),
array(“name” => “小花”, “age” => 13),
array(“name” => “小刚”, “age” => 17)
);
$ctx->status = 200;
$ctx->state[“title”] = “这是一个学生名单”;
$ctx->state[“table”] = $table;
yield $ctx->render(DIR . “/table.html”);
});

复制代码

中间件

静态文件处理 中间件 PHPKoa Static

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>PHPkoa Static</title>
    <link rel="stylesheet" href="/css/default.css">
</head>
<body>
    <img src="/images/20264902.jpg" />
</body>
</html>
复制代码
<?php
require __DIR__ . '/vendor/autoload.php';

defined(‘DS’) or define(‘DS’, DIRECTORY_SEPARATOR);

use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Application;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Context;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Error;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Timeout;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>NotFound;
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>Router;
// 静态文件处理 中间件
use Naka507<span class=“hljs-title”>Koa<span class=“hljs-title”>StaticFiles;

$app = new Application();
$app->υse(new Error());
$app->υse(new Timeout(5));
$app->υse(new NotFound());
$app->υse(new StaticFiles(DIR . DS . “static” ));

$router = new Router();

$router->get(‘/index’, function(Context $ctx, $next) {
$ctx->status = 200;
yield $ctx->render(DIR . “/index.html”);
});

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

$app->listen(3000);

复制代码
  • php

    PHP(PHP:Hypertext Preprocessor)是一种在电脑上执行的脚本语言,主要是用途在于处理动态网页,也包含了命令列执行接口(command line interface),或者产生图形使用…

    21 引用
感谢    赞同    分享    收藏    关注    反对    举报    ...