Skip to content

Commit

Permalink
minor #54669 [TypeInfo] rework isA to handle class names and improve …
Browse files Browse the repository at this point in the history
…isNullable (mtarld)

This PR was merged into the 7.1 branch.

Discussion
----------

[TypeInfo] rework isA to handle class names and improve isNullable

| Q             | A
| ------------- | ---
| Branch?       | 7.1
| Bug fix?      | no
| New feature?  | no
| Deprecations? | no
| Issues        |
| License       | MIT

#54659 introduces a better design that allows us to easily handle class names in `isA` and to simplify `isNullable`

Commits
-------

5624ee0 [TypeInfo] rework isA to handle class names and improve isNullable
  • Loading branch information
fabpot committed May 2, 2024
2 parents 96d664e + 5624ee0 commit 162a1fa
Show file tree
Hide file tree
Showing 14 changed files with 69 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,9 @@ public function testIsA()
{
$this->assertFalse((new BackedEnumType(DummyBackedEnum::class, Type::int()))->isA(TypeIdentifier::ARRAY));
$this->assertTrue((new BackedEnumType(DummyBackedEnum::class, Type::int()))->isA(TypeIdentifier::OBJECT));
$this->assertFalse((new BackedEnumType(DummyBackedEnum::class, Type::int()))->isA(self::class));
$this->assertTrue((new BackedEnumType(DummyBackedEnum::class, Type::int()))->isA(DummyBackedEnum::class));
$this->assertTrue((new BackedEnumType(DummyBackedEnum::class, Type::int()))->isA(\BackedEnum::class));
$this->assertTrue((new BackedEnumType(DummyBackedEnum::class, Type::int()))->isA(\UnitEnum::class));
}
}
3 changes: 3 additions & 0 deletions src/Symfony/Component/TypeInfo/Tests/Type/BuiltinTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,8 @@ public function testIsA()
{
$this->assertFalse((new BuiltinType(TypeIdentifier::INT))->isA(TypeIdentifier::ARRAY));
$this->assertTrue((new BuiltinType(TypeIdentifier::INT))->isA(TypeIdentifier::INT));
$this->assertFalse((new BuiltinType(TypeIdentifier::INT))->isA('array'));
$this->assertTrue((new BuiltinType(TypeIdentifier::INT))->isA('int'));
$this->assertFalse((new BuiltinType(TypeIdentifier::INT))->isA(self::class));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,5 +100,12 @@ public function testIsA()
$this->assertTrue($type->isA(TypeIdentifier::ARRAY));
$this->assertFalse($type->isA(TypeIdentifier::STRING));
$this->assertFalse($type->isA(TypeIdentifier::INT));
$this->assertFalse($type->isA(self::class));

$type = new CollectionType(new GenericType(Type::object(self::class), Type::string(), Type::bool()));

$this->assertFalse($type->isA(TypeIdentifier::ARRAY));
$this->assertTrue($type->isA(TypeIdentifier::OBJECT));
$this->assertTrue($type->isA(self::class));
}
}
3 changes: 3 additions & 0 deletions src/Symfony/Component/TypeInfo/Tests/Type/EnumTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@ public function testIsA()
{
$this->assertFalse((new EnumType(DummyEnum::class))->isA(TypeIdentifier::ARRAY));
$this->assertTrue((new EnumType(DummyEnum::class))->isA(TypeIdentifier::OBJECT));
$this->assertTrue((new EnumType(DummyEnum::class))->isA(DummyEnum::class));
$this->assertTrue((new EnumType(DummyEnum::class))->isA(\UnitEnum::class));
$this->assertFalse((new EnumType(DummyEnum::class))->isA(\BackedEnum::class));
}
}
2 changes: 2 additions & 0 deletions src/Symfony/Component/TypeInfo/Tests/Type/GenericTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ public function testIsA()
$type = new GenericType(Type::builtin(TypeIdentifier::ARRAY), Type::string(), Type::bool());
$this->assertTrue($type->isA(TypeIdentifier::ARRAY));
$this->assertFalse($type->isA(TypeIdentifier::STRING));
$this->assertFalse($type->isA(self::class));

$type = new GenericType(Type::object(self::class), Type::union(Type::bool(), Type::string()), Type::int(), Type::float());
$this->assertTrue($type->isA(TypeIdentifier::OBJECT));
$this->assertFalse($type->isA(TypeIdentifier::INT));
$this->assertFalse($type->isA(TypeIdentifier::STRING));
$this->assertTrue($type->isA(self::class));
}
}
2 changes: 2 additions & 0 deletions src/Symfony/Component/TypeInfo/Tests/Type/ObjectTypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,7 @@ public function testIsA()
{
$this->assertFalse((new ObjectType(self::class))->isA(TypeIdentifier::ARRAY));
$this->assertTrue((new ObjectType(self::class))->isA(TypeIdentifier::OBJECT));
$this->assertTrue((new ObjectType(self::class))->isA(self::class));
$this->assertFalse((new ObjectType(self::class))->isA(\stdClass::class));
}
}
11 changes: 0 additions & 11 deletions src/Symfony/Component/TypeInfo/Tests/TypeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,6 @@ public function testIs()
$this->assertFalse(Type::generic(Type::string(), Type::int())->is($isInt));
}

