jasny / reflection-factory
PHP Reflection 抽象工厂
v1.1.2
2022-06-10 23:23 UTC
Requires
- php: >=7.4.0
Requires (Dev)
- jasny/php-code-quality: ~2.7.0
- phpunit/phpunit: ^9.0
This package is auto-updated.
Last update: 2024-09-11 04:16:16 UTC
README
当使用 PHP Reflection 进行依赖注入时使用的工厂。
为什么使用工厂而不是直接使用 new ReflectionClass()
?
依赖注入可能看起来使事情变得过于复杂。然而,它是构建可维护(和可测试)代码的关键组件。
在类中使用 new
会创建类之间的强耦合。这使得编写单元测试变得更加困难,因为没有机会模拟反射。在实践中,这意味着使用 ReflectionClass
的类只能用真实存在的类进行测试。
使用 ReflectionFactory
和依赖注入,您可以注入工厂的模拟版本。这进而允许您创建模拟的反射对象,用于非存在的类、函数、属性等。
安装
composer require jasny/reflection-factory
使用方法
use Jasny\ReflectionFactory\ReflectionFactory; $factory = new ReflectionFactory(); $reflection = $factory->reflectClass(\DateTime::class);
示例用例
不使用依赖注入
use Jasny\ReflectionFactory\ReflectionFactory; class SomeTool { public function foo(string $class) { $reflection = new ReflectionClass($class); return $reflection->getConstant('FOO'); } }
但是编写测试很困难,因为它不允许模拟。相反,我们需要创建一个 SomeToolTestFooSupport
类来仅为此功能进行测试。
class SomeToolTestFooSupport { const FOO = 10; }
在单元测试中,我们进行以下操作
use PHPUnit\Framework\TestCase; class SomeToolTest extends TestCase { public function testFoo() { $tool = new SomeTool(); $this->assertEquals(10, $tool->foo("SomeToolTestFooSupport")); } }
添加一个测试类并不那么糟糕。但是考虑我们需要为每个测试添加一个,很快就会变得混乱。
使用依赖注入
依赖注入会给类添加一点开销,因为我们需要将反射工厂传递给 SomeTool
。
use Jasny\ReflectionFactory\ReflectionFactoryInterface; class SomeTool { protected $reflectionFactory; public function __construct(ReflectionFactoryInterface $reflectionFactory) { $this->reflectionFactory = $reflectionFactory; } public function foo(string $class) { return $this->reflectionFactory->reflectClass($class)->getConstant('FOO'); } }
在单元测试中,我们模拟 ReflectionClass
和 ReflectionFactory
。测试类 FakeClass
不需要存在。
use PHPUnit\Framework\TestCase; use Jasny\ReflectionFactory\ReflectionFactoryInterface; class SomeToolTest extends TestCase { public function testFoo() { $mockReflection = $this->createMock(\ReflectionClass::class); $mockReflection->expects($this->once())->method('getConstant') ->with('FOO')->willReturn(10); $mockFactory = $this->createMock(ReflectionFactoryInterface::class); $mockFactory->expects($this->once())->method('reflectClass') ->with('FakeClass')->willReturn($mockReflection); $tool = new SomeTool($mockFactory); $this->assertEquals(10, $tool->foo("FakeClass")); } }
方法
一些 PHP 函数已被包装,因此可以进行模拟