dg/bypass-finals
GitHub: dg/bypass-finals
一个 PHP 测试辅助库,通过在运行时移除 final 和 readonly 关键字,解除对最终类和方法的 Mock 限制。
Stars: 573 | Forks: 35
[](https://phpfashion.com/en/how-to-mock-final-classes)
[](https://packagist.org/packages/dg/bypass-finals)
[](https://github.com/dg/bypass-finals/actions)
[](https://github.com/dg/bypass-finals/releases)
[](https://github.com/dg/bypass-finals/blob/master/license.md)
## 简介
**BypassFinals** 能够在运行时轻松去除 PHP 代码中的 `final` 和 `readonly` 关键字。
这个实用的工具使得 mock final 方法和类成为可能,并能与 PHPUnit、Mockery 或 [Nette Tester](https://tester.nette.org) 等流行的测试框架无缝集成。
## 安装
安装 BypassFinals 最简单的方法是通过 Composer。只需在您的项目目录中运行以下命令:
```
composer require dg/bypass-finals --dev
```
## 用法
要启动并运行 BypassFinals,只需调用:
```
DG\BypassFinals::enable();
```
请确保尽早调用此方法,最好是在加载 `vendor/autoload.php` 之后立即调用,以确保所有类在被使用之前都已处理。
请注意,像 `Closure` 这样的 PHP 内部 final 类是无法被 mock 的。
如果不想移除 `readonly` 关键字,您可以通过传递参数来禁用此功能:
```
DG\BypassFinals::enable(bypassReadOnly: false);
```
要缩小 BypassFinals 的应用范围,请使用白名单来指定目录或文件:
```
DG\BypassFinals::allowPaths([
'*/Nette/*',
]);
```
或者相反,您可以使用 `DG\BypassFinals::denyPaths()` 指定不搜索的路径。
这能为您提供更精细的控制,并能解决某些框架和库的兼容问题。
通过缓存转换后的文件来提升性能。请确保缓存目录已经存在:
```
DG\BypassFinals::setCacheDirectory(__DIR__ . '/cache');
```
要与 PHPUnit 10 或更高版本集成,只需在您的 PHPUnit XML 配置文件中将 BypassFinals 添加为扩展:
```
```
您可以选择在您的 `phpunit.xml` 文件中配置 BypassFinals:
```
```
## 故障排除
**启用 BypassFinals 后类仍然是 final 的**
BypassFinals 只能从*在调用 `enable()` 之后*加载的文件中去除 `final` 关键字。如果某个类在此之前已经被加载——例如通过某个包的 `autoload` 配置中的 `files` 条目,在执行 `require 'vendor/autoload.php'` 时被 Composer 加载——那么该类将保持 final 状态。
要解决此问题,请在您的测试 bootstrap 文件中*先于* `vendor/autoload.php` 引入 `src/bootstrap.php`:
```
// tests/bootstrap.php
require __DIR__ . '/../vendor/dg/bypass-finals/src/bootstrap.php';
require __DIR__ . '/../vendor/autoload.php';
```
这会足够早地激活 stream wrapper,以便拦截自动加载期间加载的每个文件。
如果您遇到 BypassFinals 无法按预期工作的其他问题,可以使用 `debugInfo()` 方法来深入了解其内部状态。调用此方法将输出有价值的信息,以帮助诊断问题:
```
DG\BypassFinals::debugInfo();
```
这将显示:
- 配置:BypassFinals 是否已启用移除 `final` 和/或 `readonly` 关键字。
- BypassFinals 启动调用堆栈:导致 `DG\BypassFinals::enable()` 的函数调用序列,帮助您验证 BypassFinals 是何时以及在何处启动的。
- BypassFinals 启动前加载的类:在 BypassFinals 启动之前已经在 PHP 中加载的类列表。由于这些类已经定义,因此无法移除其中的关键字。这有助于识别潜在的冲突或某些类未被修改的原因。
- 已修改的文件:BypassFinals 已成功修改的文件列表。如果您期望被修改的类所在的文件不在此列表中,则说明路径匹配或 BypassFinals 的启动时机存在问题。
通过检查这些输出信息,您可以更好地了解 BypassFinals 的配置情况,以及它是否在目标文件和类上生效。这可以显著加快识别和解决问题的速度。
## 支持项目
[](https://nette.org/make-donation?to=bypass-finals)
标签:ffuf, Mock测试, OpenVAS, PHP, PHPUnit, 代码预处理, 单元测试, 测试工具