La programación orientada a objetos es tu próximo paso como programador WordPress

Ésta es una traducción de un articulo inglés. Puedes encontrar el articulo original en inglés aquí.

Eres programador WordPress. Has creado algunos plugins y/o temas. Construyes sitios WordPress por tus clientes o solamente por ti. Has oído hablar de la programación orientada a objetos, pero, cada vez que lo miras, hace nadie sentido.

Tú te dices a ti mismo que la programación orientada a objetos no es útil ni valor la pena. El objetivo de este artículo es explicar este valor a ti. Al fin de este artículo, deberías tener una idea de porque deberías aprenderlo.

Administrar tus expectativas

Bueno, comencemos con lo importante. No vas a ser un programador orientado a objetos al fin de este artículo. Esto es uno de los problemas con enseñar la programación orientada a objetos.

Las personas piensan que es fácil e inmediato. Pero no leerías un artículo sobre los beneficios del ejercicio, irías a correr una vez y esperarías estar en forma. Es el mismo aquí.

Revisas la documentación PHP o un artículo sobre el tema. Pones todos tus funciones en una clase para tus plugins. Después de todo, eso es lo que la documentación WordPress te diga. ¿Pero sentiste que eso hicieras las cosas mejor? ¿Comprendiste porque estabas haciendo eso? Probablemente no.

La verdad es que eso no es evidente. Es por eso que mucha gente lucha con ello. Incluso si hay muchos recursos disponibles.

Encima de eso, mucha gente piensa que está usando la programación orienta a objetos cuando, en hecho, no está. Esto añade a la confusión sobre el tema. También lo hace mucho más difícil para ti comprender el valor de eso.

Comencemos con lo que sabes

¿Si te pregunté de explicar como programas en este momento, podrías hacerlo? Escribes código cada día, pero es posible que no estés pensando en cómo estás escribiendo ese código. ¿Si no puedes explicar que estarlo haciendo, como puedes comprender que la programación orientada a objetos es?

Así que comencemos para explicar el estilo de programación que estás usando en ahora.

¿Estilo de programación tú dices? Sí. La programación orientada a objetos es un estilo de programación. No se trata sólo de usar clases en tu código. Esta idea equivocada causa muchos problemas para ti y otras personas.

Estás programando en un estilo procedimiento

La programación por procedimientos es uno de tantos estilos de programación en existencia. Pertenece a la familia más grande de programación estructurada. Es porque los dos comparten muchas similitudes.

La programación estructurada es todo sobre el organizando tu código de una manera que lo hace más fuerte y más fácil a comprender. Ambos la programación por procedimientos y la programación orientada a objetos comparten ese mismo objetivo. La programación orientada a objetos sólo lo hace mejor si es usado correctamente.

Volvamos a la programación por procedimientos. La idea detrás de esta es simple. Organizas tu código en una serie de pasos ordenados. Esos pasos pueden ser una sentencia condicional por ejemplo. Dicho eso, siguiendo esos paso ordenados es como obtienes tu resultado.

Esta idea de pasos ordenados es como resuelves tus problemas. Eso es crítico a comprender. Cuando escribes código para resolver un problema, lo escribes como una serie de pasos específicos. Esos pasos crean tu resultado deseado o funcionalidad.

No es una mala manera de programar. A veces, incluso es la mejor solución a un problema. Por ejemplo, temas son un lugar donde código por procedimientos hace mucho sentido. Estás pasando por pasos específicos renderizando HTML.

Programación por procedimientos en la naturaleza

Echemos un vistazo al siguiendo código WordPress. Su objetivo es obtener una lista de todos los usuarios que son autores y inscritos después de una fecha específica. Puedes ver los pasos tomados para obtener esa lista de bajo:

/**
 * Obtenga todos los autores inscritos después de la fecha dada.
 *
 * @param string  $fecha
 * @param integer $limite
 *
 * @return array
 */
function obtenga_autores_inscritos_despues($fecha, $limite = 5)
{
    $resultados = array();
    $autores = get_users('who=authors&orderby=registered&order=desc');

    foreach ($autores as $autor) {
        if ($autor->user_registered > $fecha) {
            $resultados[] = $autor;
        }

        if (count($resultados) >= $limite) {
            break;
        }
    }

    return $resultados;
}

