Countable and Friends

Countable, Stringable and JsonSerializable

Three one-method interfaces plug an object into core functions: Countable::count() answers count($obj), JsonSerializable::jsonSerialize() returns what json_encode() should encode instead of the public properties, and Stringable (PHP 8.0) marks a class with __toString() (Conversion Magic Methods). PHP adds Stringable automatically to any class defining __toString(), but declaring it documents intent, and string|Stringable is the type for "anything printable".

A cart that counts, prints and encodes itselfPHP
<?php
final class Cart implements Countable, Stringable, JsonSerializable {
  private array $lines = [];                                 // sku => [qty, cents]
  public function add(string $sku, int $qty, int $cents): static {
    $this->lines[$sku] = [$qty, $cents];
    return $this;
  }
  public function count(): int { return array_sum(array_column($this->lines, 0)); }
  public function total(): int { return array_sum(array_map(fn($l) => $l[0] * $l[1],
    $this->lines)); }
  public function __toString(): string { return sprintf('%d items, $%.2f', count($this),
    $this->total() / 100); }
  public function jsonSerialize(): array { return ['n' => count($this),
    'lines' => $this->lines]; }
}
function banner(string|Stringable $s): string { return "[ $s ]"; }
$cart = (new Cart())->add('BK-PHP-01', 2, 3990)->add('BK-SQL-01', 1, 4450);
echo count($cart), ' | ', banner($cart), "\n", json_encode($cart), "\n";
Output
3 | [ 3 items, $124.30 ]
{"n":3,"lines":{"BK-PHP-01":[2,3990],"BK-SQL-01":[1,4450]}}

count() here reports units, not lines: the class decides what its size means. Keep secrets and internal IDs out of jsonSerialize(), since every json_encode() call will use it.