add_action referencia una clase

31

¿Es posible hacer referencia a una clase en lugar de una función en 'add_action'? Parece que no puedo resolverlo. Aquí hay un ejemplo básico de la función en cuestión.

add_action( 'admin_init', 'MyClass' );
class MyClass {
     function __construct() {
          .. This is where stuff gets done ..
     }
}

Así que sí, eso no funciona. También he intentado:

$var = new MyClass();
add_action( 'admin_init', array( &$var ) );

Y:

$var = new MyClass();
add_action( 'admin_init', array( &$var, '__construct' ) );

Y también:

add_action( 'admin_init', 'MyClass::__construct' );

¿Hay alguna forma de hacerlo sin tener que crear una función separada que carga la clase? Me gustaría poder ejecutar el constructor de clases a través de add_action. Eso es todo lo que necesita ser cargado para que la bola ruede.

    
pregunta Matthew Ruddy 05.04.2012 - 15:44

7 respuestas

56

No, no puede "inicializar" o crear una instancia de la clase a través de un gancho, no directamente. Siempre se requiere algún código adicional (y no es algo deseable poder hacerlo, ya que estás abriendo una lata de gusanos para ti).

Aquí hay una mejor manera de hacerlo:

class MyClass {
     function __construct() {
          add_action( 'admin_init',array( $this, 'getStuffDone' ) );
     }
     function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
$var = new MyClass();

Por supuesto, uno podría crear una clase de interfaz para simplificarlo aún más para el caso general:

class IGetStuffDone {
    function IGetStuffDone(){
        add_action( 'admin_init',array( $this, 'getStuffDone' ) );
    }
    public abstract function getStuffDone();
}

Tenga en cuenta que, como interfaz, no puede crear un objeto de este tipo directamente, pero podría crear una subclase, lo que le permite decir:

class CDoingThings extends IGetStuffDone {
    function getStuffDone(){
        // doing things
    }
}
$var = new CDoingThings();

Lo que luego agregaría automáticamente todos los ganchos, ¡solo necesitas definir qué se está haciendo exactamente en una subclase y luego crearlo!

En constructores

No agregaría un constructor como función de enlace, es una mala práctica y puede provocar muchos eventos inusuales. También en la mayoría de los idiomas, un constructor devuelve el objeto del que se crea una instancia, por lo que si su gancho necesita devolver algo como en un filtro, no devolverá la variable filtrada como desea, sino que devolverá el objeto de clase.

Llamar a un constructor o a un destructor es una práctica de programación muy, muy, muy mala, sin importar en qué lenguaje esté, y nunca debe hacerse.

Los constructores también deben construir objetos, para inicializarlos listos para usar, no para el trabajo real. El trabajo que debe realizar el objeto debe estar en una función separada.

Métodos de clase estáticos, y no es necesario instanciar / inicializar en absoluto

Si su método de clase es un método de clase estático, puede pasar el nombre de la clase entre comillas en lugar de $this como se muestra a continuación:

class MyClass {
     public static function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
add_action( 'admin_init', array('MyClass','getStuffDone' ) );

Cierres & PHP 5.3

Lamentablemente, no puedes evitar que la línea cree la nueva clase. La única otra solución para omitirlo involucraría el código de la placa de la caldera que aún tiene esa línea y requeriría PHP 5.3+, por ejemplo:

add_action('admin_init',function(){
    $var = new MyClass();
    $var->getStuffDone();
});

En qué punto también puede omitir la clase y simplemente usar una función:

add_action('admin_init',function(){
    // do stuff
});

Pero tenga en cuenta que ahora ha introducido el espectro de funciones anónimas. No hay forma de eliminar la acción anterior usando remove_action , y esto puede y causa un gran dolor para los desarrolladores que tienen que trabajar con el código de otras personas.

En Ampersands

Es posible que veas acciones utilizadas de esta forma:

add_action( &$this, 'getStuffDone' );

Esto es malo . & se agregó nuevamente en PHP 4 cuando los objetos se pasaron como valores, no como referencias. PHP 4 tiene más de una década y no ha sido compatible con WordPress en mucho tiempo.

No hay ninguna razón para utilizar &this al agregar enlaces y filtros, y eliminar la referencia no causará problemas, e incluso puede mejorar la compatibilidad con futuras versiones de PHP

Usa esto en su lugar:

add_action( $this, 'getStuffDone' );
    
respondido por el Tom J Nowell 05.04.2012 - 16:16
9

Clase de ejemplo

Notas:

