add_action référence une classe
7 réponses
- votes
-
- 2012-04-05
Non,vousne pouvezpas «initialiser» ouinstancier la classe via un hook,pas directement. Un code supplémentaireesttoujoursnécessaire (et cen'estpas une chose souhaitable depouvoir lefaire,car vous ouvrez uneboîte de verspour vous-même.
Voici unemeilleurefaçon deprocéder:
class MyClass { function __construct() { add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } function getStuffDone() { // .. This is where stuff gets done .. } } $var = new MyClass();
Bien sûr,onpourrait créer une classe d'interfacepour la simplifierencoreplus dans le casgénéral:
class IGetStuffDone { function IGetStuffDone(){ add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } public abstract function getStuffDone(); }
Notez qu'entant qu'interface,vousne pouvezpas créer directement un objet de cetype,mais vouspouvez créer une sous-classeen vous laissant dire:
class CDoingThings extends IGetStuffDone { function getStuffDone(){ // doing things } } $var = new CDoingThings();
Ce qui ajouterait alors automatiquementtous les hooks,il vous suffit de définirexactement ce quiestfait dans une sous-classepuis de la créer!
Sur les constructeurs
Jen'ajouteraispas de constructeur commefonction de hook,c'est unemauvaisepratique,et celapeut conduire à denombreux événementsinhabituels. Deplus,dans laplupart des langages,un constructeur renvoie l'objet quiestinstancié,donc si votre hook doit renvoyer quelque chose comme dans unfiltre,ilne retournerapas la variablefiltrée comme vous le souhaitez,mais à laplaceil retournera l'objet de classe.
L'appel direct d'un constructeur ou d'un destructeurest unetrès,très,trèsmauvaisepratique deprogrammation,quel que soit le langage dans lequel vous voustrouvez,et ne devrait jamais êtrefait.
Les constructeurs devraient également construire des objets,pour lesinitialiserprêts à être utilisés,paspour untravail réel. Letravail àeffectuerpar l'objet doit être dans unefonction distincte.
Méthodes de classe statiques,et n'ayantpas dutoutbesoin d'instancier/initialiser
Si votreméthode de classeest uneméthode de classe statique,vouspouvezpasser lenom de la classeentreguillemetsplutôt que
$this
commeindiqué ci-dessous:class MyClass { public static function getStuffDone() { // .. This is where stuff gets done .. } } add_action( 'admin_init', [ __NAMESPACE__ . '\MyClass','getStuffDone' ] );
Notez l'utilisation de
__NAMESPACE__
quiest requis si votre classeest à l'intérieur d'unespace denoms.<₹Closures
Malheureusement,vousne pouvezpas éviter la ligne créant lanouvelle classe. La seule autre solutionpour l'ignorerimpliquerait un code deplaque de chaudière qui atoujours cette ligne,parexemple:
add_action( 'admin_init', function() { $var = new MyClass(); $var->getStuffDone(); } );
À ce stade,vouspouvez aussiignorer le courset simplement utiliser unefonction:
add_action( 'admin_init', function() { // do stuff } );
Maisgardez à l'esprit que vous avezmaintenantintroduit le spectre desfonctions anonymes. Iln'y a aucunmoyen de supprimer l'action ci-dessusen utilisant
remove_action
,et celapeut causerbeaucoup de douleur aux développeurs qui doiventtravailler avec le code d'autrespersonnes.Sur lesesperluettes
Vouspouvez voir des actions utilisées comme ceci:
array( &$this, 'getStuffDone' )
C'estmauvais .
&
a été rajouté dans PHP 4 lorsque les objets étaientpassésen tant que valeurs,pasen tant que références. PHP 4 aplus de dix anset n'apas étéprisen chargepar WordPress depuistrès longtemps.Iln'y a aucune raison d'utiliser
&this
lors de l'ajout de hookset defiltres,et la suppression de la référencene posera aucunproblèmeet pourramême améliorer la compatibilité avec lesfutures versions PHPUtilisezplutôt ceci:
[ $this, 'getStuffDone' ]
No, you cannot 'initialise' or instantiate the class through a hook, not directly. Some additional code is always required ( and it is not a desirable thing to be able to do that, as you're opening a can of worms for yourself.
Here is a better way of doing it:
class MyClass { function __construct() { add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } function getStuffDone() { // .. This is where stuff gets done .. } } $var = new MyClass();
Of course one could create an interface class to simplify it for the general case even further:
class IGetStuffDone { function IGetStuffDone(){ add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } public abstract function getStuffDone(); }
Note that as an interface, you can't create an object of this type directly, but you could create a sub-class, letting you say:
class CDoingThings extends IGetStuffDone { function getStuffDone(){ // doing things } } $var = new CDoingThings();
Which would then automatically add all the hooks, you just need to define what exactly is being done in a subclass and then create it!
On Constructors
I wouldn't add a constructor as a hook function, it's bad practice, and can lead ot a lot of unusual events. Also in most languages a constructor returns the object that is being instantiated, so if your hook needs to return something like in a filter, it will not return the filtered variable as you want, but instead it will return the class object.
Directly calling a constructor or a destructor is very, very, very bad programming practice, no matter which language you're in, and should never be done.
Constructors should also construct objects, to initialise them ready for use, not for actual work. Work to be done by the object should be in a separate function.
Static class methods, and not needing to instantiate/initialise at all
If your class method is a static class method, you can pass the name of the class in quotes rather than
$this
as shown below:class MyClass { public static function getStuffDone() { // .. This is where stuff gets done .. } } add_action( 'admin_init', [ __NAMESPACE__ . '\MyClass','getStuffDone' ] );
Note the use of
__NAMESPACE__
which is required if your class is inside a namespace.Closures
Sadly you cannot avoid the line creating the new class. The only other solution to skipping it would involve boiler plate code that still has that line e.g.:
add_action( 'admin_init', function() { $var = new MyClass(); $var->getStuffDone(); } );
At which point you may as well skip the class, and just use a function:
add_action( 'admin_init', function() { // do stuff } );
But keep in mind you have now introduced the spectre of anonymous functions. There is no way to remove the above action using
remove_action
, and this can and does cause great pain for developers who have to work with other peoples code.On Ampersands
You may see actions used like this:
array( &$this, 'getStuffDone' )
This is bad.
&
was added back in PHP 4 when objects were passed as values, not as references. PHP 4 is more than a decade old, and hasn't been supported by WordPress in a very long time.There is no reason to use
&this
when adding hooks and filters, and removing the reference will cause no issues, and may even improve compatibility with future versions of PHPUse this instead:
[ $this, 'getStuffDone' ]
-
D'accord.Mercipourtout cela;vraiment appris unpeu.Jene suis vraiment à l'aise qu'avec PHPbasé sur les classesmaintenant.C'est ce quej'aifaitet celafonctionne,maispouvez-vousme dire si c'est unemauvaisepratique/incorrecte de quelquemanière que ce soit?J'aiinitié la classe dans unefonction statique,dans la classeelle-même.Puis référencé lafonction statique dans lefichier add_action.Voir ce lien: http://pastebin.com/0idyPwwYOk. Thank you from all of that; really learnt quite a bit. I'm really only getting comfortable in class based PHP now. This is what I have done, and it works, but could you tell me if it is bad practice/incorrect in any way? I've initiated the class inside a static function, within the class itself. Then referenced the static function in the add_action. See this link: http://pastebin.com/0idyPwwY
- 0
- 2012-04-05
- Matthew Ruddy
-
oui,vouspouvez lefaire de cettefaçon,bien queje puisse éviter d'utiliser `$ class` commenom de variable,cesmots onttendance à être réservés.Jepense que vousfaitestout votrepossiblepour éviter de dire quelque chose de similaire à `$ x=new Y ();` dans laportéeglobale,et vous ajoutez de la complexité là où aucunen'estnécessaire.Votretentative de réduire la quantité de code écrit aimpliqué l'écriture deplus de code!yes you could do it that way, though I could avoid using `$class` as your variable name, those words tend to be reserved. I think you're going way out of your way to avoid saying something similar to `$x = new Y();` in the global scope, and you're adding complexity where none is necessary. Your attempt to reduce the amount of code written has involved writing more code!
- 0
- 2012-04-05
- Tom J Nowell
-
Jeferais remarquer que danstous les cas ci-dessus,vousferiezmieux d'utiliser unefonctionplutôt qu'une classe,car cette classe sera detoutefaçon suppriméeet sert lemême objectif.C'est ungaspillage de ressources.N'oubliezpas que la créationet la destruction d'un objet ont un coût,vous voulezpeu d'objetset vous voulez qu'ils durent longtempsI'd point out in all of the above cases, you would be better off using a function rather than a class, as that class will be discarded anyway and serves the same purpose. It's a waste of resources. Remember, there is a cost to creating and destroying an object, you want few objects, and you want them to be long lived
- 0
- 2012-04-05
- Tom J Nowell
-
Bonpoint.J'ai changémafaçon de voir les choses.Jepense queje vais l'appeler dans laportéeglobale à laplace,en évitant le code supplémentaire.Good point. Changed the way I've been looking at it. I think I'll call it in the global scope instead, avoiding the extra code.
- 0
- 2012-04-05
- Matthew Ruddy
-
Je voudrais ajouter que si vous avezmis votre classe dans unespace denoms,vous devrez l'ajouter aussi ou add_action ()/add_filter ()ne latrouverapas - comme ceci: `` `` add_action ('admin_init' '),array ('MyNamespace \ MyClass','getStuffDone')); `` ``I would like to add that if you happen to have put your class in a namespace, you will have to add that too or add_action()/add_filter() won't find it - like this: ```add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );```
- 1
- 2018-04-27
- jschrab
-
- 2012-04-05
Exemple de classe
Remarques:
- Initier la classe une seulefois
- Appel à lapriorité 0,afin que vouspuissiez utiliser lemême hook avec laprioritépar défautplustard
- Enveloppez-le dans un
! class_exists
pour éviter de l'appeler deuxfoiset placer l'appelantinit à l'intérieur
- Créez lafonction
init
et la classe varstatic
- Appelez le constructeur depuis l'intérieur de votreinit,lorsque vous appelez la classe
new self
.
Voici unexemple
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+
Veuillez ,laissez le
&
de côté. Nous sommes déjà au-delà dephp4. :)Example class
Notes:
- Init the class only once
- Call on priority 0, so you can use the same hook with the default priority later
- Wrap it up in a
! class_exists
to avoid calling it twice and place the init caller inside
- Make the
init
function and the class varstatic
- Call the constructor from inside your init, when you call the class
new self
.
Here's an example
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, leave the
&
out. We're already beyond php4. :) -
- 2018-03-04
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(); }
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(); }
-
Veuillez ** [modifier] votre réponse **,et ajouter uneexplication: **pourquoi ** celapourrait-il résoudre leproblème?Please **[edit] your answer**, and add an explanation: **why** could that solve the problem?
- 0
- 2018-03-04
- fuxia
-
-
- 2012-04-05
Demanièregénérale,vousn'ajouteriezpas une classe entière à un hook.Les hooks
add_action()
/add_filter()
attendent des fonctions de rappel,qui peuvent être référencées depuis dansune classe .Disons que vous avez unefonction
init()
à l'intérieur de votre classe,que vous souhaitez connecter au hook WordPressinit
.Mettez votre appel
add_action()
dans votre classe,puisidentifiez le rappel comme ceci:add_action( 'init', array( $this, 'init' ) );
(Remarque:je suppose que votre classeest correctementespacée denoms; sinon,assurez-vous d'espacer vosfonctions de rappel.)
Generally speaking, you wouldn't add an entire class to a hook. The
add_action()
/add_filter()
hooks expect callback functions, which can be referenced from within a class.Let's say that you have an
init()
function inside your class, that you want to hook into the WordPressinit
hook.Put your
add_action()
call inside your class, and then identify the callback like so:add_action( 'init', array( $this, 'init' ) );
(Note: I'm assuming your class is properly namespaced; otherwise, be sure to namespace your callback functions.)
-
Et si le cours actueln'apas déjà été lancé?J'essayais d'utiliser add_actionpour lancer réellement,doncje n'aipas à ajouter $ var=new MyClass ();aupréalable ailleurs.What about if the current class hasn't already been initiated? I was trying to use add_action to actually initiate, so I don't have to add $var = new MyClass(); beforehand elsewhere.
- 0
- 2012-04-05
- Matthew Ruddy
-
Nepouvez-vouspas simplement écrire un rappelpourinstancier votre classe à `init` (oupartout où vousen avezbesoin)?Can you not just write a callback to instantiate your class at `init` (or wherever you need it)?
- 0
- 2012-04-05
- Chip Bennett
-
- 2012-04-05
Vous devriezpouvoir lefaireen passant lenom de la classe au lieu de l'objetinstancié:
add_action( 'init', array( 'MyClass', '__construct' ) );
(Enthéorie,votre autre solution devrait égalementfonctionner
$var = new MyClass(); add_action( 'admin_init', array( $var, '__construct' ) );
Jene saispaspourquoi cen'estpas le cas.Peut-être que si vousn'appelezpaspar référence?)
You should be able to do it by passing the class name instead of the instantiated object:
add_action( 'init', array( 'MyClass', '__construct' ) );
(In theory, your other solution should work too
$var = new MyClass(); add_action( 'admin_init', array( $var, '__construct' ) );
Not sure off the head why it doesn't. Maybe if you don't call by reference?)
-
Lepremierne fonctionnepas.Rendjuste lapage vide.Le secondfonctionne,mais uniquementparce que la classe a étéinitiéeen première ligne.Cela vaen quelque sorte à l'encontre de l'objectif d'ajouter l'action,car la classe a déjà étéinitiée.Mais celane faitpas ce quej'essaie defaire,c'est-à-direinitier la classe àtravers l'action.Dans le code sur lequelje travaille,l'actionn'estpas «admin_init»mais une actionpersonnalisée dans une autre classe.Jene veuxpas que lafonction «MyClass» soit lancée si l'action dans l'autre classen'estpas là.Désolé sije manque quelque chose;apprendre aufuret àmesureFirst one doesn't work. Just makes the page go blank. The second works, but only because the class has been initiated in the first line. It sort of defeats the purpose of adding the action, because the class has already been initiated. But it doesn't do what I'm trying to do, which is initiate the class through the action. In the actual code I'm working on, the action isn't 'admin_init' but a custom action within another class. I don't want the function 'MyClass' to be initiated if the action in the other class isn't there. Sorry if I'm missing something; learning as I go
- 0
- 2012-04-05
- Matthew Ruddy
-
Ouais,j'avaistort.Celane fonctionne que si vous appelez uneméthode statique `init`.Voir http://wordpress.stackexchange.com/a/48093/14052Yeah, I was wrong. That only works if you're calling a static `init` method. See http://wordpress.stackexchange.com/a/48093/14052
- 0
- 2012-04-05
- Boone Gorges
-
- 2014-12-22
Vouspouvez déclencher des événements dans votre classe sans avoir à le charger initialement .C'estpratique si vousne voulezpas charger la classe complète à l'avance,mais devez accéder auxfiltreset actions WordPress.
Voici unexempletrè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();
Ceciest une versiontrès simplifiée de la réponse de Kaisermaismontreen termes simples le comportement.Celapourrait être utilepour ceux qui regardent ce stylepour lapremièrefois.
D'autresméthodespeuventtoujours lancer l'objet sinécessaire.J'utilisepersonnellement cetteméthodepourpermettre auxparties optionnelles demonplugin demettre des scriptsen file d'attente,maisne déclenche l'objet que sur une requête AJAX.
You can trigger events in your class without the need to load it initially. This is handy if you don't want to load the full class up front, but need to access the WordPress filters and actions.
Here's a very simple example
<?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();
This is a very simplified version of Kaiser's answer but shows in simple terms the behaviour. Might be handy for those looking at this style for the first time.
Other methods can still initiate the object if required. I'm personally using this method to allow optional parts of my plugin to enqueue scripts, but only triggering the object on an AJAX request.
Est-ilpossible de référencer une classe au lieu d'unefonction dans 'add_action'?Jen'arrivepas à comprendre.Voicijuste unexemple debase de lafonctionen question.
Alors oui,çane marchepas.J'ai égalementessayé:
Et:
Et aussi:
Puis-jefaire cela detoutefaçon sans avoir à créer unefonction distincte qui charge la classe?J'aimeraispouvoir simplementexécuter le constructeur de classes via add_action.C'esttout ce qui doit être chargépour lancer lebal.