歡迎感興趣的開發(fā)者參與開發(fā)
Github: https://github.com/next-laboratory/simple
php >= 8.0
composer create-project next/simple
php bin/workerman.php start
swoole/workerman
server {
server_name www.domain.com;
listen 80;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "keep-alive";
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if (!-f $request_filename) {
proxy_pass http://127.0.0.1:9501;
}
}
}
FPM
server {
server_name www.domain.com;
listen 80;
root /data/project/public;
index index.html index.php;
location / {
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
}
}
location ~ ^(.+\.php)(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
框架提供了env和config兩個(gè)函數(shù),可以方便獲取配置,如果你使用了AOP包,還可以直接使用注解將配置注入示例
class User
{
#[\Next\Config\Annotations\Config(key: 'qcloud.user.secret_key', default = '123')]
protected string $secretKey;
}
如上secretKey將會(huì)被自動(dòng)注入,如果配置文件中不存在,則默認(rèn)123
在app/Http/Kernel.php
的map
方法中注冊路由,注冊方式請參考next/routing組件文檔,或者使用注解方式
#[Controller(prefix: 'index', middleware: [BasicAuthentication::class])]
class Index
{
#[GetMapping(path: '/user/{id}\.html')]
public function index(\Psr\Http\Message\ServerRequestInterface $request, $id)
{
return new \Next\Http\Message\Response(200, [], 'Hello, world!');
}
}
上面的代碼定義了一個(gè) Index 控制器,并使用 Controller 注解設(shè)置了路由的前綴為 index, 該控制器中全部方法的中間件為BasicAuthentication::class
, 并且使用GetMapping
注解定義了一個(gè)路由,path
為/user/{id}.html
, 那么實(shí)際請求的地址可以為/index/user/1.html
, 支持的注解如下,分別對應(yīng)了不同的請求方法,其中RequestMapping對應(yīng)的請求方法默認(rèn)為GET
,POST
,HEAD
,可使用method
參數(shù)來自定義
class IntexController {
#[GetMapping(path: '/{id}')]
public functin index(ServerRequestInterface $request, $id) {
// Do something.
}
}
控制器是單例對象,和路由對應(yīng)的方法支持依賴注入,并且參數(shù)名為request
的參數(shù)會(huì)被注入當(dāng)前請求類,該類不是單例,對于每個(gè)請求都是獨(dú)立的。路由參數(shù)會(huì)被按照參數(shù)名注入,其他有類型提示的參數(shù)也會(huì)被注入
請求可以是任何實(shí)現(xiàn)了Psr的ServerRequestInterface實(shí)例
請使用
App\Http\ServerRequest
,該類繼承Next\Http\Message\ServerRequest
類,是實(shí)現(xiàn)了Psr7 ServerRequest
的請求類,并且附加了一些簡單的方法,開發(fā)者可以自定義相關(guān)方法
$request->getHeaderLine($name): string
$request->head($name): string
上面兩個(gè)方法會(huì)返回請求頭字符串,header
方法返回值 getHeaderLine
是一樣的
$request->server($name): string // 一條
$request->getServerParams(): array // 全部
獲取$_SERVER
中的值
$request->isMethod($method): bool
不區(qū)分大小寫的方式判斷請求方式是否一致
$request->url(bool $full = false): string
返回請求的地址,$full
為true
,則返回完整地址
$request->cookie(string $name): string // 單條
$request->getCookieParams(): array // 全部
獲取請求的Cookie,一般也可以直接從Header
中獲取
$request->isAjax(): bool
判斷當(dāng)前請求是否是Ajax
請求, 注意:有部分前端框架在發(fā)送Ajax請求的時(shí)候并沒有發(fā)送X_REQUESTED_WITH頭,所以這個(gè)方法會(huì)返回false
$request->is(string $path): bool
判斷當(dāng)前請求的path
是否和給定的path
匹配,支持正則
$request->get($key = null, $default = null) // $_GET
$request->post($key = null, $default = null) // $_POST
$request->all() // $_GET + $_POST
$request->input($key = null, $default = null, ?array $from = null) // $_GET + $_POST
獲取請求的參數(shù),這些參數(shù)是通過PHP全局變量加載進(jìn)來的,當(dāng)$key為null的時(shí)候會(huì)返回全部參數(shù),如果為字符串會(huì)返回單個(gè),如果不存在返回default,如果$key是數(shù)組,則會(huì)返回多個(gè)參數(shù),$default此時(shí)可以為數(shù)組,數(shù)組的鍵為參數(shù)鍵,數(shù)組的值為參數(shù)的默認(rèn)值
例如
$request->get('a');
可以給第二個(gè)參數(shù)傳入一個(gè)默認(rèn)值,例如
$request->get('a','default');
獲取多個(gè)參數(shù)可以使用
$request->get(['a','b']);
可以傳入一個(gè)關(guān)聯(lián)數(shù)組,數(shù)組的鍵為參數(shù)名,值為默認(rèn)值,例如
$request->get(['a', 'b'], ['a' => 1]);
此時(shí)如果a
不存在,則a
的值為1
$request->getUploadedFiles();
$request->file("name");
中間件基于
Psr15
實(shí)現(xiàn),在App\Http\Kernel
中的$middlewares
數(shù)組中注冊的為全局的中間件,例如請求異常處理,路由服務(wù),Session初始化,CSRF校驗(yàn)等等
首先需要?jiǎng)?chuàng)建一個(gè)中間件,例如
<?php
namespace App\Http\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class Login implement MiddlewareInterface
{
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// 前置操作
$response = $handler->handle($request);
// 后置操作
return $response;
}
#[Controller(prefix: '/', middleware(TestMiddleware::class))]
class Index {
#[GetMapping(path: '/', middlewares: [Test2Middleware::class])]
public function index() {
// Do something.
}
}
上面的注解定義了兩個(gè)中間件,控制器Index中的方法都注冊了TestMiddleware
中間件,index
方法不僅包含TestMiddleware
, 還包含Test2Middleware
中間件。
Session可以使用
File
,Redis
驅(qū)動(dòng)
Session配置文件如下
<?php
return [
'name' => 'NextPHP_SESSION_ID',
'handler' => [
'class' => '\Next\Session\Handlers\File',
'options' => [
'path' => env('storage_path') . 'session',
'ttl' => 3600,
]
],
'cookie_expire' => time() + 3600,
];
當(dāng)前請求的session需要在中間件中創(chuàng)建,所以需要開啟SessionMiddleware。開啟后將session放入Request屬性中,在控制器中使用
public function index(App\Http\ServerRequest $request)
{
$session = $request->session();
$session = $request->getAttribute(\Next\Session\Session::class);
}
你也可以自己定義session的存儲位置,但是要保證協(xié)程間隔離。如果使用workerman,還可以直接使用其提供的session
$session->has($name): bool
$session->get($name)
$session->set($name, $value): bool
可以是數(shù)組或者字符串
$session->pull($name): bool
$session->remove($name): bool
$session->destory(): bool
框架繼承了filp/whoops,可以很方便地查看異常情況,使用前需要添加異常處理類Next\Framework\Exceptions\Handlers\WhoopsExceptionHandler
到App/Http/Middlewares/ExceptionHandleMiddleware
中間件中
如果沒有安裝,需要執(zhí)行下面的命令安裝
composer require filp/whoops
打印變量使用了symfony/var-dumper組件,但是為了兼容多種環(huán)境,建議使用d
函數(shù)代替dump
,dd
函數(shù)。使用前需要添加異常處理類Next\Framework\Exceptions\Handlers\VarDumperAbortHandler
到App/Http/Middlewares/ExceptionHandleMiddleware
中間件中
d(mixed ...$vars)
如果你沒有安裝symfony/var-dumper
,需要先安裝
composer require symfony/var-dumper
你可以傳入多個(gè)變量,如果使用swoole/workerman,需要重啟服務(wù)
特別注意:異常處理使用中間件的方式,中間件未處理的異常需要用戶手動(dòng)處理,所以在中間件外執(zhí)行的代碼不能使用d函數(shù)打印變量
推薦使用下面的擴(kuò)展包
支持一下