  • Inicia la clase solo una vez
    • Llame a la prioridad 0, para que pueda usar el mismo enlace con la prioridad predeterminada más adelante
    • Envuélvalo en ! class_exists para evitar llamarlo dos veces y coloque al llamante de inicio dentro
  • Haz la función init y la clase var static
  • Llame al constructor desde su inicio, cuando llame a la clase new self .

Aquí hay un ejemplo

if ( ! class_exists( 'WPSESampleClass' ) )
{
    // Init the class on priority 0 to avoid adding priority inside the class as default = 10
    add_action( 'init', array ( 'WPSESampleClass', 'init' ), 0 );

class WPSESampleClass
{
    /**
     * The Class Object
     */
    static private $class = null;

    public static function init()
    {
        if ( null === self::$class ) 
            self :: $class = new self;

        return self :: $class;
    }

    public function __construct()
    {
        // do stuff like add action calls:
        add_action( 'init', array( $this, 'cb_fn_name' ) );
    }

    public function cb_fn_name()
    {
        // do stuff 
    }
} // END Class WPSESampleClass

} // endif;

Php 5+

Please , deja fuera & . Ya estamos más allá de php4. :)

    
respondido por el kaiser 05.04.2012 - 16:16
1
if (!class_exists("AllInOneWoo")){
    class AllInOneWoo {
        function __construct(){
            add_action('admin_menu', array($this, 'all_in_one_woo') );
        }
        function all_in_one_woo(){
            $page_title = 'All In One Woo';
            $menu_title = 'All In One Woo';
            $capability = 'manage_options';
            $menu_slug  = 'all-in-one-woo-menu';
            $function   = array($this, 'all_in_one_woo_menu');
            $icon_url   = 'dashicons-media-code';
            $position   = 59;

            add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function, $icon_url, $position);
        }
        function all_in_one_woo_menu(){?>
            <div class="wrap">
                <h1><?php _e('All In One Woo', 'all_in_one_woo'); ?></h1>
            </div>
        <?php }
    }// end class
}// end if

if (class_exists("AllInOneWoo")){       
    $all_in_one_woo = new AllInOneWoo();
}
    
respondido por el Zakir Sajib 04.03.2018 - 09:14
0

Puede desencadenar eventos en su clase sin la necesidad de cargarlos inicialmente . Esto es útil si no desea cargar la clase completa por adelantado, pero necesita acceder a los filtros y acciones de WordPress.

Aquí hay un ejemplo muy simple

<?php
class MyClass
{
    public static function init()
    {
        add_filter( 'the_content', array('MyClass', 'myMethod') );
    }

    public static function myMethod($content)
    {
        $content = $content . 'Working without loading the object';
    }
}

MyClass::init();

Esta es una versión muy simplificada de la respuesta de Kaiser, pero muestra en términos simples el comportamiento. Puede ser útil para aquellos que miran este estilo por primera vez.

Otros métodos pueden iniciar el objeto si es necesario. Personalmente estoy usando este método para permitir que las partes opcionales de mi complemento pongan en cola los scripts, pero solo activen el objeto en una solicitud AJAX.

    
respondido por el John Reid 22.12.2014 - 15:02
0

Esto funciona para mí:

class foo
{
    public static function bar()
    {
        echo 'it works!';
    }
}

add_action('foo_bar', array('foo', 'bar'));
    
respondido por el Jonathan 17.03.2015 - 19:25
0

En términos generales, no agregarías una clase completa a un gancho. Los ganchos add_action() / add_filter() esperan callback funciones , que puede ser referenciado desde dentro de una clase .

Digamos que tienes una función init() dentro de tu clase, que quieres enganchar en el enganche de WordPress init .

Ponga su llamada add_action() dentro de su clase, y luego identifique la devolución de llamada de esta manera:

add_action( 'init', array( $this, 'init' ) );

(Nota: Supongo que su clase tiene un espacio de nombre correcto; de lo contrario, asegúrese de que los espacios de nombre de sus funciones de devolución de llamada estén bien definidos).

    
respondido por el Chip Bennett 05.04.2012 - 16:03
0

Debería poder hacerlo pasando el nombre de la clase en lugar del objeto instanciado:

add_action( 'init', array( 'MyClass', '__construct' ) );

(En teoría, tu otra solución también debería funcionar

$var = new MyClass();
add_action( 'admin_init', array( $var, '__construct' ) );

No estoy seguro de por qué no lo hace. Tal vez si no llamas por referencia?

    
respondido por el Boone Gorges 05.04.2012 - 16:09

Lea otras preguntas en las etiquetas