银行系统
本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 89 课,共 91 课。
挑战
简单让我们来构建一个银行系统,用于管理账户、交易和账户间转账。你将创建一个系统,通过适当的封装保护财务数据,通过继承支持不同的账户类型,并通过验证确保数据完整性。
你将把代码组织在 6 个文件中:
Transaction.php:创建一个Transaction类来记录财务操作。使用构造函数属性提升来定义type(字符串:"deposit"、"withdrawal" 或 "transfer")、amount(浮点数)和timestamp(字符串)。所有属性都应为 public readonly。添加一个方法getDescription(): string,返回"[type]: $[amount]"(将金额格式化为 2 位小数)。BankAccount.php:引入 Transaction 文件。创建一个抽象的BankAccount类,包含:- 使用构造函数属性提升定义
accountNumber(字符串,public readonly)和holderName(字符串,public readonly) - 一个受保护的
$balance属性,初始值为 0.0 - 一个用于存储交易历史的私有数组
getBalance(): float:返回当前余额deposit(float $amount): string:增加余额,记录交易,并返回"Deposited: $[amount]"abstract withdraw(float $amount): string:由子类实现取款规则addTransaction(Transaction $t): void:用于将交易添加到历史记录的受保护方法getTransactionCount(): int:返回交易数量
- 使用构造函数属性提升定义
SavingsAccount.php:引入 BankAccount 文件。创建一个继承BankAccount的SavingsAccount类,包含:- 一个设为 0.02(2%)的类常量
INTEREST_RATE withdraw(float $amount): string:如果金额超过余额,则返回"Insufficient funds";否则扣除金额、记录交易,并返回"Withdrew: $[amount]"applyInterest(): string:根据当前余额计算利息,将利息作为一笔存款加入余额,并返回"Interest applied: $[interest]"
- 一个设为 0.02(2%)的类常量
CheckingAccount.php:引入 BankAccount 文件。创建一个继承BankAccount的CheckingAccount类,包含:- 一个通过构造函数设置的私有
$overdraftLimit属性(添加第三个参数,默认值为 100.0) withdraw(float $amount): string:如果金额不超过余额加透支限额,则允许取款;失败时返回"Insufficient funds (overdraft limit: $[limit])",成功时返回"Withdrew: $[amount]"getOverdraftLimit(): float:返回透支限额
- 一个通过构造函数设置的私有
Bank.php:引入两个账户文件。创建一个用于管理账户的Bank类:- 一个用于存储账户的私有数组,以账户编号作为索引
addAccount(BankAccount $account): void:添加一个账户findAccount(string $accountNumber): ?BankAccount:返回账户,或返回 nulltransfer(string $fromAccount, string $toAccount, float $amount): string:在账户之间转账。返回"Source account not found"、"Destination account not found",或取款失败时返回取款操作的结果。成功时,将金额存入目标账户,并返回"Transferred $[amount] from [from] to [to]"
main.php:引入 Bank 文件。你将收到两个输入:账户数据(JSON)和操作(JSON)。账户 JSON 格式:
[{"type": "savings", "number": "SAV001", "holder": "Alice", "initial": 1000}, {"type": "checking", "number": "CHK001", "holder": "Bob", "initial": 500, "overdraft": 200}]操作 JSON 格式:
[{"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"}]创建银行和所有账户(存入初始金额)。处理每个操作:
"deposit":打印deposit()的结果"withdraw":打印withdraw()的结果"transfer":打印transfer()的结果"interest":打印applyInterest()的结果(仅适用于储蓄账户)"balance":打印"[holder] balance: $[balance]"(保留 2 位小数)
将每个结果打印在新的一行。所有金额都要格式化为 2 位小数。
请记住,转账应当是原子操作。如果取款失败,就不应进行存款。受保护的 $balance 属性允许子类修改余额,同时对外部代码隐藏该属性,展示了财务场景中的适当封装。
亲手试试
<?php
require_once 'Bank.php';
// 读取输入
$accountsJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));
// 解析 JSON 输入
$accounts = (array)json_decode($accountsJson, true);
$operations = (array)json_decode($operationsJson, true);
// TODO:创建一个 Bank 实例
// TODO:根据账户数据创建账户
// 对于 $accounts 中的每个账户:
// 如果 type 是 "savings",创建 SavingsAccount
// 如果 type 是 "checking",创建 CheckingAccount(如果提供了透支额度,就使用它)
// 将账户添加到银行
// 存入初始金额
// TODO:处理每项操作
// 对于 $operations 中的每项操作:
// "deposit":打印 deposit() 的结果
// - "withdraw":输出 withdraw() 的结果
// - "transfer":输出 transfer() 的结果
// - "interest":输出 applyInterest() 的结果(仅适用于储蓄账户)
// - "balance":输出 "[holder] balance: $[balance]"(保留 2 位小数)
?>面向对象编程中的所有课
自己练习: PHP 在线编译器