diff --git a/src/Core/Injector/InjectionCreator.php b/src/Core/Injector/InjectionCreator.php index 0c70e3b23..ad91f11d2 100644 --- a/src/Core/Injector/InjectionCreator.php +++ b/src/Core/Injector/InjectionCreator.php @@ -2,18 +2,36 @@ namespace SilverStripe\Core\Injector; +use InvalidArgumentException; + /** * A class for creating new objects by the injector. */ class InjectionCreator implements Factory { + /** + * Create a new instance of a class + * + * Passing an object for $class will result from using an anonymous class in unit testing, e.g. + * Injector::inst()->load([SomeClass::class => ['class' => new class { ... }]]); + * + * @param string|object $class - string: The FQCN of the class, object: A class instance + */ public function create($class, array $params = []) { - if (!class_exists($class ?? '')) { + if (is_object($class ?? '')) { + $class = get_class($class); + } + if (!is_string($class ?? '')) { + throw new InvalidArgumentException('$class parameter must be a string or an object'); + } + if (!class_exists($class)) { throw new InjectorNotFoundException("Class {$class} does not exist"); } + // Ensure there are no string keys as they cannot be unpacked with the `...` operator - $values = array_values($params ?? []); + $values = array_values($params); + return new $class(...$values); } } diff --git a/tests/php/Core/Injector/InjectorTest.php b/tests/php/Core/Injector/InjectorTest.php index b06b0fc87..85aa7a3ff 100644 --- a/tests/php/Core/Injector/InjectorTest.php +++ b/tests/php/Core/Injector/InjectorTest.php @@ -1155,4 +1155,27 @@ class InjectorTest extends SapphireTest Injector::unnest(); $this->nestingLevel--; } + + public function testAnonymousClass() + { + Injector::inst()->load([ + 'Some\\Project\\Class' => [ + // the php anonymous class syntax will instantiate a new anonymous class object, with ('abc') + // passed to the constructor + 'class' => new class ('abc') { + private string $property; + public function __construct(string $value) + { + $this->property = $value; + } + public function foo(): string + { + return $this->property; + } + } + ], + ]); + // assert that Injector creates a new instance of the anonymous class, with ('def') passed to the constructor + $this->assertSame('def', Injector::inst()->create('Some\\Project\\Class', 'def')->foo()); + } }