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ácilConstruyamos 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 cuenta y validación para garantizar 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 del constructor paratype(string: "deposit", "withdrawal" o "transfer"),amount(float) ytimestamp(string). Todas las propiedades deben ser públicas y de solo lectura. Añade un métodogetDescription(): stringque devuelva"[type]: $[amount]"(formatea amount con 2 decimales).BankAccount.php: Incluye el archivo Transaction. Crea una clase abstractaBankAccountcon:- Promoción del constructor para
accountNumber(string, público y de solo lectura) yholderName(string, público y de solo lectura) - Una propiedad
$balanceprotegida, inicializada en 0.0 - Un array privado para almacenar el historial de transacciones
getBalance(): float: devuelve el saldo actualdeposit(float $amount): string: suma al saldo, registra la transacción y 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 del constructor para
SavingsAccount.php: Incluye el archivo BankAccount. Crea una claseSavingsAccountque extiendaBankAccountcon:- Una constante de clase
INTEREST_RATEestablecida en 0.02 (2 %) withdraw(float $amount): string: si amount supera el saldo, devuelve"Insufficient funds"; de lo contrario, descuenta el importe, registra la transacción y devuelve"Withdrew: $[amount]"applyInterest(): string: calcula los intereses sobre el saldo actual, los añade como un depósito y devuelve"Interest applied: $[interest]"
- Una constante de clase
CheckingAccount.php: Incluye el archivo BankAccount. Crea una claseCheckingAccountque extiendaBankAccountcon:- Una propiedad privada
$overdraftLimitestablecida mediante el constructor (añade un tercer parámetro con valor predeterminado 100.0) withdraw(float $amount): string: permite el retiro si amount no supera el saldo + el límite de sobregiro; devuelve"Insufficient funds (overdraft limit: $[limit])"en caso de error o"Withdrew: $[amount]"si se realiza correctamentegetOverdraftLimit(): float: devuelve el límite de sobregiro
- Una propiedad privada
Bank.php: Incluye ambos archivos de cuentas. 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. Si se realiza correctamente, deposita el dinero en la cuenta de 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 del JSON de cuentas:
[{"type": "savings", "number": "SAV001", "holder": "Alice", "initial": 1000}, {"type": "checking", "number": "CHK001", "holder": "Bob", "initial": 500, "overdraft": 200}]Formato del 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 importes 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]"(con 2 decimales)
Imprime cada resultado en una línea nueva. Formatea todos los importes monetarios con 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 permanece oculta para el código externo, demostrando una encapsulación adecuada en un contexto financiero.
Pruébalo tú mismo
<?php
require_once 'Bank.php';
// Leer entrada
$accountsJson = trim(fgets(STDIN));
$operationsJson = trim(fgets(STDIN));
// Analizar 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 cuenta al banco
// - Depositar cantidad inicial
// TODO: Procesar cada operación
// Para cada operación en $operations:
// - "deposit": Imprimir resultado de deposit()
// - "withdraw": Imprime el resultado de withdraw()
// - "transfer": Imprime el resultado de transfer()
// - "interest": Imprime el resultado de applyInterest() (solo para savings)
// - "balance": Imprime "[holder] balance: $[balance]" (2 decimales)
?>Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de la POO
Archivos externosIntroducción a la POOClases frente a objetosLa palabra clave $thisMétodosPropiedadesConstructor (__construct)Destructor (__destruct)Repaso: calculadora simple4Herencia
Herencia básicaLa palabra clave parent::Sobrescritura de métodosLa palabra clave finalClases abstractasRepaso - Jerarquía de empleados7Encapsulación
Público, protegido, privadoModificadores de acceso en profundidadGetters y settersOcultación de la informaciónPromoción del constructor (8.0)Repaso: sistema de registros de estudiantes10Conceptos avanzados de OOP
Composición vs. herenciaInyección de dependenciasClases anónimasEnums (PHP 8.1)Fibras (PHP 8.1)Análisis profundo de la clonación de objetosGeneradores e iteradores13Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository2Namespaces y carga automática
Introducción a los NamespacesLa palabra clave useEstándar de carga automática PSR-4Autoloader de ComposerRepaso: proyecto organizado5Interfaces y contratos
Introducción a las interfacesImplementación de interfacesImplementación de múltiples interfacesInterfaces vs. clase abstractaTipado con interfacesRepaso - 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 __unserializeRepaso: 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)Repaso: gestor de cuentas bancarias6Polimorfismo
Repaso de la sobrescritura de métodosPolimorfismo mediante interfacesAnotaciones de tipo y tipos uniónEnlace estático tardíoRepaso: procesador de pagos9Traits
Introducción a los TraitsUso de múltiples TraitsResolución de conflictos entre TraitsMétodos abstractos en TraitsTraits frente a la 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 aprendizaje electrónicoSistema bancarioDesarrollo de personajes de videojuegosServicio de alquiler de vehículosPractica por tu cuenta: Compilador de PHP online