Programación orientada a matrices

Si trabaja con PHP el tiempo suficiente, inevitablemente encontrará un método de clase que se parece a esto:

No hay nada particularmente malo con el código anterior; hace el trabajo. Analicemos esas docenas de líneas en el método búsqueda :

Intencionalmente mantuve el ejemplo breve, pero el código escrito con este estilo tiende a crecer exponencialmente a medida que se agregan nuevos parámetros o se introducen nuevas reglas comerciales. Las matrices PHP están abiertas a modificaciones ad-hoc, por lo que cualquier código que funcione con la matriz está lleno de comprobaciones vacías , operadores de fusión nulos u otras validaciones.

Eso se debe a que el autor de este código (el suyo verdaderamente) ha asignado un contexto implícito a una estructura de datos de forma libre. La matriz representa parámetros para una búsqueda y existen reglas sobre cómo se deben componer esos parámetros.

Solo use objetos

Veamos si podemos limpiar el ejemplo con un objeto en lugar de una matriz de parámetros. Primero necesitamos una nueva clase para representar los parámetros de búsqueda:

Ahora la función búsqueda original se puede escribir así:

Entonces, el método search ahora es bastante simple. Por otro lado, para usar el método tendríamos que hacer esto:

Hasta ahora, no hemos ganado mucho. La función search es breve y sencilla, pero ahora la validación de datos debe realizarse en todos los lugares donde se crea y utiliza la clase SearchParams . No queremos obligar a un usuario de esta interfaz a validar sus propios datos.

Encapsular

Reescribamos la clase SearchParams para encapsular la validación de sus parámetros:

Observe el constructor privado y el método de fábrica estática. Esto asegura que la única forma de crear una clase SearchParams es pasar los datos a través de la fábrica y hacer cumplir las reglas de validación.

Ahora se puede usar así:

Beneficio

En este punto, tenemos algunos beneficios reales que discutir. La validación de datos y la manipulación de parámetros de búsqueda se han movido fuera de la búsqueda en sí. Ya no tenemos una estructura de forma libre en la que no podemos confiar; el código de la clase User puede olvidarse de asegurarse de que los datos se vean de una manera particular.

Sin embargo, todavía tenemos algunas matrices flotando. La clase padre tiene un método request que espera una matriz. Si tenemos el control de esa clase, deberíamos considerar refactorizarla también.

Otro ejemplo

Un patrón común orientado a matrices implica la construcción de una matriz a partir de varias operaciones. Eche un vistazo a este doloroso ejemplo:

El código anterior es un desastre; sufre los mismos problemas que el primer ejemplo. Sin embargo, hay otro anti-patrón acechando aquí que quiero resaltar. La matriz $ transaction se modifica varias veces, cada vez que crece o se reduce en una bolsa diferente de parámetros antes de pasar a otros métodos para realizar algún trabajo.

Tengo muchas preguntas.

No puede mirar este código y obtener una buena imagen de lo que está sucediendo bajo el capó sin rastrear la vida de $ transacción y mantener muchas rutas ciclomáticas de código en su cabeza. La “transacción” en este caso se difunde a través de muchos métodos. Es más fácil escribir sin querer un código complicado como este cuando todo es una matriz.

La solución aquí es deshacerse de las matrices.

Sin profundizar en las implementaciones individuales, podemos ver que hemos creado tres nuevos objetos: PostParams , Transaction y Processor . Esto significa que tuvimos que escribir estas implementaciones y crear un poco más de código que cuando usamos una matriz simple, pero el código anterior es mucho más fácil de leer y razonar. Las implementaciones de create , getProcessor y process se pueden refactorizar para aceptar estos objetos, y probablemente también se volverán más limpias, al igual que nuestro original código> búsqueda ejemplo.

Mantenlo OOP

Transmitir arreglos humildes parece simple en la superficie y es fácil de escribir ya que no estamos creando tantas clases, pero hace que el código se vuelva sutilmente más complejo ya que no podemos confiar en la estructura del arreglo. El intercambio de contexto implícito con clases explícitas nos permite confiar en nuestro código; hace que nuestro código sea simple, más sólido y más fácil de entender.