3v4l.org

run code in 300+ PHP versions simultaneously
<?php interface ICupboard { public function getNextCup(): Cup; public function haveCups(): bool; } class InfiniteCupBoard implements ICupboard { public function getNextCup(): Cup { return Cup::createEmpty(); } public function haveCups(): bool { return true; } } interface ITap { public function getWater(): Liquid; } class InfiniteTap implements ITap { private int $waterVolumePerReuqest; public function __construct(int $waterVolumePerReuqest) { $this->waterVolumePerReuqest = $waterVolumePerReuqest; } public function getWater(): Liquid { return Liquid::createVolume($this->waterVolumePerReuqest); } } class Cup { private Liquid $liquid; private int $volume; private function __construct(Liquid $liquid, int $volume = 300) { $this->liquid = $liquid; $this->volume = $volume; } public static function createEmpty(): self { return new self(Liquid::createEmpty()); } public function fill(Liquid $liquid): void { if (false === $this->canAddLiquid($liquid)) { throw new DomainException( sprintf( 'Cannot hold liquid volume. Expected volume: %s. Current volume: %s. Provided volume: %s.', $this->volume, $this->liquid->getVolume(), $liquid->getVolume() ) ); } $this->liquid = $this->liquid->add($liquid); } public function canAddLiquid(Liquid $liquid): bool { return $this->volume >= $this->liquid->getVolume() + $liquid->getVolume(); } } class Liquid { private int $volume; private function __construct(int $volume) { $this->volume = $volume; } public static function createEmpty(): self { return new self(0); } public static function createVolume(int $volume): self { return new self($volume); } public function add(Liquid $liquid): self { return new self($this->volume + $liquid->volume); } public function getVolume(): int { return $this->volume; } } class FillCupsWithWater { private ITap $tap; private ICupboard $cupboard; public function __construct(ITap $tap, ICupboard $cupboard) { $this->tap = $tap; $this->cupboard = $cupboard; } public function __invoke(int $cupsToFillCount): array { $filledCups = []; while($this->cupboard->haveCups() && $cupsToFillCount) { $cup = $this->cupboard->getNextCup(); $water = $this->tap->getWater(); while($cup->canAddLiquid($water)) { $cup->fill($water); } $filledCups[] = $cup; $cupsToFillCount--; } return $filledCups; } } $fillCupsWithWater = new FillCupsWithWater(new InfiniteTap(14), new InfiniteCupBoard); print_r($fillCupsWithWater(4));

preferences:
58.18 ms | 402 KiB | 5 Q