Originally published on decentphp.dev — part of the Writing decent PHP course. View this lesson on the original site.
This lesson is intentionally hands-on.
Complete all three sandbox exercises below in order.
Exercise 1: flatten nested logic
Refactor this function to use early returns so the happy path is obvious.
<?php
function sendReceiptIfNeeded(array $order, array &$sentEmails): void
{
if (($order['is_paid'] ?? false) === true) {
if (($order['customer_email'] ?? '') !== '') {
$sentEmails[] = $order['customer_email'];
}
}
}
Exercise 2: remove hidden dependencies
Refactor this function so it does not rely on $_ENV or globals.
All required values should be explicit function parameters.
<?php
$_ENV['MAIL_ENABLED'] = '1';
function canSendDigest(array $user): bool
{
global $currentHour;
$currentHour = $currentHour ?? 9;
if (($_ENV['MAIL_ENABLED'] ?? '0') !== '1') {
return false;
}
if (($user['email'] ?? '') === '') {
return false;
}
return $currentHour >= 9;
}
Exercise 3: avoid unnecessary abstraction
Simplify this over-engineered export flow.
Behaviour to preserve: keep only active users with a non-empty email address.
<?php
interface UserSelectionStrategy
{
public function include(array $user): bool;
}
final class ActiveUserSelectionStrategy implements UserSelectionStrategy
{
public function include(array $user): bool
{
return ($user['active'] ?? false) === true;
}
}
final class UserExportPipeline
{
public function __construct(private UserSelectionStrategy $strategy) {}
public function run(array $users): array
{
$emails = [];
foreach ($users as $user) {
if (! $this->strategy->include($user)) {
continue;
}
$email = (string) ($user['email'] ?? '');
if ($email === '') {
continue;
}
$emails[] = $email;
}
return $emails;
}
}
How to approach the exercises
- keep each change small
- preserve behaviour before improving structure
- optimise for readability and local reasoning
- avoid adding abstractions unless there is a current, concrete need
Reference solutions
Reference implementations for all three exercises are available here:
Try each exercise yourself first before comparing against the reference.
From Writing decent PHP — What decent PHP looks like