النظام المصرفي
جزء من قسم Object Oriented Programming في رحلة PHP على Coddy — الدرس 89 من 91.
التحدي
سهللنقم ببناء نظام بنكي (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— تعيد عدد المعاملات
- ترقية المنشئ (Constructor promotion) لـ
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— تعيد الحساب أو 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]"(بمنزلتين عشريتين)
اطبع كل نتيجة في سطر جديد. قم بتنسيق جميع المبالغ المالية لتكون بمنزلتين عشريتين.
تذكر أن التحويلات يجب أن تكون ذرية (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
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsالكلمة المفتاحية $thisالـ Methodsالـ Propertiesالمنشئ (__construct)الهادم (__destruct)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةالكلمة المفتاحية parent::إعادة تعريف الدوال (Method Overriding)الكلمة المفتاحية finalالأصناف المجردة (Abstract Classes)مراجعة - هيكلية الموظفين7التغليف (Encapsulation)
العام، المحمي، الخاص (Public, Protected, Private)نظرة متعمقة على معدلات الوصولدوال Getters و Settersإخفاء المعلوماتميزة Constructor Promotion (8.0)مراجعة - نظام سجلات الطلاب10مفاهيم البرمجة كائنية التوجه المتقدمة
التركيب مقابل الوراثةحقن التبعيةالأصناف المجهولةالتعدادات (PHP 8.1)الألياف (PHP 8.1)تعمق في استنساخ الكائناتالمولدات والمكررات13أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المستودع2مساحات الأسماء والتحميل التلقائي
مقدمة إلى مساحات الأسماءالكلمة المفتاحية useمعيار التحميل التلقائي PSR-4أداة التحميل التلقائي Composerملخص - مشروع منظم5الواجهات والعقود
مقدمة إلى الواجهاتتنفيذ الواجهاتتنفيذ واجهات متعددةالواجهة مقابل الـ Abstract Classالـ Type Hinting مع الواجهاتملخص - حاسبة الأشكال8الميثودات السحرية (Magic Methods)
مقدمة في الميثودات السحرية__toString و __debugInfo__get, __set, __isset, __unset__call و __callStatic__clone واستنساخ الكائنات__serialize و __unserializeمراجعة - Custom Collection3خصائص الكلاس
خصائص الـ Instance مقابل الخصائص الساكنة (Static)الثوابت في الكلاساتالدوال والخصائص الساكنة (Static)الخصائص الخاصة (Private) والمحمية (Protected)خصائص للقراءة فقط (Readonly) في PHP 8.1مراجعة - مدير الحساب البنكي6تعدد الأشكال (Polymorphism)
مراجعة إعادة تعريف الدوال (Method Overriding)تعدد الأشكال عبر الـ Interfacesتلميح النوع (Type Hinting) وأنواع الاتحاد (Union Types)الربط الاستاتيكي المتأخر (Late Static Binding)ملخص - معالج الدفع (Payment Processor)