add_action référence une classe

31

Est-il possible de référencer une classe au lieu d'une fonction dans 'add_action'? Je n'arrive pas à comprendre. Voici juste un exemple de base de la fonction en question.

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

Alors oui, ça ne marche pas. J'ai aussi essayé:

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

Et:

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

Et aussi:

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

Y at-il un moyen de le faire sans avoir à créer une fonction distincte qui charge la classe? J'aimerais pouvoir simplement exécuter le constructeur de classes via add_action. C'est tout ce qui doit être chargé pour lancer le processus.

    
posée Matthew Ruddy 05.04.2012 - 15:44

7 réponses

56

Non, vous ne pouvez pas "initialiser" ou instancier la classe par un hook, pas directement. Il faut toujours du code supplémentaire (et ce n’est pas souhaitable de pouvoir le faire, car vous ouvrez une boîte de Pandore pour vous-même.

Voici une meilleure façon de le faire:

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

Bien sûr, on pourrait créer une classe d'interface pour la simplifier davantage dans le cas général:

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

Notez qu'en tant qu'interface, vous ne pouvez pas créer directement un objet de ce type, mais vous pouvez créer une sous-classe en vous permettant de dire:

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

Ce qui ajouterait automatiquement tous les points, il vous suffit de définir ce qui est exactement fait dans une sous-classe, puis de le créer!

Sur les constructeurs

Je n’ajouterais pas de constructeur en tant que fonction de hook, c’est une mauvaise pratique, qui peut mener à de nombreux événements inhabituels. De plus, dans la plupart des langages, un constructeur renvoie l'objet en cours d'instanciation. Par conséquent, si votre hook doit renvoyer quelque chose comme dans un filtre, il ne renverra pas la variable filtrée comme vous le souhaitez, mais plutôt l'objet de classe.

Appeler un constructeur ou un destructeur est une très, très très mauvaise pratique de programmation, quelle que soit la langue dans laquelle vous vous trouvez, et devrait ne jamais être fait.

Les constructeurs doivent également construire des objets, pour les initialiser, prêts à être utilisés et non pour le travail réel. Le travail à effectuer par l'objet doit figurer dans une fonction distincte.

Méthodes de classe statiques, ne nécessitant aucune instanciation / initialisation

Si votre méthode de classe est une méthode de classe statique, vous pouvez donner le nom de la classe entre guillemets plutôt que $this comme indiqué ci-dessous:

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

Fermetures & PHP 5.3

Malheureusement, vous ne pouvez pas éviter la ligne créant la nouvelle classe. La seule autre solution à éviter consiste à utiliser un code de plaque de chaudière contenant toujours cette ligne et nécessitant PHP 5.3+, par exemple:

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

À ce stade, vous pouvez également ignorer la classe et utiliser une fonction:

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

Mais gardez à l’esprit que vous avez maintenant introduit le spectre des fonctions anonymes. Il n’existe aucun moyen de supprimer l’action ci-dessus à l’aide de remove_action , ce qui peut causer des problèmes aux développeurs qui doivent travailler avec le code d’autres personnes.

Sur les esperluettes

Vous pouvez voir les actions utilisées comme ceci:

add_action( &$this, 'getStuffDone' );

C'est mauvais . & a été rajouté en PHP 4 lorsque les objets étaient passés en tant que valeurs et non en tant que références. PHP 4 a plus de dix ans et n’a pas été supporté par WordPress depuis très longtemps.

Il n'y a pas de raison d'utiliser &this lors de l'ajout de points d'ancrage et de filtres. La suppression de la référence ne posera aucun problème et pourrait même améliorer la compatibilité avec les futures versions de PHP

.

Utilisez ceci à la place:

add_action( $this, 'getStuffDone' );
    
réponse donnée Tom J Nowell 05.04.2012 - 16:16
9

Exemple de classe

Notes:

  • Commencez la classe une seule fois
    • Appelez sur la priorité 0 pour pouvoir utiliser ultérieurement le même point d'ancrage avec la priorité par défaut
    • Enveloppez-le dans un ! class_exists pour éviter de l'appeler deux fois et placez l'appelant init à l'intérieur
  • Créez la fonction init et la classe var static
  • Appelez le constructeur depuis votre init, lorsque vous appelez la classe new self .

Voici un exemple

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 +

S'il vous plaît , laissez le & en dehors. Nous sommes déjà au-delà de php4. :)

    
réponse donnée 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();
}
    
réponse donnée Zakir Sajib 04.03.2018 - 09:14
0

Vous pouvez déclencher des événements dans votre classe sans avoir à le charger au départ . C'est pratique si vous ne voulez pas charger toute la classe à l'avance, mais que vous devez accéder aux filtres et actions WordPress.

Voici un exemple très 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();

Ceci est une version très simplifiée de la réponse de Kaiser, mais montre simplement son comportement. Pourrait être utile pour ceux qui regardent ce style pour la première fois.

D'autres méthodes peuvent toujours initier l'objet si nécessaire. Personnellement, j'utilise cette méthode pour autoriser des parties facultatives de mon plug-in à mettre en file d'attente des scripts, mais uniquement en déclenchant l'objet sur une requête AJAX.

    
réponse donnée John Reid 22.12.2014 - 15:02
0

Cela fonctionne pour moi:

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

add_action('foo_bar', array('foo', 'bar'));
    
réponse donnée Jonathan 17.03.2015 - 19:25
0

De manière générale, vous ne voudriez pas ajouter une classe entière à un hook. Les add_action() / add_filter() hooks attendent des fonctions de rappel , auxquelles peut être référencé à partir de dans une classe .

Supposons que vous ayez une fonction init() dans votre classe et que vous souhaitez vous accrocher à WordPress init hook.

Placez votre add_action() call dans votre classe, puis identifiez le rappel comme suit:

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

(Remarque: je suppose que votre classe utilise correctement les noms; sinon, assurez-vous de nommer vos fonctions de rappel.)

    
réponse donnée Chip Bennett 05.04.2012 - 16:03
0

Vous devriez pouvoir le faire en passant le nom de la classe à la place de l'objet instancié:

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

(En théorie, votre autre solution devrait également fonctionner

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

Je ne suis pas sûr de comprendre pourquoi. Peut-être que si vous n'appelez pas par référence?)

    
réponse donnée Boone Gorges 05.04.2012 - 16:09

Lire d'autres questions sur les étiquettes