En el ejemplo encima, la función get_users es una función ayudante alrededor de la clase WP_User_Query. También podrías usar simplemente la clase WP_User_Query para lograr el mismo resultado. Actualicemos nuestro ejemplo para usar la clase WP_User_Query:

/**
 * Obtenga todos los autores inscritos después de la fecha dada.
 *
 * @param string  $fecha
 * @param integer $limite
 *
 * @return array
 */
function obtenga_autores_inscritos_despues($fecha, $limite = 5)
{
    $resultados = array();
    $query = new WP_User_Query(array(
        'who'     => 'authors',
        'orderby' => 'registered',
        'order'   => 'desc'
    ));

    foreach ($query->results as $autor) {
        if ($autor->user_registered > $fecha) {
            $resultados[] = $autor;
        }

        if (count($resultados) >= $limite) {
            break;
        }
    }

    return $resultados;
}

Los dos ejemplos usan la programación por procedimientos. Logras tu resultado deseado al usar una serie de pasos ordenados. WordPress está lleno de ejemplos como éstos. Es porque los APIs de WordPress están ahí para esconderse el uso de clases. Es una de las fuerzas de WordPress pero aún es código de procedimiento.

Ahora, echemos un vistazo a este ejemplo último.

class Autores
{
    /**
     * Obtenga todos los autores inscritos después de la fecha dada.
     *
     * @param string  $fecha
     * @param integer $limite
     *
     * @return array
     */
    public function obtenga_inscritos_despues($fecha, $limite = 5)
    {
        $resultados = array();
        $query = new WP_User_Query(array(
            'who'     => 'authors',
            'orderby' => 'registered',
            'order'   => 'desc'
        ));

        foreach ($query->results as $autor) {
            if ($autor->user_registered > $fecha) {
                $resultados[] = $autor;
            }

            if (count($resultados) >= $limite) {
                break;
            }
        }

        return $resultados;
    }
}

¿Espere esto no es programación orientada a objetos? No, no es. Envolviendo tu código en una clase no cambia como resuelves el problema. Todavía estás pasando por los mismos pasos para obtener tu resultado.

Alcanzando tus límites

Aquí está una situación común: creaste un pequeño plugin para resolver un problema. Con el tiempo, tu plugin deviene más complejo. Tus usuarios quieren más características, una página de administración, opciones, etc.

Comienzas a experimentar dolores de crecimiento. Es porque la programación por procedimientos tiene sus limitaciones. Hablemos de algunos de los problemas con los que podría encontrarse.

Dificultad a organizar tu código

Algún código, como tus páginas de administración, son fáciles de agrupar juntos. No todo el código es así aunque. Cuando divides tu código en pasos, podrías querer reutilizar un subconjunto de ello. Creas una nueva función para que puedas reutilizar ello.

“¿Dónde pongo esta función?”, te preguntas.

Comienzas a crear un archivo PHP separado para almacenarlos. ¿Pero cuándo divides este primer archivo en pequeños archivos? ¿Y cómo llamas esos archivos? Hay una lista interminable de preguntas que puedes preguntar.

La programación estructurada te hace buscar claridad en tu organización de código. Si tienes solamente funciones con pasos, pone todo sobre el mismo nivel. Las distinciones entre los tipos de funciones devienen arbitrario. Esto hace la organización de tu código difícil a manejar.

Si trabajas con un equipo, multiplicas eso por 10.

Difícil de reutilizar tu código

Tu código está bien organizado ahora. Un cliente viene a ti con un nuevo proyecto. Te gustaría reutilizar alguna funcionalidad de tu plugin en ese proyecto.

¿Como reusas docenas de funciones que actúan juntas para resolver un problema? Podrías copiar simplemente el código en el nuevo proyecto. Sin embargo, ahora tendrías ese código en dos lugares. Eso es dos veces los errores para arreglar.

Una manera común de arreglar esto es de crear un plugin para esa funcionalidad. Entonces extraes código de varios archivos en un plugin separado, repitiendo el ejercicio de organización de código otra vez.

