PHP Loan Request Project
Build a small in-memory lending operation with one clear invariant: successful reservations reduce available stock, while rejected requests leave it unchanged.
Your brief
Write the rule and its tests before adding a form or database. This model is deliberately single-process and has no durable storage, so it cannot coordinate real concurrent borrowers. Returning a boolean separates a normal capacity rejection from an invalid-input exception. A later database implementation should preserve the observable contract through an authorised transactional operation rather than sharing this object between web requests.
Run it locally
Run this complete source locally with PHP 8.2 or newer. Save it using the filename shown and run the command below. PHP is not currently available in Bhylu’s browser playground. Apache and MySQL are not needed for an ordinary CLI example.
php -l loan-project.php
php loan-project.phpDownload this source as a local PHP lab file. Keep lab files separate from the Bhylu project and production data.
Worked solution
Show the worked solution
<?php
declare(strict_types=1);
class LendingDesk {
public function __construct(private int $available) { if ($available<0) throw new InvalidArgumentException("Negative stock"); }
public function request(int $count): bool {
if ($count<=0) throw new InvalidArgumentException("Positive request required");
if ($count>$this->available) return false;
$this->available-=$count; return true;
}
public function remaining(): int { return $this->available; }
}
$desk = new LendingDesk(6);
if (!$desk->request(4)) throw new RuntimeException("First request failed");
if ($desk->request(3)) throw new RuntimeException("Overdraw accepted");
if ($desk->remaining()!==2) throw new RuntimeException("Rejection changed stock");
echo "Reservation contract passed; 2 remain\n";
Expected result
Reservation contract passed; 2 remainThe three explicit checks cover acceptance, rejection and unchanged state. They fail the run even when PHP assertions are disabled. The remaining count belongs only to this object. Before turning it into a real endpoint, add parsed input, authentication/authorisation, CSRF where applicable and a database consistency boundary.
Extend and test
Add returnUnits with a capacity invariant and test repeated or invalid returns.
Check the official PHP manual for detailed version and API contracts.