exercises and solutions
OOP exercises
OOP exercises should focus on responsibilities rather than syntax inventory. Ask what data an object owns, which operations it exposes, and which invalid states it prevents.
Practical Example
<?php
declare(strict_types=1);
final class Basket
{
public function __construct(private array $items) {}
public function total(): int
{
return array_sum(array_column($this->items, 'price'));
}
}
$basket = new Basket([['price' => 500], ['price' => 750]]);
echo $basket->total() . PHP_EOL;
// Prints:
// 1250
OOP exercises should focus on responsibilities: what data the object owns, what behaviour it exposes, and what it hides from the caller.
Useful extensions include introducing a value object, replacing a broad array with a typed model, or adding an interface where callers genuinely need interchangeable implementations.
Practice
Model A Basket
Show solution
Validate each quantity when constructing or adding an item, then sum price_pence * quantity inside total(). Keep the items private so callers cannot bypass the invariant.
The object earns its place by owning a rule and a useful operation, not merely by wrapping an array.
Model A Money Value
Show solution
Keep the pence value private and validate it in the constructor. add() should return new Money($this->pence + $other->pence). A formatter can return number_format($this->pence / 100, 2).
Returning a new value keeps the object easy to reason about and prevents callers from changing an existing total accidentally.