Seguramente a vos nunca te haya pasado lo que te voy a contar, pero tenés algún amigo al que sí.
Uno de esos pobres programadores que se enfrenta a una codebase que combina cosas como:
function shipTo(string $street, int $number, string $postalCode, string $city): void; function getDeliveryCost(string $city, string $street, int $number, string $postalCode): float; function canPurchase(string $city, string $postalCode, int $number, string $street): bool;
Claramente, este tipo de estructuras son una invitación al error.
A partir de PHP 8.0 existen los argumentos nombrados, con lo cual el problema está de algún modo mitigado aunque, en mi opinión, es más un workaround que una solución como tal.
Un mejor enfoque sería tomar una mirada algo menos pegada al código y más cercana al dominio y darse cuenta de que aquí hay un concepto implícito: la dirección postal.
Lo correcto en esta situación sería implementar una clase que modele este concepto de dominio:
<?php declare(strict_types=1); readonly class Address { public function __construct( private string $street, private int $number, private string $postalCode, private string $city ) { } public function __toString(): string { return "$this->street $this->number, $this->postalCode, $this->city"; } }
Y luego hacer que las funciones usen instancias de este objeto:
function shipTo(Address $address): void; function getDeliveryCost(Address $address): float; function canPurchase(Address $address): bool;
Ahora sí el código de tu amigo se ve mucho más bonito, limpio, mantenible y profesional, ¿cierto?
Pero… ¿cómo puede tu amigo implementar este cambio sin romper todo el código ya está escrito usando las firmas viejas?
Paso intermedio: wrappers al rescate
Aunque parezca una tarea titánica (y ciertamente lo es si se intenta hacer en un solo paso), es muy sencillo realizar el cambio en forma segura. Sólo requiere un poquito de planificación.
La clave está en crear un intermediario que haga de adaptador entre el código viejo y el nuevo.
Tomemos por ejemplo la función shipTo
. Queremos pasar de esta firma function shipTo(string $street, int $number, string $postalCode, string $city): void
a esta otra: function shipTo(Address $address): void
pero, si simplemente hacemos el cambio, todas las llamadas a la vieja comenzarán a fallar.
Lo que podemos hacer es:
- Crear la nueva función con la firma objetivo (
function shipTo(Address $address): void
) - Copiar el cuerpo de la función vieja a la nueva
- Adaptar el código de la nueva función para que use objetos
Address
en lugar de parámetros individuales - Cambiar el código en la función original por una llamada a la nueva implementación, pasándole como parámetro una nueva instancia de Address creada a partir de los parámetros recibidos:
function shipTo(string $street, int $number, string $postalCode, string $city): void { shipTo(new Address($street, $number, $postalCode, $city)); }
- Marcar el método (o función) viejo como
#[Deprecated]
(O@Deprecated
si tu versión de PHP no soporta atributos), de modo que, en lo sucesivo, todo el equipo sepa que debe usar el método nuevo.
Una vez hecho todo esto será cuestión de tiempo hasta que todo el código haya sido migrado hacia la implementación que usa objetos.
Un detalle importante:
Si prestaste atención abrás notado que hay dos funciones con el mismo nombre: shipTo
.
Desafortunadamente, PHP no soporta la sobrecarga de funciones como otros lenguajes (Java por ejemplo) lo cual hará que, para que todo esto funcione, sea necesario ensuciar un poquito el código usando un nombre diferente para la nueva función, por ejemplo shipToAddress
.
No es lo que más me gusta pero lo considero un precio aceptable.
Así que ahora sí podés ir a contarle a tu amigo cómo hacer para dejar de sufrir ese código que vaya uno a saber quién escribió.
- Introducir objetos en un código viejo - 11/09/2025
- Ejemplo de inyección de depencias en PHP - 02/09/2025
- Un ejemplo de Laravel y React sobre Docker que funciona - 10/01/2025