Dos maneras de desarrollar plugins de WordPress: Programación funcional
Spanish (Español) translation by Eva Collados Pascual (you can also view the original English article)
Esta segunda parte de una serie que analiza dos estilos de programación diferentes (a veces llamados paradigmas de programación) que puedes usar al escribir plugins de WordPress. En la primera parte Tom McFarlin cubrió la programación orientada a objetos. En esta parte veremos la programación funcional.
Debido a que el nivel de experiencia de los lectores varía, vamos a estar hablando de programación a un alto nivel, así que si usted es un principiante, entonces usted no debe tener ningún problema en seguir adelante. Sin embargo, si eres un desarrollador más experimentado, es posible que encuentres información más útil más adelante en el artículo.
¿Qué es la programación funcional?
La programación funcional es probablemente el estilo con el que estés más familiarizado, y casi universalmente, es el estilo utilizado en los diversos sitios web de fragmentos de código de WordPress repartidos por Internet. Por esta razón, a veces se puede ver como programación de "nivel de entrada": el estilo empleado por los principiantes hasta que han aprendido a dominar la programación orientada a objetos. Esto es increíblemente engañoso, porque si bien la programación funcional es mucho más simple, no es en sí misma inferior.
La programación funcional hace hincapié en la evaluación de las funciones y evita la noción de estados u objetos como oposición a la programación orientada a objetos que fomenta la concepción del código como una actuación sobre objetos, utilizando métodos para cambiar esos objetos o interactuar con ellos. Veamos un ejemplo muy sencillo para comparar los dos estilos:
1 |
// Functional method
|
2 |
function add_two( $n ) { |
3 |
return $n +2; |
4 |
}
|
5 |
|
6 |
$a = 2; |
7 |
$b = add_two( $a ); // $b = 4; |
8 |
|
9 |
|
10 |
// Object oriented method
|
11 |
class Number { |
12 |
var $value = 0; |
13 |
|
14 |
function __construct( $a ) { |
15 |
$this->value = $a; |
16 |
}
|
17 |
|
18 |
function add_two() { |
19 |
$this->value = $this->value +2; |
20 |
}
|
21 |
}
|
22 |
|
23 |
$a = new Number( 2 ); |
24 |
echo $a->value; //Prints 2 |
25 |
$a->add_two(); |
26 |
echo $a->value; //Prints 4 |
Este sencillo ejemplo ilustra la diferencia fundamental en el estilo de los dos paradigmas: la programación funcional se centra en pasar argumentos y recibir valores procedentes de funciones. No existen 'objetos' sobre los que se actúe, solo parámetros y valores devueltos. Por el contrario, el enfoque orientado a objetos asigna a un objeto varias propiedades (en nuestro caso un 'valor') y los métodos actúan sobre esas propiedades.
Funciones: Los fundamentos
Definir funciones es muy sencillo:
1 |
function add( $number, $number2 = 1 ) { |
2 |
// Perform code acting on passed variables
|
3 |
$sum = $number + $number2; |
4 |
|
5 |
// Optional, if needed you can return a value
|
6 |
return $sum; |
7 |
}
|
Una vez declarada la función, puede utilizarse en cualquier lugar del plugin, es decir, tiene ámbito global.
1 |
$a = 4; |
2 |
$b = 7; |
3 |
echo add( $a, $b ); // Prints 11 |
Es posible que hayas notado que en la definición de add, el segundo argumento se establece igual a 1. Esto establece un valor predeterminado para $number2 (en este caso, 1) y, al hacerlo, hace que el argumento sea opcional. Si no se proporciona el argumento, el valor se toma como el valor predeterminado:
1 |
echo add( 4 ); // Prints 5 |
2 |
echo add( 4, 1 ); // Prints 5 |
Por otro lado, no se proporciona ningún valor predeterminado para el primer valor, por lo que omitir ese argumento producirá un error
1 |
echo add(); // Throws an error as $number is not defined |
También puedes tener un número variable de argumentos. Dentro de la función podemos utilizar func_num_args() para obtener el número de argumentos recibidos, mientras que func_get_arg() te permite acceder a una variable pasada determinada, indexada desde 0.
1 |
function sum() { |
2 |
// Get the number of arguments given to sum()
|
3 |
$number_args = func_num_args(); |
4 |
|
5 |
$sum = 0; |
6 |
|
7 |
if ( ! $number_args ) |
8 |
return $sum; |
9 |
|
10 |
for ( $i = 0; $i < $number_args; $i++ ) { |
11 |
$sum += func_get_arg( $i ); |
12 |
}
|
13 |
|
14 |
return $sum; |
15 |
}
|
16 |
|
17 |
echo sum( 1, 2, 3, 4 ); //Prints 10 |
18 |
echo sum( 1, 2 ); //Prints 3 |
19 |
echo sum(); //Prints 0 |
Lo anterior también se puede utilizar en métodos de objeto. Por último, declarando una variable como 'global' puedes acceder a la variable desde el interior de una función.
1 |
$a = 'Hello'; |
2 |
$b = 'World'; |
3 |
function hello_world() { |
4 |
// This is necessary to access $a and $b
|
5 |
// declared outside of the function scope.
|
6 |
global $a, $b; |
7 |
$b = $a . ' ' . $b; |
8 |
}
|
9 |
hello_world(); |
10 |
echo $b; // Prints 'Hello World' |
¿Por qué usar la programación funcional?
Decidir qué estilo de programación usar se reduce al juicio, y sí, a la preferencia personal. No es más correcto o incorrecto usar la programación funcional sobre la orientada a objetos, pero con frecuencia existe un estilo que es más adecuado dependiendo de lo que estés tratando de lograr.
A veces, la programación orientada a objetos simplemente no es necesaria y solo complica demasiado las cosas o introduce código superfluo. Un ejemplo podrían ser las diversas funciones de "utilidad" que proporciona WordPress. Se trata de funciones genéricas que sirven para realizar un propósito particular. Por ejemplo, wp_trim_words( $text, $num_words) simplemente acorta la cadena dada a un tamaño determinado (en palabras). No añadiría nada definir wp_trim_words() como un método que pertenece a algún objeto y daría lugar a código más feo. Con la programación funcional, una línea basta.
Una ventaja de la programación funcional, particularmente para principiantes, es su simplicidad. No tienes que preocuparte por las funciones estáticas, privadas o protegidas, todas son globales. Tampoco existe la noción de variables estáticas. En el nivel más básico, la función devuelve una salida derivada de lo que le hayas dado. Por ejemplo, get_the_title( 7 ) devolverá el título de la entrada con el ID 7.
Otra ventaja de la programación funcional es que las funciones son accesibles a nivel global. Con los programas orientados a objetos, para actuar sobre un objeto específico, debes pasar alrededor de ese objeto. Esto a veces puede ser complicado. Para ilustrar esto tomemos un ejemplo de la primera parte:
1 |
class DemoPlugin { |
2 |
public function __construct() { |
3 |
add_action( 'wp_enqueue_scripts', array( $this, 'register_plugin_scripts' ) ); |
4 |
}
|
5 |
|
6 |
public function register_plugin_scripts() { |
7 |
// Register plugin scripts
|
8 |
}
|
9 |
}
|
10 |
$demo_plugin = new DemoPlugin(); |
Cuando WordPress almacena el método register_plugin_scripts() para que pueda invocarse cuando se desencadena la acción wp_enqueue_scripts lo hace haciendo referencia no solo al método, sino también al objeto $demo_plugin. Esto se debe a que el mismo método para diferentes instancias de un objeto se consideran métodos diferentes, es decir, $demo_plugin->register_plugin_scripts() y $copy_of_demo_plugin->register_plugin_scripts() no son los mismos. Esto puede parecer extraño, pero los métodos pueden comportarse de manera diferente para diferentes instancias de la misma clase, por lo que necesitamos hacer referencia tanto al método como a la instancia.
Pero, ¿por qué importa esto? Hace que sea muy difícil para un plugin o tema de terceros desenganchar ese método, ya que para ello tendrían que invocar:
1 |
remove_action( 'wp_enqueue_scripts', array( $demo_plugin, 'register_plugin_scripts' ) ); |
Pero en general no tendrán acceso a la variable $demo_plugin. (Nota: si el método se declara estático, entonces podrías sortear esto).
Programación funcional y orientada a objetos en WordPress
Por supuesto, la programación orientada a objetos tiene sus ventajas, como se discutió en la primera parte. Como Tom también mencionó, es inevitable cuando se utiliza la API de widgets de WordPress. Otro ejemplo común es WP_Query(). Aquí un enfoque orientado a objetos es claramente el mejor: tienes un objeto (en este caso una consulta), que tiene varias propiedades (es decir, criterios de búsqueda, información de paginación, resultados coincidentes) y deseas actuar sobre esa consulta (analizarla, generar y desinfectar el SQL correspondiente y devolver los resultados).
WP_Query() muestra cuán potente puede ser la programación orientada a objetos cuando se utiliza correctamente. Después de iniciar la consulta:
1 |
$the_query = new WP_Query( array(...) ); |
No sólo se puede acceder a los resultados, sino también a otra información, como los valores de paginación: cuántas páginas de resultados hay, qué página se está viendo, el número total de resultados y el 'tipo' de consulta, por ejemplo, $the_query->is_search(), $the_query->is_single() etc. También está toda la infraestructura de "bucle";
1 |
if ( $the_query->have_posts() ) { |
2 |
echo '<ul>'; |
3 |
while( $the_query->have_posts() ): $the_query->the_post(); |
4 |
// The Loop
|
5 |
echo '<li>' . get_the_title( $the_post->ID ) . '</li>'; |
6 |
endwhile; |
7 |
echo '</ul>'; |
8 |
}
|
9 |
wp_reset_postdata(); |
Lo que oculta todos los malabares internos de los resultados y los globales detrás de una API amigable con el ser humano.
¿Y qué hay de get_posts()? Esto solo sirve como contenedor para WP_Query() y simplemente devuelve una matriz de entradas que coinciden con la consulta. Como tal, no se obtienen las "florituras" de WP_Query(), pero es un poco más eficiente. Así que utilizar get_posts() o WP_Query() dependerá de tu caso de uso (por ejemplo, si necesitas paginación o no), pero también se reduce preferencias personales.
1 |
$results = get_posts( array( ... ) ); |
2 |
|
3 |
if ( $results ) { |
4 |
echo '<ul>'; |
5 |
foreach( $results as $the_post ) { |
6 |
echo '<li>' . get_the_title( $the_post->ID ) . '</li>'; |
7 |
}
|
8 |
echo '</ul>'; |
9 |
}
|
Resumen
Esperamos que estos dos artículos hayan ayudado a resaltar las ventajas y desventajas de estos estilos de programación. El punto de partida es que aquí no hay nada correcto o incorrecto, cada programador tendrá su propia preferencia personal. Pero algunos contextos se prestan más fácilmente a un cierto estilo de programación, y por tanto deberías esperar que tu plugin contenga una combinación de ambos.



