Skip to content

Commit af74f21

Browse files
GromNaNdg
authored andcommitted
Make ClassLike::from return type assert the subclass type (BC break) (#154)
1 parent dec0711 commit af74f21

File tree

5 files changed

+61
-10
lines changed

5 files changed

+61
-10
lines changed

src/PhpGenerator/ClassLike.php

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,28 @@ abstract class ClassLike
4040

4141
public static function from(string|object $class, bool $withBodies = false): self
4242
{
43-
return (new Factory)
43+
$instance = (new Factory)
4444
->fromClassReflection(new \ReflectionClass($class), $withBodies);
45+
46+
if (!$instance instanceof static) {
47+
$class = is_object($class) ? $class::class : $class;
48+
trigger_error("$class cannot be represented with " . static::class . '. Call ' . $instance::class . '::' . __FUNCTION__ . '() or ' . __METHOD__ . '() instead.', E_USER_WARNING);
49+
}
50+
51+
return $instance;
4552
}
4653

4754

4855
public static function fromCode(string $code): self
4956
{
50-
return (new Factory)
57+
$instance = (new Factory)
5158
->fromClassCode($code);
59+
60+
if (!$instance instanceof static) {
61+
trigger_error('Provided code cannot be represented with ' . static::class . '. Call ' . $instance::class . '::' . __FUNCTION__ . '() or ' . __METHOD__ . '() instead.', E_USER_WARNING);
62+
}
63+
64+
return $instance;
5265
}
5366

5467

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Nette\PhpGenerator\ClassType;
6+
use Nette\PhpGenerator\InterfaceType;
7+
use Nette\PhpGenerator\TraitType;
8+
use Tester\Assert;
9+
10+
require __DIR__ . '/../bootstrap.php';
11+
require __DIR__ . '/fixtures/classes.php';
12+
13+
14+
Assert::error(
15+
fn() => ClassType::from(Abc\Interface1::class),
16+
E_USER_WARNING,
17+
'Abc\Interface1 cannot be represented with Nette\PhpGenerator\ClassType. Call Nette\PhpGenerator\InterfaceType::from() or Nette\PhpGenerator\ClassLike::from() instead.',
18+
);
19+
20+
Assert::error(
21+
fn() => TraitType::from(Abc\Class1::class),
22+
E_USER_WARNING,
23+
'Abc\Class1 cannot be represented with Nette\PhpGenerator\TraitType. Call Nette\PhpGenerator\ClassType::from() or Nette\PhpGenerator\ClassLike::from() instead.',
24+
);
25+
26+
Assert::error(
27+
fn() => ClassType::fromCode('<?php interface I {}'),
28+
E_USER_WARNING,
29+
'Provided code cannot be represented with Nette\PhpGenerator\ClassType. Call Nette\PhpGenerator\InterfaceType::fromCode() or Nette\PhpGenerator\ClassLike::fromCode() instead.',
30+
);
31+
32+
Assert::error(
33+
fn() => InterfaceType::fromCode('<?php trait T {}'),
34+
E_USER_WARNING,
35+
'Provided code cannot be represented with Nette\PhpGenerator\InterfaceType. Call Nette\PhpGenerator\TraitType::fromCode() or Nette\PhpGenerator\ClassLike::fromCode() instead.',
36+
);

tests/PhpGenerator/ClassType.from.82.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
declare(strict_types=1);
88

99
use Nette\PhpGenerator\ClassType;
10+
use Nette\PhpGenerator\TraitType;
1011

1112
require __DIR__ . '/../bootstrap.php';
1213
require __DIR__ . '/fixtures/classes.82.php';
1314

1415
$res[] = ClassType::from(new Abc\Class13);
15-
$res[] = ClassType::from(Abc\Trait13::class);
16+
$res[] = TraitType::from(Abc\Trait13::class);
1617

1718
sameFile(__DIR__ . '/expected/ClassType.from.82.expect', implode("\n", $res));

tests/PhpGenerator/ClassType.from.phpt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@ declare(strict_types=1);
88

99
use Nette\PhpGenerator\ClassType;
1010
use Nette\PhpGenerator\Factory;
11+
use Nette\PhpGenerator\InterfaceType;
1112

1213
require __DIR__ . '/../bootstrap.php';
1314
require __DIR__ . '/fixtures/classes.php';
1415

15-
$res[] = ClassType::from(Abc\Interface1::class);
16-
$res[] = ClassType::from(Abc\Interface2::class);
17-
$res[] = ClassType::from(Abc\Interface3::class);
18-
$res[] = ClassType::from(Abc\Interface4::class);
16+
$res[] = InterfaceType::from(Abc\Interface1::class);
17+
$res[] = InterfaceType::from(Abc\Interface2::class);
18+
$res[] = InterfaceType::from(Abc\Interface3::class);
19+
$res[] = InterfaceType::from(Abc\Interface4::class);
1920
$res[] = ClassType::from(Abc\Class1::class);
2021
$res[] = ClassType::from(new Abc\Class2);
2122
$obj = new Abc\Class3;

tests/PhpGenerator/ClassType.from.trait.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
declare(strict_types=1);
44

5-
use Nette\PhpGenerator\ClassType;
5+
use Nette\PhpGenerator\ClassLike;
66

77
require __DIR__ . '/../bootstrap.php';
88
require __DIR__ . '/fixtures/traits.php';
@@ -19,11 +19,11 @@ $classes = [
1919
Class5::class,
2020
];
2121

22-
$res = array_map(fn($class) => ClassType::from($class), $classes);
22+
$res = array_map(fn($class) => ClassLike::from($class), $classes);
2323

2424
sameFile(__DIR__ . '/expected/ClassType.from.trait-use.expect', implode("\n", $res));
2525

2626

27-
$res = array_map(fn($class) => ClassType::from($class, withBodies: true), $classes);
27+
$res = array_map(fn($class) => ClassLike::from($class, withBodies: true), $classes);
2828

2929
sameFile(__DIR__ . '/expected/ClassType.from.trait-use.bodies.expect', implode("\n", $res));

0 commit comments

Comments
 (0)