Aún no has terminado. Necesitas condiciones adicionales para este nuevo caso de uso. A medida que añades más lógica, tus pasos devienen cada vez más complejo y más difícil a mantener. Tu solución simple ya no es tan simple.

Algunos problemas son difíciles de descomponer en pasos

Bien, entonces lograste descomponer tu código en un plugin. Tienes funciones con muchas condiciones, pero tienes una solución. Usas un args vector con valores predeterminados.

Y ahora, tu función es más de 100 líneas de código con docenas de condiciones. Pequeños cambios tienen consecuencias involuntarias porque los pasos y condiciones son complejos ahora.

“Dios mío, esto es complicado”, pienses mientras miras tus funciones.

Cuando hay un error, te esfuerzas por descifrar que pasó. Te preguntas, “¿Cuales son las condiciones o grupo de condiciones que causaron ese error?” Pero es difícil.

Es porque, a medida que problemas devienen más complejos, no puedes descomponerlos en pasos como eso. Bueno, eso no es toda la verdad. Puedes hacerlo, pero te traerá mucho dolor.

Como la programación orientada a objetos hace cosas

Como decíamos, usas programación por procedimientos para resolver problemas usando pasos ordenados. La programación orientada a objetos usa una clase o machas clases trabajando juntas para resolver un problema. Estos soluciones se llaman patrones de diseño.

Otro elemento importante de la programación orientada a objetos es que esas soluciones tienen características comunes. Dicho eso, estas características merecen su propio artículo para explicarlos correctamente.

Esto nos trae el uso de clases en la programación orientada a objetos. Vale la pena señalar que su uso es engañosa. Clases implementan características importantes que definen la programación orientada a objetos, pero no son obligatorias. Puedes implementar una solución orientada a objetos sin usar clases.

Un ejemplo usando el patrón mediador

El patrón mediador es un patrón de diseño importante. Lo usas cuando necesitas una manera para tus diferentes clases de comunicar entre ellas. La ventaja de usar el patrón mediador es que permite a estas clases de comunicar sin ser dependientes el uno del otro.

Esta dependencia entre clases se llama acoplamiento. La programación orientada a objetos siempre se esfuerza para reducir el acoplamiento entre clases. El patrón mediador es una de las soluciones a ese problema.

La versión WordPress

El patrón mediador es fundamental a WordPress. Es posible que no estés consciente de ello, pero lo usas todo el tiempo construyendo plugins. Es la API plugin.

/**
 * Hooks a function or method to a specific filter action.
 */
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
    global $wp_filter, $merged_filters;
 
    $idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
    $wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
    unset( $merged_filters[ $tag ] );
    return true;
}
 
/**
 * Call the functions added to a filter hook.
 */
function apply_filters( $tag, $value ) {
    global $wp_filter, $merged_filters, $wp_current_filter;
 
    $args = array();
 
    // Do 'all' actions first
    if ( isset($wp_filter['all']) ) {
        $wp_current_filter[] = $tag;
        $args = func_get_args();
        _wp_call_all_hook($args);
    }
 
    if ( !isset($wp_filter[$tag]) ) {
        if ( isset($wp_filter['all']) )
            array_pop($wp_current_filter);
        return $value;
    }
 
    if ( !isset($wp_filter['all']) )
        $wp_current_filter[] = $tag;
 
    // Sort
    if ( !isset( $merged_filters[ $tag ] ) ) {
        ksort($wp_filter[$tag]);
        $merged_filters[ $tag ] = true;
    }
 
    reset( $wp_filter[ $tag ] );
 
    if ( empty($args) )
        $args = func_get_args();
 
    do {
        foreach( (array) current($wp_filter[$tag]) as $the_ )
            if ( !is_null($the_['function']) ){
                $args[1] = $value;
                $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
            }
 
    } while ( next($wp_filter[$tag]) !== false );
 
    array_pop( $wp_current_filter );
 
    return $value;
}

Esto es un pequeño subconjunto de las funciones usando por la API plugin. No vamos a ver todo la API plugin. Sin embargo, estas funciones son importantes para comprender la utilidad de la programación orientada a objetos.

