Skip to content

Instantly share code, notes, and snippets.

@edykim
Last active August 30, 2022 04:47
Show Gist options
  • Select an option

  • Save edykim/e97d52ef35d40211fa7188fe582a39b1 to your computer and use it in GitHub Desktop.

Select an option

Save edykim/e97d52ef35d40211fa7188fe582a39b1 to your computer and use it in GitHub Desktop.
a typed collection with phpstan
<?php declare(strict_types=1);
interface Spaceship
{
}
interface Car
{
}
interface Animal
{
}
interface Device
{
}
class Camera implements Device
{
}
class SomeCamera extends Camera
{
}
class Cow implements Animal
{
}
/**
* @template T
*/
class Collection
{
/**
* @var T[] $items
*/
protected array $items = [];
/**
* @param T[] $items
*/
public function __construct(array $items)
{
$this->items = $items;
}
/**
* @param int $index
* @return T
*/
public function get(int $index)
{
return $this->items[$index];
}
}
/**
* @template T
*/
class CollectionGenerator
{
/**
* @param T[] $items
* @return Collection<T>
*/
public function __invoke(array $items)
{
return new Collection($items);
}
}
/**
* @template T
* @param class-string<T> $type
* @return CollectionGenerator<T>
*/
function collectionOf($type): CollectionGenerator
{
/** @var CollectionGenerator<T> $generator */
$generator = new CollectionGenerator();
return $generator;
}
/**
* @template TA
* @template TB
* @param class-string<TA> $typeA
* @param class-string<TB> $typeB
* @return class-string<TA>|class-string<TB>
*/
function unionType($typeA, $typeB): string
{
/** @var class-string<TA>|class-string<TB> $empty */
$empty = '';
return $empty;
}
function run(): void
{
$arr = [
new Camera,
new Camera,
new SomeCamera,
new Cow,
];
$aCollection = collectionOf(Device::class)($arr);
$bCollection = collectionOf(unionType(Device::class, Cow::class))($arr);
$cCollection = collectionOf(
unionType(Device::class, Spaceship::class),
)($arr);
\PHPStan\dumpType($aCollection);
\PHPStan\dumpType($bCollection);
\PHPStan\dumpType($cCollection);
}
// Line Error
// 109 Parameter #1 $items of callable CollectionGenerator<Device> expects array<Device>, array<int, Camera|Cow> given.
// 115 Parameter #1 $items of callable CollectionGenerator<Device|Spaceship> expects array<Device|Spaceship>, array<int, Camera|Cow> given.
// 117 Dumped type: Collection<Device>
// 118 Dumped type: Collection<Cow|Device>
// 119 Dumped type: Collection<Device|Spaceship>
@edykim
Copy link
Author

edykim commented Aug 30, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment