安装数: 2,188

依赖者: 24

建议者: 0

安全: 0

星标: 4

关注者: 2

分支: 1

公开问题: 0

类型:框架

v0.1.9 2021-11-25 01:24 UTC

This package is auto-updated.

Last update: 2024-09-25 07:54:40 UTC


README

此部分可以跳过,但建议开发人员阅读。

该框架遵循极简主义,并基于三个基本原则——优雅、性能、实用主义。

性能

PHP 7 是一个性能良好的语言,但流行的框架开发者过于热衷于可替换性和通用性,同时不断增加运行时抽象,以至于没有注意到如何使一切变得混乱。通常可以看到,有大量的模块注册表,它们在每次请求时依次遍历,并且每个模块都会在状态中添加一些东西。

结果就是我们现在所看到的情况。平均网站在专用服务器上每秒只能处理大约 50 个请求(没有在 nginx 中缓存响应),该服务器占据机架上的两个单元。

零引导原理

这是 Hello world! 控制器的 backtrace,只需将其与您曾经使用过的框架中的调用链进行比较即可。您会大吃一惊。

1	0.0000	397392	{main}( )	.../index.php:0
2	0.0006	444616	Zer0\HTTP\HTTP->handleRequest( )	.../index.php:22
3	0.0008	520416	MyProject\HTTP\Controllers\Index->indexAction( )	.../HTTP.php:136

我们不执行运行时中的任何多余操作,也不执行不需要的代码。

例如,如果业务逻辑不需要执行此特定 HTTP 请求的会话,那么访问会话(从存储中读取)被视为不体面的行为。同样,如果会话数据没有变化,则不应将会话存储写入存储。

Composer 实现得如此之好,以至于连接的依赖关系可以无耻地添加文件到无条件自动加载中,因此,在 cli 目录中为 phinx 等不用于 Web 部分的包创建了单独的 composer.json。在 cli 中,性能无关紧要,并且没有问题连接任何东西,而我们的主要应用程序则保持干净。

PHP 不再会死亡

历史上,PHP 被视为在请求处理完成后完全重置其状态的解释器。然而,更有效的选项是真正的 FastCGI,其中 bootstrap 阶段在工作进程执行一次后,然后是进入请求的顺序处理。这就是 FastCGI 中“Fast”的含义。而经典的 CGI 则没有一次性执行 bootstrap 阶段的能力。

  • 我们不使用 exit() 和 die()
  • 我们使用异常来代替致命错误。
  • 常量不应该是请求相关的。

接近 PHP

在大多数框架中(我们不会指出具体哪个),要访问请求参数,需要几十个类,创建一大堆对象,然后调用一个方法,该方法调用另一个方法,该方法调用另一个方法,该方法最终访问参数集合,检查是否存在参数并返回值或默认值 $default。这非常低效,不直观且庞大。

我们简单地写入 $_GET['name'] ?? 'John Doe'。是的,在某个时候没有操作符 ??,必须到处携带 isset() 或使用辅助方法。但那些日子已经过去了。

测试

单元和集成测试是很好的。代码覆盖的测试越多,破坏的机会就越小,并且不会注意到。但是,测试必须是快速的,最重要的是支持多线程执行。

实用主义

对 PHP 版本的态度

我们始终针对最新的稳定版 PHP(目前为 7.2.10)进行优化,不关注旧版本的支持,这样我们就可以使用最新的功能,同时避免使用 PHP_VERSION 条件。

代码风格

我们不浪费时间手动维护代码风格,也不争论哪种风格更好。

在开发环境中,make fmt 队伍(fmt 的目标也包含在 all 中)会自动格式化所有 PHP、JS 和 CSS 源代码。

类型化

在开发框架时,我们几乎在所有情况下都坚持严格类型化的原则。也就是说,函数/方法应该指定参数类型和返回值类型。例如,

public function validate(?string $token = null): bool

这可以避免许多错误。同时,强烈建议在每个文件的开始处指定 declare(strict_types=1);

我们几乎从不使用 loose comparison(运算符 ==!=)。少数例外是当需要按类型和属性而不是按引用比较两个对象时。

此外,我们不将字符串转换为 boolean、float 和 integer,因为这会导致 PHP 历史上不正确的识别。例如,

php > var_dump(('1helloWorld' == 1);
bool(true)

这可能在处理用户输入时导致不良后果。

代理

本质上,它们是组件和库的工厂。例如,$app->factory('Redis') 将返回一个 Redis 驱动器对象,其设置来自 conf/Redis。get() 方法接受一个可选参数,指定配置名称,这使得可以拥有多个同一组件的配置。

有些代理在第一次创建后存储对象,例如 PDOSessionStorage。而其他代理,如 Session,在每次调用 get() 时都会创建一个新的对象。

添加自己的代理

需要将以下内容添加到 Main 配置中

brokers:
  MyCustomBroker: \My\Custom\Broker

并创建一个继承自 \Zer0\Brokers\Base 的相应类。

同样,也可以替换 \Zer0\Brokers\* 中不需要在配置中声明的代理。