¿Porque esto es programación orientada a objetos?

La primera cosa que podrías haber notado es que no hay objetos usado aquí. Incluso sin objetos, esto es todavía programación orientada a objetos. Esto remonta a las funcionalidades antes mencionado. La implementación WordPress tiene algunas de las funcionalidades que una solución orientada a objetos debería tener.

Eso desacopla el código del plugin de las funciones de WordPress. El dicho “Don’t hack core” refleja la importancia de la idea de desacoplamiento. Y la API plugin es la fundación práctica de esa idea.

También las funciones de filtros mantienen una lista interna de los ganchos usando la variable global $wp_filter. Una solución orientada a objetos siempre mantiene información interna. Esta idea es una parte de una más gran funcionalidad llamado encapsulamiento. Encapsulamiento ayuda a mantener tu código modular y simple.

Desventajas de la versión WordPress

La desventaja principal de la API plugin WordPress es que dependa de una variable global. Tu información es accesible a cualquiera que desee manipularlo. No es un encapulamiento total.

El uso de variables globales limitan el reutilización del código también. Puedes copiar y pegar todo en otro proyecto. Dicho eso, no puedes reutilizar la solución en una lengua de programación que no usa globales esa manera.

No es una solución universal al problema.

Lo que esa podría parecer como clase

¿Y si WordPress no usa globales para almacenar ganchos? ¿Cómo se vería una clase implementando acciones or filtros?

class WP_Filtros
{
    protected $filtros = array();

    /**
     * Engancha una función o método a un filtro específico.
     *
     * @param string  $etiqueta
     * @param mixed   $funcion
     * @param integer $prioridad
     * @param integer $args_aceptados
     */
    public function anada($etiqueta, $funcion, $prioridad = 10, $args_aceptados = 1)
    {
    }

    /**
     * Llama todas las funciones añadidas a un filtro.
     *
     * @param string $etiqueta
     * @param mixed  $valor
     */
    public function aplique($etiqueta, $valor)
    {
    }

    /**
     * Elimina todas las funciones de un filtro.
     *
     * @param string $etiqueta
     */
    public function despeje($etiqueta)
    {
    }

    /**
     * Elimina una función de un filtro específico.
     *
     * @param string  $etiqueta
     * @param mixed   $funcion
     * @param integer $prioridad
     */
    public function elimine($etiqueta, $funcion, $prioridad = 10)
    {
    }

    /**
     * Crea una identificación única para el almacenamiento y la recuperación de una función.
     *
     * @param string  $etiqueta
     * @param mixed   $funcion
     * @param integer $prioridad
     */
    protected function cree_identificacion_unica($etiqueta, $funcion, $prioridad)
    {
    }
}

Ese ejemplo es solamente un esqueleto de la clase sí misma. Destaca como una clase puede arreglar las desventajas de la versión con funciones. Tus ganchos no pueden estar manipulados porque almacenas ellos en el objeto. Eso es lo que la palabra reservada “protected” hace.

Es fácil de reutilizar la clase en tus otros proyectos. Si deseas que tu plugin use su proprio sistema de ganchos, podrías hacerlo. Sin embargo, hay nadie razón de hacerlo.

La programación orientada a objetos se trata de resolver problemas más difíciles

Mientras el ejemplo es simple, ha resuelto todos los problemas mencionados antes. Lograste:

  • Organizar tu código alrededor de un problema que estás resolviendo.
  • Hacer tu código más fácil a reutilizar.
  • Resolver un problema complejo sin escribir código sucio.

Y eso realmente que esto es. La razón porque deberías aprender la programación orientada a objetos. No es porque es popular y todos le utilizan.

Se trata de los problemas que estás tentando resolver. Haciendo cosas más complicadas sin los dolores de cabeza de usar funciones y hacer la misma cosa una y otra vez.

Nota: Me gustaría agradecer Anthony Ferrara por este artículo (en inglés) que me dio algo de mi inspiración. Da una breve pero esclarecedor visión de conjunto de la programación por procedimientos vs orientada a objetos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *