adriansuter/php-autoload-override
Composer 安装命令:
composer require --dev adriansuter/php-autoload-override
包简介
Override global scoped fully qualified function calls inside your class methods in order to be able to mock them during testing.
README 文档
README
This library allows overriding fully qualified function calls inside your class methods in order to be able to mock them during testing.
NOTE: The library can be used for other scenarios as well. But we recommend using it for testing purposes only.
Requirements
- PHP 8.2 or later
- Composer with PSR-4 (PSR-0 is not supported)
Installation
composer require --dev adriansuter/php-autoload-override ^2.0
Usage with PHPUnit
Say we want to unit test the following class Probability.
namespace My\App; class Probability { public function pick(int $probability, string $color1, string $color2): string { if (\rand(1, 100) <= $probability) { return $color1; } else { return $color2; } } }
The class uses \rand() from the global scope. Because we cannot control its output, we cannot
test pick() deterministically — until we override it.
Setting up the bootstrap
Open the bootstrap script
of your test suite and register the override. The recommended approach uses OverrideFactory:
// tests/bootstrap.php use AdrianSuter\Autoload\Override\OverrideFactory; use My\App\Probability; /** @var \Composer\Autoload\ClassLoader $classLoader */ $classLoader = require_once __DIR__ . '/../vendor/autoload.php'; OverrideFactory::create() ->forClass(Probability::class, ['rand' => \rand(...)]) ->apply($classLoader);
Each entry in forClass() maps a function name to its real implementation, written as a
first-class callable.
OverrideFactory generates the override closure automatically: when a test sets a mock value via
MockRegistry::set(), that value is returned; otherwise the real \rand() is called. No mock
value is registered initially, so non-test code is unaffected.
For multiple classes, chain forClass() calls:
OverrideFactory::create() ->forClass(Clock::class, ['time' => \time(...)]) ->forClass(Probability::class, ['rand' => \rand(...)]) ->apply($classLoader);
If you need the raw declarations array instead (e.g. for an AbstractIntegrationTestCase),
use build() instead of apply():
protected function getOverrideDeclarations(): array { return OverrideFactory::create() ->forClass(Probability::class, ['rand' => \rand(...)]) ->build(); }
Writing the test
Set a mock value with MockRegistry::set() before calling the code under test, and reset it in
tearDown() so it does not affect other tests:
namespace My\App\Tests; use AdrianSuter\Autoload\Override\MockRegistry; use My\App\Probability; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; final class ProbabilityTest extends TestCase { protected function tearDown(): void { MockRegistry::reset(Probability::class); } #[Test] public function pickReturnsSecondColorWhenRandExceedsProbability(): void { MockRegistry::set(Probability::class, 'rand', 35); $p = new Probability(); $this->assertSame('blue', $p->pick(34, 'red', 'blue')); } #[Test] public function pickReturnsFirstColorWhenRandMeetsProbability(): void { MockRegistry::set(Probability::class, 'rand', 35); $p = new Probability(); $this->assertSame('red', $p->pick(35, 'red', 'blue')); } }
MockRegistry::reset(Probability::class) clears only the overrides for that class. Call
MockRegistry::reset() without arguments to clear all registered overrides at once.
Note that these overrides are only applied during the unit tests.
Sharing an override across multiple classes
MockRegistry::set() registers an override for one specific class. To register a fallback that
applies to every class, use setGlobal():
MockRegistry::setGlobal('time', 1574333284);
If a class also has a per-class override for the same function, the per-class value takes
priority. Reset only the global overrides with MockRegistry::resetGlobal().
Using Override::apply() directly
If you register overrides via Override::apply() directly rather than using OverrideFactory,
you write the closure yourself. MockRegistry::get() takes three arguments: the class name, the
function name, and a default that is returned when no mock is registered:
Override::apply($classLoader, [ Probability::class => [ 'rand' => function (int $min, int $max): int { return MockRegistry::get(Probability::class, 'rand', \rand($min, $max)); } ] ]);
Be aware that the third argument — \rand($min, $max) — is evaluated on every call, even when a
mock value is set. This is harmless for \rand(), but if the real function is expensive or has
side effects that must be avoided when a mock is active, guard the call with MockRegistry::has():
'rand' => function (int $min, int $max): int { if (MockRegistry::has(Probability::class, 'rand')) { return MockRegistry::get(Probability::class, 'rand'); } return \rand($min, $max); }
Note: Using
$GLOBALSinside override closures still works and remains fully supported.MockRegistryis a cleaner alternative, not a replacement — existing code does not need to be migrated.
Learn More
License
The PHP-Autoload-Override library is licensed under the MIT license. See License File for more information.
adriansuter/php-autoload-override 适用场景与选型建议
adriansuter/php-autoload-override 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 65.92k 次下载、GitHub Stars 达 22, 最近一次更新时间为 2019 年 11 月 23 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「php」 「testing」 「override」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 adriansuter/php-autoload-override 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 adriansuter/php-autoload-override 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 adriansuter/php-autoload-override 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Symfony bundle which allows to override entities by using inheritance
Merge Tailwind CSS classes without style conflicts
Configuration access helper and environment manager
Testing Suite For Lumen like Laravel does.
Provides access to current date and time that can be mocked for testing purposes
Allows re-building materials from 3rd party libraries with patch
统计信息
- 总下载量: 65.92k
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 23
- 点击次数: 24
- 依赖项目数: 12
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2019-11-23