From 5dca1409d025830f222b1a58c602ad0f20b5c395 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 26 Feb 2024 23:32:56 +0100 Subject: [PATCH 1/3] Make ClassLike::from return type more strict --- src/PhpGenerator/ClassLike.php | 5 ++--- tests/PhpGenerator/ClassType.from.82.phpt | 3 ++- tests/PhpGenerator/ClassType.from.phpt | 9 +++++---- tests/PhpGenerator/ClassType.from.trait.phpt | 6 +++--- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/PhpGenerator/ClassLike.php b/src/PhpGenerator/ClassLike.php index ce49782d..1491ae2a 100644 --- a/src/PhpGenerator/ClassLike.php +++ b/src/PhpGenerator/ClassLike.php @@ -37,15 +37,14 @@ abstract class ClassLike private ?PhpNamespace $namespace; private ?string $name; - - public static function from(string|object $class, bool $withBodies = false): self + public static function from(string|object $class, bool $withBodies = false): static { return (new Factory) ->fromClassReflection(new \ReflectionClass($class), $withBodies); } - public static function fromCode(string $code): self + public static function fromCode(string $code): static { return (new Factory) ->fromClassCode($code); diff --git a/tests/PhpGenerator/ClassType.from.82.phpt b/tests/PhpGenerator/ClassType.from.82.phpt index eb171d5d..cdb1f850 100644 --- a/tests/PhpGenerator/ClassType.from.82.phpt +++ b/tests/PhpGenerator/ClassType.from.82.phpt @@ -7,11 +7,12 @@ declare(strict_types=1); use Nette\PhpGenerator\ClassType; +use Nette\PhpGenerator\TraitType; require __DIR__ . '/../bootstrap.php'; require __DIR__ . '/fixtures/classes.82.php'; $res[] = ClassType::from(new Abc\Class13); -$res[] = ClassType::from(Abc\Trait13::class); +$res[] = TraitType::from(Abc\Trait13::class); sameFile(__DIR__ . '/expected/ClassType.from.82.expect', implode("\n", $res)); diff --git a/tests/PhpGenerator/ClassType.from.phpt b/tests/PhpGenerator/ClassType.from.phpt index 43734a5e..583faf19 100644 --- a/tests/PhpGenerator/ClassType.from.phpt +++ b/tests/PhpGenerator/ClassType.from.phpt @@ -7,15 +7,16 @@ declare(strict_types=1); use Nette\PhpGenerator\ClassType; +use Nette\PhpGenerator\InterfaceType; use Nette\PhpGenerator\Factory; require __DIR__ . '/../bootstrap.php'; require __DIR__ . '/fixtures/classes.php'; -$res[] = ClassType::from(Abc\Interface1::class); -$res[] = ClassType::from(Abc\Interface2::class); -$res[] = ClassType::from(Abc\Interface3::class); -$res[] = ClassType::from(Abc\Interface4::class); +$res[] = InterfaceType::from(Abc\Interface1::class); +$res[] = InterfaceType::from(Abc\Interface2::class); +$res[] = InterfaceType::from(Abc\Interface3::class); +$res[] = InterfaceType::from(Abc\Interface4::class); $res[] = ClassType::from(Abc\Class1::class); $res[] = ClassType::from(new Abc\Class2); $obj = new Abc\Class3; diff --git a/tests/PhpGenerator/ClassType.from.trait.phpt b/tests/PhpGenerator/ClassType.from.trait.phpt index 3fdf8b24..1f62a4b0 100644 --- a/tests/PhpGenerator/ClassType.from.trait.phpt +++ b/tests/PhpGenerator/ClassType.from.trait.phpt @@ -2,7 +2,7 @@ declare(strict_types=1); -use Nette\PhpGenerator\ClassType; +use Nette\PhpGenerator\ClassLike; require __DIR__ . '/../bootstrap.php'; require __DIR__ . '/fixtures/traits.php'; @@ -19,11 +19,11 @@ $classes = [ Class5::class, ]; -$res = array_map(fn($class) => ClassType::from($class), $classes); +$res = array_map(fn($class) => ClassLike::from($class), $classes); sameFile(__DIR__ . '/expected/ClassType.from.trait-use.expect', implode("\n", $res)); -$res = array_map(fn($class) => ClassType::from($class, withBodies: true), $classes); +$res = array_map(fn($class) => ClassLike::from($class, withBodies: true), $classes); sameFile(__DIR__ . '/expected/ClassType.from.trait-use.bodies.expect', implode("\n", $res)); From cca65d8e22bdcce568933d09631f7c4cac51ebe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Mon, 26 Feb 2024 23:49:27 +0100 Subject: [PATCH 2/3] Throw exception instead of relying on PHP type error --- src/PhpGenerator/ClassLike.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/PhpGenerator/ClassLike.php b/src/PhpGenerator/ClassLike.php index 1491ae2a..23728897 100644 --- a/src/PhpGenerator/ClassLike.php +++ b/src/PhpGenerator/ClassLike.php @@ -39,15 +39,27 @@ abstract class ClassLike public static function from(string|object $class, bool $withBodies = false): static { - return (new Factory) + $class = (new Factory) ->fromClassReflection(new \ReflectionClass($class), $withBodies); + + if (!$class instanceof static) { + throw new Nette\InvalidArgumentException("Object '$class' is not an instance of " . static::class); + } + + return $class; } public static function fromCode(string $code): static { - return (new Factory) + $class = (new Factory) ->fromClassCode($code); + + if (!$class instanceof static) { + throw new Nette\InvalidArgumentException("Object '$class' is not an instance of " . static::class); + } + + return $class; } From 129d0ad2c9abc6afb21016daf4cc7a8d8df46236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Thu, 7 Mar 2024 12:23:59 +0100 Subject: [PATCH 3/3] Improve exception message and add test --- src/PhpGenerator/ClassLike.php | 17 +++++++------ tests/PhpGenerator/ClassLike.typecheck.phpt | 28 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 tests/PhpGenerator/ClassLike.typecheck.phpt diff --git a/src/PhpGenerator/ClassLike.php b/src/PhpGenerator/ClassLike.php index 23728897..a459d05f 100644 --- a/src/PhpGenerator/ClassLike.php +++ b/src/PhpGenerator/ClassLike.php @@ -39,27 +39,28 @@ abstract class ClassLike public static function from(string|object $class, bool $withBodies = false): static { - $class = (new Factory) + $instance = (new Factory) ->fromClassReflection(new \ReflectionClass($class), $withBodies); - if (!$class instanceof static) { - throw new Nette\InvalidArgumentException("Object '$class' is not an instance of " . static::class); + if (!$instance instanceof static) { + $class = is_object($class) ? get_class($class) : $class; + throw new Nette\InvalidArgumentException("'$class' cannot be represented with " . static::class . ". Call " . get_class($instance) . "::" . __FUNCTION__ . "() or " . __METHOD__ . "() instead."); } - return $class; + return $instance; } public static function fromCode(string $code): static { - $class = (new Factory) + $instance = (new Factory) ->fromClassCode($code); - if (!$class instanceof static) { - throw new Nette\InvalidArgumentException("Object '$class' is not an instance of " . static::class); + if (!$instance instanceof static) { + throw new Nette\InvalidArgumentException("Provided code cannot be represented with " . static::class . ". Call " . get_class($instance) . "::" . __FUNCTION__ . "() or " . __METHOD__ . "() instead."); } - return $class; + return $instance; } diff --git a/tests/PhpGenerator/ClassLike.typecheck.phpt b/tests/PhpGenerator/ClassLike.typecheck.phpt new file mode 100644 index 00000000..7085540c --- /dev/null +++ b/tests/PhpGenerator/ClassLike.typecheck.phpt @@ -0,0 +1,28 @@ +