oasys/core
最新稳定版本:v1.0.0
Composer 安装命令:
composer require oasys/core
包简介
Minimal PSR-compatible HTTP framework with routing, middleware pipeline, and exception handling
README 文档
README
Minimal HTTP framework for modern PHP.
Works with any PSR-7 messages, PSR-15 middleware, and PSR-11 container.
- Manual and attribute-based routing
- Controller and method level middleware pipeline
- Exception-to-handler mapping
- Small dependency-free kernel
Installation
Example using PHP-DI container and Guzzle's request/response:
composer require oasys/core composer require php-di/php-di composer require guzzlehttp/psr7
Quick start
public/index.php:
<?php declare(strict_types=1); use App\Controller\IndexController; use Oasys\Kernel; use Oasys\Routing\ExceptionMapper; use Oasys\Routing\Router; use DI\ContainerBuilder; use GuzzleHttp\Psr7\ServerRequest; require __DIR__ . '/../vendor/autoload.php'; // Build DI container $builder = new ContainerBuilder(); $container = $builder->build(); // Build router and register routes $router = new Router(); $router->get('/', [IndexController::class, 'home']); // Map default exception handler $exceptionMapper = new ExceptionMapper([IndexController::class, 'error']); // Build kernel $kernel = new Kernel( $container, $router, $exceptionMapper ); // Build request $request = ServerRequest::fromGlobals(); // Resolve request $response = $kernel->resolve($request); // Emit response Kernel::send($response);
src/Controller/IndexController.php:
<?php declare(strict_types=1); namespace App\Controller; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; final class IndexController { public function home(ServerRequestInterface $request): ResponseInterface { return new Response( 200, ['Content-Type' => 'text/plain; charset=utf-8'], "Welcome home\n" ); } public function error(ServerRequestInterface $request): ResponseInterface { return new Response( 500, ['Content-Type' => 'text/plain; charset=utf-8'], "Internal server error\n" ); } }
Routing
Manual routes
You can register routes manually
$router->get('/', [IndexController::class, 'home']); $router->post('/contact-form', [ContactController::class, 'send']); // put(), patch(), delete(), head(), options(), connect(), trace()
You can daisy-chain routes
$router ->get('/', [IndexController::class, 'home']) ->post('/contact-form', [ContactController::class, 'send']);
Route attributes
Alternatively, you can use attributes on controller method
use Oasys\Routing\Attributes\Get; // Post, Put, Patch, Delete, Head, Options, Connect, Trace #[Get('/')] public function home(ServerRequestInterface $request): ResponseInterface { // ... }
...and auto-wire routes
$router->bind(IndexController::class);
You can use multiple attributes on a single method
#[Post('/contact-form')] #[Put('/contact-form')] public function send(ServerRequestInterface $request): ResponseInterface { // ... }
Path aliases
You can create dynamic route using alias by registering its pattern
$router = new Router([ 'id' => '\d+', // other aliases... ]);
...and then use placeholder in the path
$router->get('/user/{id}', [UserController::class, 'show']); // or #[Get('/user/{id}')] public function show(ServerRequestInterface $request): ResponseInterface { // ... }
Middleware
You can use any PSR-15 middleware
<?php declare(strict_types=1); namespace App\Middleware; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; final class TimingMiddleware implements MiddlewareInterface { public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { $start = microtime(true); $response = $handler->handle($request); $elapsed = number_format((microtime(true) - $start) * 1000, 2); return $response->withHeader('X-Response-Time-ms', (string) $elapsed); } }
Scope
You can apply middleware using MiddlewareAttribute
Class-level attributes apply to all methods; method-level attributes apply only to that action
use Oasys\Middleware\MiddlewareAttribute as Middleware; #[Middleware(TimingMiddleware::class)] final class ProfileController { #[Middleware(AuthMiddleware::class)] public function show(ServerRequestInterface $request): ResponseInterface { // ... } }
Parameters
You can supply parameters to the middleware
#[Middleware(ContentTypeMiddleware::class, 'application/json' /* , other parameters...*/)] public function show(ServerRequestInterface $request): ResponseInterface { // ... }
...and access them in the constructor
<?php declare(strict_types=1); namespace App\Middleware; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; final class ContentTypeMiddleware implements MiddlewareInterface { public function __construct( protected string $supported // other parameters... ) {} public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { if ($request->getHeaderLine('Content-Type') !== $this->supported) { return new Response( 400, ['Content-Type' => 'text/plain'], sprintf("Bad request: required Content-Type is: %s\n", $this->supported) ); } return $handler->handle($request); } }
Exception handling
Register default handler for any exception thrown during runtime
$exceptionMapper = new ExceptionMapper([ErrorController::class, 'serverError']);
You can register individual handlers for specific exception types
$exceptionMapper->register(NotFoundException::class, [ErrorController::class, 'notFound']); $exceptionMapper->register(ValidationException::class, [ErrorController::class, 'badRequest']);
You can daisy-chain mapping
$exceptionMapper ->register(NotFoundException::class, [ErrorController::class, 'notFound']) ->register(ValidationException::class, [ErrorController::class, 'badRequest']);
When resolving a handler, ExceptionMapper will:
- use a handler registered for the exact exception class
- otherwise walk up the inheritance chain and use the first parent class that has a handler
- otherwise fall back to the default handler registered in constructor
Any exception thrown inside controllers or middleware is passed to the handler via request attribute
<?php declare(strict_types=1); namespace App\Controller; use GuzzleHttp\Psr7\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Throwable; final class ErrorController { public function serverError(ServerRequestInterface $request): ResponseInterface { /** @var Throwable|null $e */ $e = $request->getAttribute(Throwable::class); return new Response( 500, ['Content-Type' => 'text/plain; charset=utf-8'], sprintf("Internal Server Error: %s\n", $e?->getMessage()) ); } }
Summary
- Define controllers returning PSR-7
ResponseInterface - Add routing attributes to methods and auto-wire routes, or register routes manually on
Router - Use
MiddlewareAttributeto attach PSR-15 middleware to controllers and actions - Use
ExceptionMapperto send exceptions to dedicated controllers - Let
Kernelwire everything together and emit the response withKernel::send()
统计信息
- 总下载量: 2
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-06