Skip to content

Commit

Permalink
Make ClassLike::from return type assert the subclass type (BC break) (
Browse files Browse the repository at this point in the history
  • Loading branch information
GromNaN authored and dg committed Mar 7, 2024
1 parent dec0711 commit af74f21
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 10 deletions.
17 changes: 15 additions & 2 deletions src/PhpGenerator/ClassLike.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,28 @@ abstract class ClassLike

public static function from(string|object $class, bool $withBodies = false): self
{
return (new Factory)
$instance = (new Factory)
->fromClassReflection(new \ReflectionClass($class), $withBodies);

if (!$instance instanceof static) {
$class = is_object($class) ? $class::class : $class;
trigger_error("$class cannot be represented with " . static::class . '. Call ' . $instance::class . '::' . __FUNCTION__ . '() or ' . __METHOD__ . '() instead.', E_USER_WARNING);
}

return $instance;
}


public static function fromCode(string $code): self
{
return (new Factory)
$instance = (new Factory)
->fromClassCode($code);

if (!$instance instanceof static) {
trigger_error('Provided code cannot be represented with ' . static::class . '. Call ' . $instance::class . '::' . __FUNCTION__ . '() or ' . __METHOD__ . '() instead.', E_USER_WARNING);
}

return $instance;
}


Expand Down
36 changes: 36 additions & 0 deletions tests/PhpGenerator/ClassLike.typecheck.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\InterfaceType;
use Nette\PhpGenerator\TraitType;
use Tester\Assert;

require __DIR__ . '/../bootstrap.php';
require __DIR__ . '/fixtures/classes.php';


Assert::error(
fn() => ClassType::from(Abc\Interface1::class),
E_USER_WARNING,
'Abc\Interface1 cannot be represented with Nette\PhpGenerator\ClassType. Call Nette\PhpGenerator\InterfaceType::from() or Nette\PhpGenerator\ClassLike::from() instead.',
);

Assert::error(
fn() => TraitType::from(Abc\Class1::class),
E_USER_WARNING,
'Abc\Class1 cannot be represented with Nette\PhpGenerator\TraitType. Call Nette\PhpGenerator\ClassType::from() or Nette\PhpGenerator\ClassLike::from() instead.',
);

Assert::error(
fn() => ClassType::fromCode('<?php interface I {}'),
E_USER_WARNING,
'Provided code cannot be represented with Nette\PhpGenerator\ClassType. Call Nette\PhpGenerator\InterfaceType::fromCode() or Nette\PhpGenerator\ClassLike::fromCode() instead.',
);

Assert::error(
fn() => InterfaceType::fromCode('<?php trait T {}'),
E_USER_WARNING,
'Provided code cannot be represented with Nette\PhpGenerator\InterfaceType. Call Nette\PhpGenerator\TraitType::fromCode() or Nette\PhpGenerator\ClassLike::fromCode() instead.',
);
3 changes: 2 additions & 1 deletion tests/PhpGenerator/ClassType.from.82.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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));
9 changes: 5 additions & 4 deletions tests/PhpGenerator/ClassType.from.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ declare(strict_types=1);

use Nette\PhpGenerator\ClassType;
use Nette\PhpGenerator\Factory;
use Nette\PhpGenerator\InterfaceType;

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;
Expand Down
6 changes: 3 additions & 3 deletions tests/PhpGenerator/ClassType.from.trait.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -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));

0 comments on commit af74f21

Please sign in to comment.