Menu
Coddy logo textTech

Banking System

Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 89 of 91.

challenge icon

Challenge

Easy

Let's build a Banking System that handles accounts, transactions, and transfers between accounts. You'll create a system with proper encapsulation to protect financial data, inheritance for different account types, and validation to ensure data integrity.

You'll organize your code across six files:

  • Transaction.php — Create a Transaction class to record financial operations. Use constructor promotion for type (string — "deposit", "withdrawal", or "transfer"), amount (float), and timestamp (string). All properties should be public readonly. Add a method getDescription(): string that returns "[type]: $[amount]" (format amount to 2 decimal places).
  • BankAccount.php — Include the Transaction file. Create an abstract BankAccount class with:
    • Constructor promotion for accountNumber (string, public readonly) and holderName (string, public readonly)
    • A protected $balance property initialized to 0.0
    • A private array to store transaction history
    • getBalance(): float — returns the current balance
    • deposit(float $amount): string — adds to balance, records transaction, returns "Deposited: $[amount]"
    • abstract withdraw(float $amount): string — child classes implement withdrawal rules
    • addTransaction(Transaction $t): void — protected method to add transactions to history
    • getTransactionCount(): int — returns number of transactions
  • SavingsAccount.php — Include the BankAccount file. Create a SavingsAccount class extending BankAccount with:
    • A class constant INTEREST_RATE set to 0.02 (2%)
    • withdraw(float $amount): string — if amount exceeds balance, return "Insufficient funds"; otherwise deduct, record transaction, return "Withdrew: $[amount]"
    • applyInterest(): string — calculates interest on current balance, adds it as a deposit, returns "Interest applied: $[interest]"
  • CheckingAccount.php — Include the BankAccount file. Create a CheckingAccount class extending BankAccount with:
    • A private $overdraftLimit property set via constructor (add a third parameter with default 100.0)
    • withdraw(float $amount): string — allows withdrawal if amount doesn't exceed balance + overdraft limit; return "Insufficient funds (overdraft limit: $[limit])" on failure, or "Withdrew: $[amount]" on success
    • getOverdraftLimit(): float — returns the overdraft limit
  • Bank.php — Include both account files. Create a Bank class that manages accounts:
    • A private array to store accounts indexed by account number
    • addAccount(BankAccount $account): void — adds an account
    • findAccount(string $accountNumber): ?BankAccount — returns account or null
    • transfer(string $fromAccount, string $toAccount, float $amount): string — transfers money between accounts. Return "Source account not found", "Destination account not found", or the result of the withdrawal if it fails. On success, deposit to destination and return "Transferred $[amount] from [from] to [to]"
  • main.php — Include the Bank file. You'll receive two inputs: accounts data (JSON) and operations (JSON).

    Accounts JSON format:

    [{"type": "savings", "number": "SAV001", "holder": "Alice", "initial": 1000}, {"type": "checking", "number": "CHK001", "holder": "Bob", "initial": 500, "overdraft": 200}]

    Operations JSON format:

    [{"op": "deposit", "account": "SAV001", "amount": 200}, {"op": "withdraw", "account": "CHK001", "amount": 600}, {"op": "transfer", "from": "SAV001", "to": "CHK001", "amount": 300}, {"op": "interest", "account": "SAV001"}, {"op": "balance", "account": "SAV001"}]

    Create the bank and all accounts (depositing initial amounts). Process each operation:

    • "deposit" — Print the result of deposit()
    • "withdraw" — Print the result of withdraw()
    • "transfer" — Print the result of transfer()
    • "interest" — Print the result of applyInterest() (only for savings accounts)
    • "balance" — Print "[holder] balance: $[balance]" (2 decimal places)

    Print each result on a new line. Format all monetary amounts to 2 decimal places.

Remember that transfers should be atomic — if the withdrawal fails, the deposit shouldn't happen. The protected $balance property allows child classes to modify it while keeping it hidden from outside code, demonstrating proper encapsulation in a financial context.

Try it yourself

<?php

require_once 'Bank.php';

// Read input
$accountsJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));

// Parse JSON inputs
$accounts = (array)json_decode($accountsJson, true);
$operations = (array)json_decode($operationsJson, true);

// TODO: Create a Bank instance

// TODO: Create accounts from the accounts data
// For each account in $accounts:
//   - If type is "savings", create SavingsAccount
//   - If type is "checking", create CheckingAccount (with overdraft if provided)
//   - Add account to bank
//   - Deposit initial amount

// TODO: Process each operation
// For each operation in $operations:
//   - "deposit": Print result of deposit()
//   - "withdraw": Print result of withdraw()
//   - "transfer": Print result of transfer()
//   - "interest": Print result of applyInterest() (only for savings)
//   - "balance": Print "[holder] balance: $[balance]" (2 decimal places)

?>

All lessons in Object Oriented Programming