chrisgalliano / pion
Pion 是一个轻量级的 PHP 框架
Requires
- php: 7.4.*
- ext-json: *
- guzzlehttp/psr7: 1.8.4
- psr/http-message: 1.0.1
Requires (Dev)
- roave/security-advisories: dev-master
This package is auto-updated.
Last update: 2024-09-20 14:05:44 UTC
README
Pion - 轻量级 PHP 框架。
Pion 组件
- Pion Support 插件 for PhpStorm
- Peony 模板
- Muon 表单
示例
Pion 原则
1. 最小化
Pion 仅提供基本工具集。其任务是获取用户请求、处理并返回响应。
这种设计是为了故意保护框架核心不受“多余”组件的紧密集成。简单来说——您可以毫无问题地使用您喜欢的模板/ORM/IoC 容器等。😄
备注 1: ➡️ Pion 示例,在这里您可以找到一个“即插即用”的应用程序示例,该应用程序基于 Pion + Doctrine + Symfony Console + 另一些 Symfony 组件。
备注 2: 为 Pion 开发了一个本机模板组件——Peony。它非常简单,可能不适合复杂任务。但有一些优点,例如 PhpStorm 插件 用于编译传递给视图的变量。😉
备注 3: 可能未来会开发本机 ORM/IoC 容器/Console 等 component。无论如何,它们将以单独的包的形式提供。
2. 可定制性
Pion 设计时考虑到了几乎任何内部组件都可以被自定义。
3. 魔法原则
框架的架构力求减少“魔法”。
我认为:您应该能够在任何时刻查看框架的“内部”,快速了解发生了什么。没有与“反向调用地狱”或抽象类和 yaml/array 配置的斗争。
Pion 推崇直观的流程和控制。
4. IoC/DI
此外,Pion 支持反转控制原则。这在 Arguments Resolver 子组件的示例中可见(下面将详细介绍)。简而言之——如果某个动作需要连接到数据库,应用程序必须将其 EntityManager 实例作为参数传递给它。
5. 安全可靠
是的,Pion 假设您每次都会继承 \Pion\Http\Uri\PionUri
以定义每个动作的链接。例如。但这也使您免受 GET 参数名称意外打字错误的困扰。而且修改 GET 参数也会容易得多。😄
6. 简单配置
Pion 的配置过程非常简单(这就是 lightweight 框架嘛 🙂)。配置时不会使用 yaml/json/关联数组。我坚信这是不好的做法,因为 IDE 不能在此类配置中解析键,如果您需要查看“内部”,就必须使用文本搜索来查找这些键的名称。🤦♂️
您应该能够在配置的任何位置使用“转到声明”。
Hello World
目前,作为 Hello World 示例的是 Pion 示例 仓库。您可以下载它并使用 Docker 运行,那里有说明。通过它,您可以很容易地理解框架的工作原理。
如果您想了解更多细节——请继续滚动查看此文档 😃
主要组件
应用程序
应用程序——框架的心脏。其任务
- 确定当前请求的动作
- 执行动作并返回其结果
作为配置,Application 接受 \Pion\Routing\RoutingInterface
和 \Pion\Actions\Resolver\ActionArgumentsResolverInterface
。
为了处理请求并获取响应 - 需要调用方法 \Pion\Application\ApplicationInterface::dispatch
并传入 \Pion\Http\Request\RequestInterface
。以下将介绍这些组件。⤵️
Request
任何实现 \Pion\Http\Request\RequestInterface
的类。标准实现称为 - \Pion\Http\Request\Request
。为应用程序提供 OOP-style 访问超级全局变量 $_GET
/$_POST
/$_SERVER
/$_COOKIES
。
Routing
任何实现 \Pion\Routing\RoutingInterface
的类。标准实现为 - \Pion\Routing\Routing
。在构造函数中接受一个对象数组作为配置,这些对象实现了 \Pion\Routing\Route\RouteInterface
。
RouteInterface\Pion\Routing\Route\RouteInterface
有 3 个方法
\Pion\Routing\Route\RouteInterface::path(): string
- 返回路由的 URL path。这是为了构建该路由的 URL 所必需的。\Pion\Routing\Route\RouteInterface::isSupported(RequestInterface $request): bool
- 确定当前路由能否处理传入的请求。\Pion\Routing\Route\RouteInterface::action(): \Pion\Actions\ActionInterface
- 返回该路由的处理器对象。
Actions
根据 MVC,应用程序应该有控制器来接收用户请求,执行某些业务逻辑并返回响应。通常,一个控制器可以包含多个动作,每个动作处理自己的路由。这种方法的缺点如下
- 控制器类无限制地增长
- 动作开始使用控制器内部封装的某些公共逻辑。如果需要将此类动作移动到单独的控制器,可能会成为问题。
- 如果动作在控制器对象属性中保存数据 - 这可能导致不可预见的错误。例如,动作 A 将授权用户对象放入
$this->user
。然后有人尝试在动作 B 中访问$this->user
并获得 NPE。这是一个夸张的例子,但我想大家应该明白这个道理。
考虑到这一切,在 Pion 中没有控制器 - 只有动作。Action 实现了 \Pion\Actions\ActionInterface
。
每个动作必须实现 2 个方法
\Pion\Actions\ActionInterface::route(): \Pion\Routing\Route\RouteInterface
- 返回为该动作配置的路由。\Pion\Actions\ActionInterface::__invoke(???): \Pion\Http\Response\ResponseInterface
。方法__invoke
在\Pion\Actions\ActionInterface
中没有描述,因为它可以接受任意参数集(关于这一点将在参数解析部分说明)。实际上,在这个方法中,我们处理请求,执行业务逻辑并返回将被发送给用户的响应。
参数解析
\Pion\Actions\ActionInterface::__invoke(???)
- 此方法的参数可以是任意的。Pion 使用一种称为 参数解析 的机制。本质上,它实现了 IoC(控制反转)的一个原则 - 依赖注入。如果你的动作依赖于数据库连接,那么它的签名应该如下所示
# ... public function __invoke(DbConnection $dbConnection): \Pion\Http\Response\ResponseInterface { # ... }
在初始化此动作时,Application 必须向它传递 DbConnection。Application 从哪里获得这个依赖关系?
在上面的 Application
块中,我提到 Application 的配置之一是 \Pion\Actions\Resolver\ActionArgumentsResolverInterface
。
此接口的合约中只有一个方法 - ActionArgumentsResolverInterface::resolve(ActionInterface $action): array
。其任务是确定需要传递给 __invoke
方法的参数,并返回这些参数的数组,如果它可以确定这些参数。
当然,不需要自己实现参数确定的逻辑,为此有一个标准的实现 - \Pion\Actions\Resolver\ActionArgumentsResolver
。
作为配置,需要传递一个 \Pion\Actions\Resolver\Argument\Value\ValueResolverInterface
数组。
我不会深入细节,简单地说 - ValueResolver 的任务是返回 __invoke
中的一个特定参数的值。
\Pion\Actions\Resolver\Argument\Value\ValueResolverInterface
当然有标准的实现,有两个。
ObjectValueResolver
在构造函数中接受一个对象,该对象将被解析。
RequestValueResolver
作为构造函数的参数接受 RequestInterface。能够解析 $_GET 和 $_POST 的值。
示例
假设在您的应用程序中有一个删除用户的操作。这个操作有两个依赖项 - 与数据库的连接和需要删除的用户 ID。
$request = new \Pion\Http\Request\Request(); $dbConnection = new DbConnection(...); $response = (new \Pion\Application\Application( new \Pion\Routing\Routing( DeleteUserAction::route() ), new \Pion\Actions\Resolver\ActionArgumentsResolver( new \Pion\Actions\Resolver\Argument\Value\RequestValueResolver($request), new \Pion\Actions\Resolver\Argument\Value\ObjectValueResolver($dbConnection) ) ))->dispatch($request); # ... class DeleteUserAction implements \Pion\Actions\ActionInterface { public function __invoke(DbConnection $dbConnection, string $userId) : \Pion\Http\Response\ResponseInterface { ... } }
备注:不一定必须通过 ArgumentsResolver 来处理
$_GET
/$_POST
参数。您可以直接解析请求new \Pion\Actions\Resolver\Argument\Value\ObjectValueResolver($request)
😄
响应
此接口仍在开发中,目前只提供基本功能。
任何实现 \Pion\Http\Response\ResponseInterface
。作为标准,可以使用 \Pion\Http\Response\PlainTextResponse
或 \Peony\Response\TemplatedResponse
,如果您使用的是 Peony。如果您使用其他模板引擎,建议根据示例实现 TemplatedResponse
。
URL
为了构建 URL 到操作,建议继承 \Pion\Http\Uri\PionUri
。
例如 这样。