Uso de clases y objetos en eventos
Hasta ahora solamente estuvimos viendo cómo asignar funciones a eventos. Sin embargo, cuando creemos nuestros plugins, o cuando estemos mirando el código de plugins de terceros, nos vamos a encontrar con que necesitamos usar métodos de clases, en lugar de funciones, para llevar a cabo algún proceso.
La solución más simple a este problema es crear funciones que sirvan a manera de contenedores de los métodos de clase. Por ejemplo, podemos tener algo como esto.
<?php
class My_Class {
function my_method() {
//
}
}
add_action( 'my_action', 'my_method_wrapper' );
function my_method_wrapper() {
$obj = new My_Class;
$obj->my_method();
}
do_action( 'my_action' );
De esta manera tenemos una función que instancia el objeto que queremos usar y ejecuta el método que necesitamos. El problema que tenemos acá es que es la función misma la que crea un nuevo objeto, el cual no va a ser accesible por fuera de ella, y probablemente necesitemos usar ese objeto para otras cosas por fuera de la función. Una solución a esto sería pasar el objeto como parámetro a la función desde do_action()
.
<?php
class My_Class {
public function my_method() {}
}
add_action( 'my_action', 'my_method_wrapper' );
function my_method_wrapper( $obj ) {
$obj->my_method();
}
$obj = new My_Class;
do_action( 'my_action', $obj );
Es una posibilidad, y puede servirnos para muchos casos, pero esta propuesta depende de que tengamos acceso al llamado a do_action()
y de que tengamos control de lo que se le pasa como parámetro. Eso es algo que no va a pasar cuando estemos interactuando con eventos nativos de WordPress.
Este problema se resuelve pasando directamente el método como parámetro a add_action()
o add_filter()
. Para eso necesitamos que el segundo parámetro sea un array con dos elementos: el primero va a corresponder al objeto o al nombre de la clase que contiene nuestro método, y el segundo va a ser el nombre del método.
<?php
class My_Class {
public function my_method() {}
}
$obj = new My_Class;
add_action( 'my_action', array( $obj, 'my_method' ) );
do_action( 'my_action' );
Lo que necesitamos para que esto funcione es que el objeto haya sido instanciado antes de hacer nuestro llamado a add_action()
.
Otra posibilidad es asignar el método al evento directamente dentro de un método de la clase misma, por ejemplo el constructor. De esta manera, cuando el objeto se instancia, directamente se asigna el método al evento. Esto es lo mismo que decir que el objeto "sabe" cuáles de sus métodos van a asignarse a un evento.
<?php
class My_Class {
public function __construct() {
add_action( 'my_action', array( $this, 'my_method' ) );
}
public function my_method() {}
}
$obj = new My_Class;
do_action( 'my_action' );
Además, tenemos la posibilidad de asignar métodos estáticos a eventos, es decir métodos que no necesitan conocer el contexto de una instancia de la clase, tal como pasa con las funciones. Si ya contamos con el objeto instanciado, es decir si ya hicimos un llamado a $obj = new My_Class
, podemos asignar el método estático usando el objeto, tal como lo veníamos haciendo.
<?php
class My_Class {
public static function my_method() {}
}
$obj = new My_Class;
add_action( 'my_action', array( $obj, 'my_method' ) );
do_action( 'my_action' );
Sin embargo, esto puede no ocurrir; puede darse el caso en el que necesite usar ese método estático de mi clase antes de que la clase misma sea instanciada. En ese caso, en lugar de pasar el objeto como primer elemento del hook, voy a pasar directamente el nombre de la clase.
<?php
class My_Class {
public static function my_method() {}
}
add_action( 'my_action', array( 'My_Class', 'my_method' ) );
do_action( 'my_action' );
Algo muy importante a tener en cuenta a la hora de asignar métodos de clase a eventos es que esos métodos siempre tienen que ser de acceso público; WordPress va a mostrar un error si un método usado como hook es privado o está protegido. Por ejemplo, esto no va a funcionar:
<?php
class My_Class {
private function my_method() {}
protected function my_other_method() {}
}
$obj = new My_Class;
add_action( 'my_action', array( $obj, 'my_method' ) );
add_action( 'my_action', array( $obj, 'my_other_method' ) );
do_action( 'my_action' );
Una recomendación en materia de extensibilidad que suele hacerse entre los desarrolladores que trabajan con WordPress es que los métodos de clase que vayamos a crear no sean nunca privados, o que lo sean solo en casos extremadamente necesarios. En lugar de hacerlos privados, la recomendación es dejarlos como protegidos, para que de esta manera otros desarrolladores puedan extender nuestras clases desde sus propios plugins si lo necesitan.
Por otra parte, nótese que, si bien estuvimos usando acciones para los ejemplos de este capítulo, estas mismas formas de manipular métodos también son por completo aplicables a filtros.
Todos estas son formas totalmente válidas de trabajar con métodos en la implementación del paradigma de programación orientada a eventos que hace WordPress, pero ninguna es una solución definitiva. La solución óptima depende mucho de las características del plugin con el que estemos trabajando, por lo cual está en nosotros probar y evaluar cuál nos conviene más para resolver un problema determinado.