Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

النظام المصرفي

جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 89 من 91.

challenge icon

التحدي

سهل

لنقم ببناء نظام بنكي (Banking System) يتعامل مع الحسابات، المعاملات، والتحويلات بين الحسابات. ستقوم بإنشاء نظام مع تغليف (encapsulation) مناسب لحماية البيانات المالية، ووراثة (inheritance) لأنواع الحسابات المختلفة، والتحقق من الصحة لضمان سلامة البيانات.

ستقوم بتنظيم الكود الخاص بك عبر ستة ملفات:

  • Transaction.php — أنشئ فئة Transaction لتسجيل العمليات المالية. استخدم خاصية الترقية في المنشئ (constructor promotion) لكل من type (سلسلة نصية — "deposit" أو "withdrawal" أو "transfer")، و amount (رقم عشري float)، و timestamp (سلسلة نصية). يجب أن تكون جميع الخصائص public readonly. أضف طريقة getDescription(): string تعيد "[type]: $[amount]" (قم بتنسيق المبلغ إلى منزلتين عشريتين).
  • BankAccount.php — قم بتضمين ملف Transaction. أنشئ فئة مجردة (abstract class) باسم BankAccount تحتوي على:
    • ترقية المنشئ (Constructor promotion) لـ accountNumber (سلسلة نصية، public readonly) و holderName (سلسلة نصية، public readonly)
    • خاصية $balance محمية (protected) تبدأ بـ 0.0
    • مصفوفة خاصة (private) لتخزين سجل المعاملات
    • getBalance(): float — تعيد الرصيد الحالي
    • deposit(float $amount): string — تضيف إلى الرصيد، تسجل المعاملة، وتعيد "Deposited: $[amount]"
    • abstract withdraw(float $amount): string — تقوم الفئات الفرعية بتنفيذ قواعد السحب
    • addTransaction(Transaction $t): void — طريقة محمية (protected) لإضافة المعاملات إلى السجل
    • getTransactionCount(): int — تعيد عدد المعاملات
  • SavingsAccount.php — قم بتضمين ملف BankAccount. أنشئ فئة SavingsAccount ترث من BankAccount مع:
    • ثابت للفئة INTEREST_RATE قيمته 0.02 (2%)
    • withdraw(float $amount): string — إذا تجاوز المبلغ الرصيد، أعد "Insufficient funds"؛ خلاف ذلك، اخصم المبلغ، سجل المعاملة، وأعد "Withdrew: $[amount]"
    • applyInterest(): string — تحسب الفائدة على الرصيد الحالي، تضيفها كإيداع، وتعيد "Interest applied: $[interest]"
  • CheckingAccount.php — قم بتضمين ملف BankAccount. أنشئ فئة CheckingAccount ترث من BankAccount مع:
    • خاصية $overdraftLimit خاصة (private) يتم تعيينها عبر المنشئ (أضف معاملًا ثالثًا بقيمة افتراضية 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 — تعيد الحساب أو null
    • transfer(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]" (بمنزلتين عشريتين)

    اطبع كل نتيجة في سطر جديد. قم بتنسيق جميع المبالغ المالية لتكون بمنزلتين عشريتين.

تذكر أن التحويلات يجب أن تكون ذرية (atomic) — إذا فشل السحب، فلا يجب أن يتم الإيداع. تسمح الخاصية المحمية $balance للفئات الفرعية بتعديلها مع إبقائها مخفية عن الكود الخارجي، مما يوضح التغليف (encapsulation) السليم في سياق مالي.

جرّب بنفسك

<?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: إنشاء مثيل (instance) للبنك

// TODO: إنشاء حسابات من بيانات الحسابات
// لكل حساب في $accounts:
//   - إذا كان النوع "savings"، أنشئ SavingsAccount
//   - إذا كان النوع "checking"، أنشئ CheckingAccount (مع السحب على المكشوف إذا تم توفيره)
//   - أضف الحساب إلى البنك
//   - أودع المبلغ الأولي

// TODO: معالجة كل عملية
// لكل عملية في $operations:
//   - "deposit": اطبع نتيجة deposit()
//   - "withdraw": اطبع نتيجة withdraw()
//   - "transfer": اطبع نتيجة transfer()
//   - "interest": اطبع نتيجة applyInterest() (فقط لحسابات التوفير)
//   - "balance": اطبع "[holder] balance: $[balance]" (بمنزلتين عشريتين)

?>

جميع دروس Object Oriented Programming