经过多年开发与打磨,Yii 3 正式发布了。Yii 框架始终秉承着一致的原则:高性能、灵活且具备良好默认值、注重实践、简单、明确且一致。Yii 3 亦不例外。
虽然 Yii 1.1 和 Yii 2.0 是优秀的框架,但 Yii 3 的诞生旨在进一步改进,解决前代存在的一些缺点:
- Yii 2.0 曾有一个相对封闭的生态系统,配置通用的 PHP 包较为困难。
- 一些“魔法”和隐式行为,例如 Yii 2.0 中引入的对象非标准 PHP 行为。
- 由于向后兼容性的限制,未能完全实现 PHP 标准兼容性和现代 PHP 的用法。
- 存在一些反模式,例如开箱即用的服务定位器,从长远看影响项目的可测试性与可维护性。
下面我们将总结这个备受期待的新版本中的一些亮点。如果你想立即上手体验,可以查看 入门指南。
独立的包
与 Yii 1.1 和 Yii 2.0 的单体框架不同,Yii 3 是一个包含超过 130 个官方包的包生态系统。这些包既可以单独用于任何 PHP 项目中,也可以组合在一起作为一个完整的框架使用,类似于 Yii 2.0 或 Yii 1.1。为此,应用模板提供了极大的便利。
应用模板
开箱即用提供了三种应用模板:
- Web — 用于经典的服务器端渲染应用。
- API — 用于构建 API。
- Console — 用于仅限命令行的工具和后台工作者。
与 Yii 2.0 不同,这些模板非常精简。你将从已经预连接好的基本路由、配置、DI 容器和环境变量开始。但同时,诸如连接数据库等额外功能默认并未包含在模板中。只安装你需要的部分——没有臃肿,只有你需要的解决方案。
能够使用任何包
不同于 Yii 2.0 主要聚焦于 Yii 特定的扩展,我们让框架能够与 Packagist 上的任何 PHP 包良好协作,无论它们是遵循 PSR 标准的、Symfony 包,还是通用的 PHP 代码。依赖注入容器能够配置它们中的任何一个。
Yii 3 拥抱整个 PHP 生态系统,而非重复造轮子。它与任何 PHP 库都能无缝集成。没有供应商锁定,也没有专有 API。只有现代 PHP 标准,让你能充分利用整个生态系统的创新成果。
一流的 DI 容器
框架的核心是其依赖注入(DI)容器。它将所有独立的包组合在一起,自动解析依赖关系并帮助你获取所需的类。其用法通常非常简单明了:
[
// 接口到类的映射
EngineInterface::class => EngineMarkOne::class,
// 详细配置
MyServiceInterface::class => [
'class' => MyService::class,
'__construct()' => [
42
],
'setDiscount()' => [
10
],
],
// 工厂闭包
'api' => static fn(ApiConfig $config) => new ApiClient($config),
];
// 依赖基于类型提示自动注入
final readonly class MyController
{
public function __construct(private CacheInterface $cache){}
}
这个容器的另一个优势是速度极快,并且在运行时工作。你的配置就是实际执行的内容,因此没有任何“魔法”,你甚至可以使用 XDebug 逐步调试它。
配置
延续 Yii 2.0 配置事物的传统方式,我们提炼了高级应用中包含的内容,支持多环境、配置覆盖等。Yii 3 中的配置非常强大,基本上可以适配遵循任何项目布局的结构。
如果需要,应用模板默认提供了分为 Web(或 API)和 Console 的配置,以及一些常见的共享配置。配置主要分为两个部分:DI 容器配置(用于将配置的类映射到接口)和参数(用于配置这些类)。
'yiisoft/view' => [
'basePath' => null,
'parameters' => [
'assetManager' => Reference::to(AssetManager::class),
'applicationParams' => Reference::to(ApplicationParams::class),
'aliases' => Reference::to(Aliases::class),
'urlGenerator' => Reference::to(UrlGeneratorInterface::class),
'currentRoute' => Reference::to(CurrentRoute::class),
],
],
'yiisoft/yii-view-renderer' => [
'viewPath' => null,
'layout' => '@src/Web/Shared/Layout/Main/layout.php',
'injections' => [
Reference::to(CsrfViewInjection::class),
],
],
安全
与 Yii 1.1 和 Yii 2.0 一样,我们非常重视安全。每个包在实现时都考虑了安全性,例如呈现层和数据库抽象层。
其功能包括:
- 访问控制抽象
- RBAC(基于角色的访问控制)实现
- JWT 认证
- 用户应用抽象
- 处理代理链和头部的中间件
- 第三方认证客户端。
此外,还有用于常见安全相关操作的助手,例如 CSRF 保护包。文档中设有专门的安全指南页面,并包含了已建立的安全响应流程。
数据库
Yii 2.0 拥有出色的数据库抽象层。首先,我们将其提取到单独的包中,然后重新构想并改进了它。其结果就是 yiisoft/db,它提供了数据库访问、模式管理和强大的查询构建器。额外的工具和存储(如迁移、数据库缓存等)基于 DB 包构建,还有更明确但仍保持高速的 Active Record 实现。
$posts = $connection
->select(['id', 'title', 'created_at'])
->from('{{%posts}}')
->where(['status' => 'published'])
->andWhere(['>', 'views', 1000])
->orderBy(['created_at' => SORT_DESC])
->limit(10)
->all();
除了我们自己的数据库层,你也可以使用 Cycle ORM 或 Doctrine,通过 PDO 或原生驱动程序进行查询。无论你喜欢什么方式,Yii 3 都不会强迫你坚持单一的实现。
数据抽象
强大的数据抽象层 yiisoft/data,以及为其提供的组件(如网格视图),非常适合构建功能强大的通用管理后台。该抽象包括了数据格式化、分页、排序,并能够将任何数据源与任何操作/呈现方式结合使用,反之亦然。
缓存
缓存系统比 Yii 2.0 更先进。首先,开箱即用就提供了缓存雪崩保护。其次,缓存驱动程序兼容 PSR-16 标准。这意味着你可以使用任何遵循 PSR-16 的实现来对接特定存储,并且能立即工作。
我们的团队已经实现了以下后端:
- APCu
- DB
- Files
- Memcached
- Redis
标准优先
与缓存类似,框架在更多方面利用了 PSR 接口:
- 日志记录,因此你可以坚持使用 Yii 的日志记录器,或者如果愿意,也可以用 Monolog 替换它。
- 中间件,因此你可以从 Packagist 引入无数解决方案(例如 CORS 处理),而无需更改代码。
- 请求-响应抽象,允许最佳的测试和工作模式。
- 甚至 DI 容器也可以被替换或与其他 PSR-11 兼容的容器结合使用。
这种标准优先的架构确保了你的代码保持可移植性和面向未来,同时又能完全访问现代 PHP 工具。
工作模式
在传统的 PHP 服务器中,框架初始化和数据库连接为每个请求执行,这对性能不利。Yii 3 可以与 RoadRunner、Swoole 或 FrankenPHP 一起在工作模式下运行。在这种模式下,它只初始化一次,然后为多个请求-响应周期提供服务,从而显著降低响应时间。
虽然这种模式很棒,但状态在多个请求-响应处理之间很大程度上是共享的,因此开发者应注意隔离状态(或根本不存储状态)以及潜在的内存泄漏。Yii 3 在这方面提供了很大帮助:所有包都被设计为不依赖任何状态,或在每个请求开始时正确重置它。
经典 Web 应用的一切
并非每个项目都必须是带有客户端的 API,因此经典服务器渲染 Web 应用所需的一切都可用:小部件、视图(支持 Twig 等模板引擎)、表单、资产管理、HTML 助手等。
此外,还提供了现成的 Bootstrap 5 和 Bulma 小部件。
构建 API 的工具集
Yii 3 提供了许多帮助构建 API 的工具:
- 数据响应器,负责数据呈现。
- Swagger 支持。
我们计划在未来添加更多工具,但当前的集合已经足以构建强大的 API。
HTTP 层和网络
Yii 3 在 HTTP 层上的工作比以前版本更精确,并遵循 PSR 接口。在这些相对底层的接口之上,提供了方便的抽象:
- HTTP 助手,用于定义响应代码等。
- Cookies
- 下载响应工厂,允许从应用发送文件。
此外,还提供了用于处理 IP 协议的网络实用程序。
用户输入和验证器
Yii 3 拥有一个强大的验证器,它由属性驱动,能够从 HTTP(通过 input-http 包)或其他地方填充表单数据,并提供了处理表单的工具等。
<?php
declare(strict_types=1);
namespace App\Web\Echo;
use Yiisoft\FormModel\FormModel;
use Yiisoft\Validator\Label;
use Yiisoft\Validator\Rule\Length;
final class Form extends FormModel
{
#[Label('The message to be echoed')]
#[Length(min: 2)]
public string $message = '';
}
助手
框架提供了各种各样的助手,用以简化常见的编程任务。
国际化
由于 Yii 框架社区和团队成员来自世界各地,我们非常重视国际化并深刻理解其重要性。
Yii 3 开箱即用支持:
- 使用 intl 扩展驱动的 ICU 格式进行消息翻译。
- 视图层的国际化支持。
- 路由器的国际化支持。
测试
适当的依赖倒置使得对使用 Yii 3 创建的代码进行单元测试变得容易。遵循 PSR 标准的请求和响应允许你在不实际运行 HTTP 服务器的情况下进行 API 测试。
为了进一步简化测试,yiisoft/test-support 包提供了一套测试专用的 PSR 实现集合。
错误处理
我们重视开发者的时间。这就是为什么我们关注错误信息和错误页面。所有这些都力求实用。错误信息提供上下文,我们绝不会仅使用“Error”作为消息。此外,我们通过“友好的异常”将其提升到了新的水平。在开发模式下,这些异常在渲染时会附带信息块,解释错误发生的原因以及如何可能修复它。未来,我们计划尝试提供一个按钮来自动应用修复。
错误页面会包含错误详情。对于堆栈跟踪的每个级别,它都会显示源代码。发生错误的行会被高亮显示。属于框架包的堆栈跟踪部分默认会被折叠,因为这些包经过了充分测试,问题不太可能出在那里。
错误处理器本身,即 yiisoft/error-handler,比 Yii 2 的更有趣。它可以处理内存不足错误和致命错误,能将某些异常类型映射到自定义异常,并以不同格式响应等。
此外,还有一个用于集成 Sentry 进行错误收集的包。
以上便是 Yii 3.0 带来的主要革新。它标志着这个经典的 PHP 框架正式迈入了现代、模块化与标准化的新阶段,为开发者提供了前所未有的灵活性与强大的生态系统支持。更多深入的技术解析和实践案例,欢迎访问 云栈社区 与广大开发者一同探讨。