dg/bypass-finals

GitHub: dg/bypass-finals

一个 PHP 测试辅助库,通过在运行时移除 final 和 readonly 关键字,解除对最终类和方法的 Mock 限制。

Stars: 573 | Forks: 35

[![bypass-finals](https://static.pigsec.cn/wp-content/uploads/repos/cas/9f/9fb30684316bb029c66ea7b9a1cbef62b2c085ee4d2612d4fec1ec580592e21a.png)](https://phpfashion.com/en/how-to-mock-final-classes) [![本月下载量](https://img.shields.io/packagist/dm/dg/bypass-finals.svg)](https://packagist.org/packages/dg/bypass-finals) [![测试](https://static.pigsec.cn/wp-content/uploads/repos/cas/1e/1eb60c96331bf3b781460d138431e9ebaef63f0625894915fb88fc86344652c8.svg)](https://github.com/dg/bypass-finals/actions) [![最新稳定版本](https://poser.pugx.org/dg/bypass-finals/v/stable)](https://github.com/dg/bypass-finals/releases) [![许可证](https://img.shields.io/badge/license-New%20BSD-blue.svg)](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://files.nette.org/icons/donation-1.svg?)](https://nette.org/make-donation?to=bypass-finals)
标签:ffuf, Mock测试, OpenVAS, PHP, PHPUnit, 代码预处理, 单元测试, 测试工具