Skip to content

Commit

Permalink
Fail nicely on enum FQCNs
Browse files Browse the repository at this point in the history
  • Loading branch information
derrabus committed Mar 2, 2022
1 parent 16d01f9 commit 227caa3
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 14 deletions.
9 changes: 9 additions & 0 deletions phpcs.xml.dist
Expand Up @@ -51,4 +51,13 @@
<exclude-pattern>src/Doctrine/Instantiator/Exception/ExceptionInterface.php</exclude-pattern>
<exclude-pattern>src/Doctrine/Instantiator/InstantiatorInterface.php</exclude-pattern>
</rule>

<rule ref="Generic.WhiteSpace.ScopeIndent.Incorrect">
<!-- see https://github.com/squizlabs/PHP_CodeSniffer/issues/3474 -->
<exclude-pattern>tests/DoctrineTest/InstantiatorTestAsset/SimpleEnumAsset.php</exclude-pattern>
</rule>
<rule ref="Generic.WhiteSpace.ScopeIndent.IncorrectExact">
<!-- see https://github.com/squizlabs/PHP_CodeSniffer/issues/3474 -->
<exclude-pattern>tests/DoctrineTest/InstantiatorTestAsset/SimpleEnumAsset.php</exclude-pattern>
</rule>
</ruleset>
14 changes: 11 additions & 3 deletions src/Doctrine/Instantiator/Exception/InvalidArgumentException.php
Expand Up @@ -17,11 +17,11 @@ class InvalidArgumentException extends BaseInvalidArgumentException implements E
public static function fromNonExistingClass(string $className): self
{
if (interface_exists($className)) {
return new self(sprintf('The provided type "%s" is an interface, and can not be instantiated', $className));
return new self(sprintf('The provided type "%s" is an interface, and cannot be instantiated', $className));
}

if (trait_exists($className)) {
return new self(sprintf('The provided type "%s" is a trait, and can not be instantiated', $className));
return new self(sprintf('The provided type "%s" is a trait, and cannot be instantiated', $className));
}

return new self(sprintf('The provided class "%s" does not exist', $className));
Expand All @@ -35,8 +35,16 @@ public static function fromNonExistingClass(string $className): self
public static function fromAbstractClass(ReflectionClass $reflectionClass): self
{
return new self(sprintf(
'The provided class "%s" is abstract, and can not be instantiated',
'The provided class "%s" is abstract, and cannot be instantiated',
$reflectionClass->getName()
));
}

public static function fromEnum(string $className): self
{
return new self(sprintf(
'The provided class "%s" is an enum, and cannot be instantiated',
$className
));
}
}
7 changes: 7 additions & 0 deletions src/Doctrine/Instantiator/Instantiator.php
Expand Up @@ -12,13 +12,16 @@
use Serializable;

use function class_exists;
use function enum_exists;
use function is_subclass_of;
use function restore_error_handler;
use function set_error_handler;
use function sprintf;
use function strlen;
use function unserialize;

use const PHP_VERSION_ID;

final class Instantiator implements InstantiatorInterface
{
/**
Expand Down Expand Up @@ -148,6 +151,10 @@ private function getReflectionClass(string $className): ReflectionClass
throw InvalidArgumentException::fromNonExistingClass($className);
}

if (PHP_VERSION_ID >= 80100 && enum_exists($className, false)) {
throw InvalidArgumentException::fromEnum($className);
}

$reflection = new ReflectionClass($className);

if ($reflection->isAbstract()) {
Expand Down
Expand Up @@ -33,7 +33,7 @@ public function testFromNonExistingTypeWithTrait(): void
$exception = InvalidArgumentException::fromNonExistingClass(SimpleTraitAsset::class);

self::assertSame(
sprintf('The provided type "%s" is a trait, and can not be instantiated', SimpleTraitAsset::class),
sprintf('The provided type "%s" is a trait, and cannot be instantiated', SimpleTraitAsset::class),
$exception->getMessage()
);
}
Expand All @@ -44,7 +44,7 @@ public function testFromNonExistingTypeWithInterface(): void

self::assertSame(
sprintf(
'The provided type "%s" is an interface, and can not be instantiated',
'The provided type "%s" is an interface, and cannot be instantiated',
InstantiatorInterface::class
),
$exception->getMessage()
Expand All @@ -58,7 +58,7 @@ public function testFromAbstractClass(): void

self::assertSame(
sprintf(
'The provided class "%s" is abstract, and can not be instantiated',
'The provided class "%s" is abstract, and cannot be instantiated',
AbstractClassAsset::class
),
$exception->getMessage()
Expand Down
24 changes: 16 additions & 8 deletions tests/DoctrineTest/InstantiatorTest/InstantiatorTest.php
Expand Up @@ -14,13 +14,15 @@
use DoctrineTest\InstantiatorTestAsset\PharExceptionAsset;
use DoctrineTest\InstantiatorTestAsset\SerializableArrayObjectAsset;
use DoctrineTest\InstantiatorTestAsset\SerializableFinalInternalChildAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleEnumAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleSerializableAsset;
use DoctrineTest\InstantiatorTestAsset\SimpleTraitAsset;
use DoctrineTest\InstantiatorTestAsset\UnCloneableAsset;
use DoctrineTest\InstantiatorTestAsset\UnserializeExceptionArrayObjectAsset;
use DoctrineTest\InstantiatorTestAsset\WakeUpNoticesAsset;
use DoctrineTest\InstantiatorTestAsset\XMLReaderAsset;
use Exception;
use Generator;
use PDORow;
use PharException;
use PHPUnit\Framework\TestCase;
Expand All @@ -29,6 +31,8 @@
use function str_replace;
use function uniqid;

use const PHP_VERSION_ID;

/**
* Tests for {@see \Doctrine\Instantiator\Instantiator}
*
Expand Down Expand Up @@ -142,15 +146,19 @@ public function getInstantiableClasses(): array
/**
* Provides a list of instantiable classes (existing)
*
* @return string[][]
* @psalm-return Generator<string, array{string}>
*/
public function getInvalidClassNames(): array
public function getInvalidClassNames(): Generator
{
return [
[self::class . str_replace('.', '', uniqid('', true))],
[InstantiatorInterface::class],
[AbstractClassAsset::class],
[SimpleTraitAsset::class],
];
yield 'invalid string' => [self::class . str_replace('.', '', uniqid('', true))];
yield 'interface' => [InstantiatorInterface::class];
yield 'abstract class' => [AbstractClassAsset::class];
yield 'trait' => [SimpleTraitAsset::class];

if (PHP_VERSION_ID < 80100) {
return;
}

yield 'enum' => [SimpleEnumAsset::class];
}
}
9 changes: 9 additions & 0 deletions tests/DoctrineTest/InstantiatorTestAsset/SimpleEnumAsset.php
@@ -0,0 +1,9 @@
<?php

namespace DoctrineTest\InstantiatorTestAsset;

enum SimpleEnumAsset
{
case Foo;
case Bar;
}

0 comments on commit 227caa3

Please sign in to comment.