diff --git a/src/Factories/ImmutableFactory.php b/src/Factories/ImmutableFactory.php index f15041c..b6303f5 100644 --- a/src/Factories/ImmutableFactory.php +++ b/src/Factories/ImmutableFactory.php @@ -54,7 +54,7 @@ abstract public function definition(): array; * @param array $attributes * @return TClass */ - abstract protected function instance(array $attributes): mixed; + abstract protected function instance(array $attributes): object; private function resolveValue(mixed $value): mixed { diff --git a/src/Factories/InstanceFactory.php b/src/Factories/InstanceFactory.php new file mode 100644 index 0000000..36371b2 --- /dev/null +++ b/src/Factories/InstanceFactory.php @@ -0,0 +1,35 @@ + */ + private string $classFQN, + ) {} + + /** + * @param array $attributes + * @return TClass + */ + public function make(array $attributes): object + { + $instance = new ReflectionClass($this->classFQN)->newInstanceWithoutConstructor(); + + foreach ($attributes as $attribute => $value) { + new ReflectionProperty($this->classFQN, $attribute)->setValue($instance, $value); + } + + return $instance; + } +} + diff --git a/src/Factories/InstanceFactoryTest.php b/src/Factories/InstanceFactoryTest.php new file mode 100644 index 0000000..e8ad155 --- /dev/null +++ b/src/Factories/InstanceFactoryTest.php @@ -0,0 +1,78 @@ +expectException(ReflectionException::class); + + new InstanceFactory($subject::class)->make(['nonsense' => true]); + } + + #[Test] + public function itCanConstructInstances(): void + { + $attributes = [ + 'public' => 'Public', + 'protected' => 'Protected', + 'private' => 'Private', + ]; + $subject = new readonly class(...$attributes) + { + public function __construct( + public string $public, + protected string $protected, + private string $private, + ) {} + + public function protected(): string + { + return $this->protected; + } + + public function private(): string + { + return $this->private; + } + }; + + $instance = new InstanceFactory($subject::class)->make($attributes); + + $this->assertSame($attributes['public'], $instance->public); + $this->assertSame($attributes['protected'], $instance->protected()); + $this->assertSame($attributes['private'], $instance->private()); + } + + #[Test] + public function itConstructsInstancesWithUninitializedPropertiesWhenNotProvidingAttributes(): void + { + $subject = new readonly class('some-id') + { + public function __construct( + public string $id, + ) {} + }; + + $result = new InstanceFactory($subject::class)->make([]); + + $this->assertInstanceOf($subject::class, $result); + $this->assertFalse(new ReflectionProperty($subject::class, 'id')->isInitialized($result)); + } +}