public function testIsA()
{
$this->assertTrue(Type::int()->isA(TypeIdentifier::INT));
$this->assertTrue(Type::union(Type::string(), Type::int())->isA(TypeIdentifier::INT));
$this->assertTrue(Type::generic(Type::int(), Type::string())->isA(TypeIdentifier::INT));

$this->assertFalse(Type::string()->isA(TypeIdentifier::INT));
$this->assertFalse(Type::union(Type::string(), Type::float())->isA(TypeIdentifier::INT));
$this->assertFalse(Type::generic(Type::string(), Type::int())->isA(TypeIdentifier::INT));
}

public function testIsNullable()
{
$this->assertTrue(Type::null()->isNullable());
Expand Down
16 changes: 8 additions & 8 deletions src/Symfony/Component/TypeInfo/Type.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ abstract class Type implements \Stringable

abstract public function getBaseType(): BuiltinType|ObjectType;

/**
* @param TypeIdentifier|class-string $subject
*/
abstract public function isA(TypeIdentifier|string $subject): bool;

abstract public function asNonNullable(): self;

/**
* @param callable(Type): bool $callable
*/
Expand All @@ -34,15 +41,8 @@ public function is(callable $callable): bool
return $callable($this);
}

public function isA(TypeIdentifier $typeIdentifier): bool
{
return $this->getBaseType()->getTypeIdentifier() === $typeIdentifier;
}

public function isNullable(): bool
{
return \in_array($this->getBaseType()->getTypeIdentifier(), [TypeIdentifier::NULL, TypeIdentifier::MIXED], true);
return $this->is(fn (Type $t): bool => $t->isA(TypeIdentifier::NULL) || $t->isA(TypeIdentifier::MIXED));
}

abstract public function asNonNullable(): self;
}
13 changes: 13 additions & 0 deletions src/Symfony/Component/TypeInfo/Type/BuiltinType.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,19 @@ public function getTypeIdentifier(): TypeIdentifier
return $this->typeIdentifier;
}

public function isA(TypeIdentifier|string $subject): bool
{
if ($subject instanceof TypeIdentifier) {
return $this->getTypeIdentifier() === $subject;
}

try {
return TypeIdentifier::from($subject) === $this->getTypeIdentifier();
} catch (\ValueError) {
return false;
}
}

/**
* @return self|UnionType<BuiltinType<TypeIdentifier::OBJECT>|BuiltinType<TypeIdentifier::RESOURCE>|BuiltinType<TypeIdentifier::ARRAY>|BuiltinType<TypeIdentifier::STRING>|BuiltinType<TypeIdentifier::FLOAT>|BuiltinType<TypeIdentifier::INT>|BuiltinType<TypeIdentifier::BOOL>>
*/
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/TypeInfo/Type/CollectionType.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ public function getType(): BuiltinType|ObjectType|GenericType
return $this->type;
}

public function isA(TypeIdentifier|string $subject): bool
{
return $this->getType()->isA($subject);
}

public function isList(): bool
{
return $this->isList;
Expand Down
9 changes: 2 additions & 7 deletions src/Symfony/Component/TypeInfo/Type/CompositeTypeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,9 @@ public function __construct(Type ...$types)
$this->types = array_values(array_unique($types));
}

public function isA(TypeIdentifier $typeIdentifier): bool
public function isA(TypeIdentifier|string $subject): bool
{
return $this->is(fn (Type $type) => $type->isA($typeIdentifier));
}

public function isNullable(): bool
{
return $this->is(fn (Type $type) => $type->isNullable());
return $this->is(fn (Type $type) => $type->isA($subject));
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/TypeInfo/Type/GenericType.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public function getType(): BuiltinType|ObjectType
return $this->type;
}

public function isA(TypeIdentifier|string $subject): bool
{
return $this->getType()->isA($subject);
}

public function asNonNullable(): self
{
return $this;
Expand Down
9 changes: 9 additions & 0 deletions src/Symfony/Component/TypeInfo/Type/ObjectType.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,15 @@ public function getTypeIdentifier(): TypeIdentifier
return TypeIdentifier::OBJECT;
}

public function isA(TypeIdentifier|string $subject): bool
{
if ($subject instanceof TypeIdentifier) {
return $this->getTypeIdentifier() === $subject;
}

return is_a($this->getClassName(), $subject, allow_string: true);
}

/**
* @return T
*/
Expand Down
6 changes: 6 additions & 0 deletions src/Symfony/Component/TypeInfo/Type/TemplateType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\TypeInfo\Exception\LogicException;
use Symfony\Component\TypeInfo\Type;
use Symfony\Component\TypeInfo\TypeIdentifier;

/**
* Represents a template placeholder, such as "T" in "Collection<T>".
Expand All @@ -35,6 +36,11 @@ public function getBaseType(): BuiltinType|ObjectType
throw new LogicException(sprintf('Cannot get base type on "%s" template type.', $this));
}

public function isA(TypeIdentifier|string $subject): bool
{
return false;
}

public function getName(): string
{
return $this->name;
Expand Down

0 comments on commit 162a1fa

Please sign in to comment.