Skip to content

Instantly share code, notes, and snippets.

@nbish11
Created May 28, 2022 09:30
Show Gist options
  • Select an option

  • Save nbish11/64db626bc60a12905fec9dbd1edcab31 to your computer and use it in GitHub Desktop.

Select an option

Save nbish11/64db626bc60a12905fec9dbd1edcab31 to your computer and use it in GitHub Desktop.
Removing reliance on nulls in PHP
<?php
declare(strict_types=1);
// IMPLEMENTATION using DDD...
final class ItemIdentity
{
public function __construct(public readonly int $number) {}
public function equals(self $other): bool
{
return $this->number === $other->number;
}
}
final class ItemDescription
{
public function __construct(public readonly string $value) {}
}
final class Item
{
public readonly ItemDescription $description;
public function __construct(public readonly ItemIdentity $identity)
{
$this->describe('');
}
public function identify(): int
{
return $this->identity->number;
}
public function describe(string $description): void
{
$this->description = new ItemDescription($description);
}
public function equals(self $other): bool
{
return $this === $other;
}
}
interface ItemRepository
{
public function get(ItemIdentity $id): Item;
public function add(Item $item): void;
public function remove(Item $item): void;
}
final class InMemoryItemRepository
{
private static $stored = [];
private static $id = 0;
public static function withDefaultItems()
{
$items = new self();
$itemsToMake = [
$items->nextAvailableIdentity() => 'One',
$items->nextAvailableIdentity() => 'Second Item',
$items->nextAvailableIdentity() => 'Third Item'
];
foreach ($itemsToMake as $id => $description) {
$itemToAdd = new Item($id);
$itemToAdd->describe($description);
$items->add($itemToAdd);
}
return $items;
}
// note this function will ALWAYS return a product
public function get(ItemIdentity $id): Item
{
// if product exists... return it
foreach (self::$stored as $item) {
if ($item->identity->equals($id)) {
return $item;
}
}
// if it doesn't exist... return an empty one with id set
return new Item($this->nextAvailableIdentity());
}
public function add(Item $item): void
{
if (!this->exists($item)) {
self::$stored[] = $item;
}
}
public function remove(Item $item): void
{
if (($index = $this->indexOf($item)) !== -1) {
unset(self::$stored[$index]);
}
}
public function exists(Item $item): bool
{
foreach (self::$stored as $storedItem) {
if ($storedItem->equals($item)) {
return true;
}
}
return false;
}
private function indexOf(Item $item): int
{
foreach (self::$stored as $index => $storedItem) {
if ($storedItem->equals($item)) {
return $index;
}
}
return -1;
}
public function nextAvailableIdentity(): ProductIdentity
{
return new ItemIdentity(self::$id++);
}
}
// USAGE:
$items = InMemoryItemRepository::withDefaultItems();
// essentially an "update" query
$itemThatDoesExist = $items->get(new ItemIdentity(0));
$itemThatDoesExist->describe('First Item');
$items->add($itemThatDoesExist);
// essentially a "create" query
$itemThatDoesNotExist = $items->get(new ItemIdentity(3));
$itemThatDoesNotExist->describe('Fourth Item');
$items->add($itemThatDoesNotExist);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment