Sistema bancario
Parte de la sección Programación Orientada a Objetos del Journey de PHP de Coddy — lección 89 de 91.
Desafío
FácilVamos a construir un Sistema Bancario que gestione cuentas, transacciones y transferencias entre cuentas. Crearás un sistema con una encapsulación adecuada para proteger los datos financieros, herencia para diferentes tipos de cuentas y validación para asegurar la integridad de los datos.
Organizarás tu código en seis archivos:
Transaction.php— Crea una claseTransactionpara registrar operaciones financieras. Usa la promoción de constructor paratype(string — "deposit", "withdrawal", o "transfer"),amount(float) ytimestamp(string). Todas las propiedades deben ser public readonly. Añade un métodogetDescription(): stringque devuelva"[type]: $[amount]"(formatea el monto a 2 decimales).BankAccount.php— Incluye el archivo Transaction. Crea una clase abstractaBankAccountcon:- Promoción de constructor para
accountNumber(string, public readonly) yholderName(string, public readonly) - Una propiedad protegida
$balanceinicializada en 0.0 - Un array privado para almacenar el historial de transacciones
getBalance(): float— devuelve el saldo actualdeposit(float $amount): string— añade al saldo, registra la transacción, devuelve"Deposited: $[amount]"abstract withdraw(float $amount): string— las clases hijas implementan las reglas de retiroaddTransaction(Transaction $t): void— método protegido para añadir transacciones al historialgetTransactionCount(): int— devuelve el número de transacciones
- Promoción de constructor para
SavingsAccount.php— Incluye el archivo BankAccount. Crea una claseSavingsAccountque extienda deBankAccountcon:- Una constante de clase
INTEREST_RATEestablecida en 0.02 (2%) withdraw(float $amount): string— si el monto excede el saldo, devuelve"Insufficient funds"; de lo contrario, descuenta, registra la transacción y devuelve"Withdrew: $[amount]"applyInterest(): string— calcula el interés sobre el saldo actual, lo añade como un depósito y devuelve"Interest applied: $[interest]"
- Una constante de clase
CheckingAccount.php— Incluye el archivo BankAccount. Crea una claseCheckingAccountque extienda deBankAccountcon:- Una propiedad privada
$overdraftLimitestablecida a través del constructor (añade un tercer parámetro con un valor predeterminado de 100.0) withdraw(float $amount): string— permite el retiro si el monto no excede el saldo + el límite de sobregiro; devuelve"Insufficient funds (overdraft limit: $[limit])"en caso de fallo, o"Withdrew: $[amount]"en caso de éxitogetOverdraftLimit(): float— devuelve el límite de sobregiro
- Una propiedad privada
Bank.php— Incluye ambos archivos de cuenta. Crea una claseBankque gestione las cuentas:- Un array privado para almacenar las cuentas indexadas por número de cuenta
addAccount(BankAccount $account): void— añade una cuentafindAccount(string $accountNumber): ?BankAccount— devuelve la cuenta o nulltransfer(string $fromAccount, string $toAccount, float $amount): string— transfiere dinero entre cuentas. Devuelve"Source account not found","Destination account not found", o el resultado del retiro si este falla. En caso de éxito, deposita en el destino y devuelve"Transferred $[amount] from [from] to [to]"
main.php— Incluye el archivo Bank. Recibirás dos entradas: datos de cuentas (JSON) y operaciones (JSON).Formato JSON de cuentas:
[{"type": "savings", "number": "SAV001", "holder": "Alice", "initial": 1000}, {"type": "checking", "number": "CHK001", "holder": "Bob", "initial": 500, "overdraft": 200}]Formato JSON de operaciones:
[{"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"}]Crea el banco y todas las cuentas (depositando los montos iniciales). Procesa cada operación:
"deposit"— Imprime el resultado dedeposit()"withdraw"— Imprime el resultado dewithdraw()"transfer"— Imprime el resultado detransfer()"interest"— Imprime el resultado deapplyInterest()(solo para cuentas de ahorro)"balance"— Imprime"[holder] balance: $[balance]"(2 decimales)
Imprime cada resultado en una línea nueva. Formatea todos los montos monetarios a 2 decimales.
Recuerda que las transferencias deben ser atómicas: si el retiro falla, el depósito no debe realizarse. La propiedad protegida $balance permite que las clases hijas la modifiquen mientras se mantiene oculta del código externo, demostrando una encapsulación adecuada en un contexto financiero.
Pruébalo tú mismo
<?php
require_once 'Bank.php';
// Leer la entrada
$accountsJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));
// Analizar las entradas JSON
$accounts = (array)json_decode($accountsJson, true);
$operations = (array)json_decode($operationsJson, true);
// TODO: Crear una instancia de Bank
// TODO: Crear cuentas a partir de los datos de las cuentas
// Para cada cuenta en $accounts:
// - Si el tipo es "savings", crear SavingsAccount
// - Si el tipo es "checking", crear CheckingAccount (con sobregiro si se proporciona)
// - Añadir la cuenta al banco
// - Depositar el monto inicial
// TODO: Procesar cada operación
// Para cada operación en $operations:
// - "deposit": Imprimir el resultado de deposit()
// - "withdraw": Imprimir el resultado de withdraw()
// - "transfer": Imprimir el resultado de transfer()
// - "interest": Imprimir el resultado de applyInterest() (solo para ahorros)
// - "balance": Imprimir "[holder] balance: $[balance]" (2 decimales)
?>Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosIntroducción a OOPClases vs ObjetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Resumen - Calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasResumen - Jerarquía de empleados7Encapsulamiento
Público, Protegido, PrivadoModificadores de acceso a fondoGetters y SettersOcultamiento de informaciónPromoción de constructor (8.0)Resumen - Sistema de registros de estudiantes10Conceptos avanzados de POO
Composición vs. HerenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibers (PHP 8.1)Clonación de objetos a fondoGeneradores e Iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Espacios de nombres y Autoloading
Introducción a los espacios de nombresLa palabra clave useEstándar de Autoloading PSR-4Autoloader de ComposerResumen - Proyecto organizado5Interfaces y Contratos
Introducción a las InterfacesImplementación de InterfacesImplementación de Múltiples InterfacesInterfaz vs Clase AbstractaType Hinting con InterfacesResumen - Calculadora de Formas8Métodos mágicos
Introducción a los métodos mágicos__toString y __debugInfo__get, __set, __isset, __unset__call y __callStatic__clone y clonación de objetos__serialize y __unserializeResumen - Colección personalizada3Propiedades de clase
Propiedades de instancia vs. estáticasConstantes en clasesMétodos y propiedades estáticosPropiedades privadas y protegidasPropiedades de solo lectura (PHP 8.1)Resumen - Gestor de cuenta bancaria6Polimorfismo
Sobrescritura de métodos revisadaPolimorfismo mediante interfacesType Hinting y tipos de uniónEnlace estático tardíoResumen - Procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos de TraitsMétodos abstractos en TraitsTraits frente a herencia12Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy15Desafíos finales
Plataforma de E-LearningSistema bancarioDesarrollo de personajes de videojuegosServicio de alquiler de vehículos