add_action fa riferimento a una classe
7 risposta
- voti
-
- 2012-04-05
No,nonpuoi "inizializzare" oistanziare la classetramite un hook,non direttamente. È semprenecessario del codice aggiuntivo (enon è una cosa desiderabilepoterlofare,poiché stai aprendo una lattina di wormperte stesso.
Ecco unmodomiglioreperfarlo:
class MyClass { function __construct() { add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } function getStuffDone() { // .. This is where stuff gets done .. } } $var = new MyClass();
Ovviamente sipotrebbe creare una classe diinterfacciaper semplificarla ulteriormenteperil casogenerale:
class IGetStuffDone { function IGetStuffDone(){ add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } public abstract function getStuffDone(); }
Nota che comeinterfaccia,nonpuoi creare un oggetto di questotipo direttamente,mapotresti creare una sottoclasse,permettendoti di dire:
class CDoingThings extends IGetStuffDone { function getStuffDone(){ // doing things } } $var = new CDoingThings();
Che quindi aggiungerebbe automaticamentetuttigli hook,devi solo definire cosa vienefattoesattamentein una sottoclassee quindi crearlo!
Sui costruttori
Non aggiungerei un costruttore comefunzione hook,è una cattivapraticae puòportare amoltieventiinsoliti. Inoltrenellamaggiorparte dei linguaggi un costruttore restituisce l'oggetto che vieneistanziato,quindi seiltuo hook deve restituire qualcosa di similein unfiltro,non restituirà la variabilefiltrata come desideri,ma restituiràinvece l'oggetto classe.
Chiamare direttamente un costruttore o un distruttore è unapratica diprogrammazionemolto,molto,moltopessima,indipendentemente dal linguaggioin cuiti trovi,e non dovrebbemaiesserefatto.
I costruttori dovrebbero anche costruire oggetti,perinizializzarliprontiper l'uso,nonperil lavoroeffettivo. Il lavoro che deveessere svolto dall'oggetto dovrebbeesserein unafunzione separata.
Metodi di classe staticie non ènecessario creare alcunaistanza/inizializzazione
Seiltuometodo di classe è unmetodo di classe statico,puoipassareilnome della classetra virgolette anziché
$this
comemostrato di seguito:class MyClass { public static function getStuffDone() { // .. This is where stuff gets done .. } } add_action( 'admin_init', [ __NAMESPACE__ . '\MyClass','getStuffDone' ] );
Nota l'uso di
__NAMESPACE__
che è richiesto se latua classe è all'interno di uno spazio deinomi.<⇨Chiusure"
Purtroppononpuoievitare la riga che crea lanuova classe. L'unica altra soluzioneper saltarlo sarebbeil codice dellatarga della caldaia che ha ancora quella riga,adesempio:
add_action( 'admin_init', function() { $var = new MyClass(); $var->getStuffDone(); } );
A quelpuntopuoi anche saltare la lezionee usare semplicemente unafunzione:
add_action( 'admin_init', function() { // do stuff } );
Matieni presente che ora haiintrodotto lo spettro dellefunzioni anonime. Non c'èmodo di rimuovere l'azione di cui sopra utilizzando
remove_action
,e questopuò causaree causa ungrande dolorepergli sviluppatori che devono lavorare conil codice di altrepersone.Sue commerciali
Potresti vedere azioni usatein questomodo:
array( &$this, 'getStuffDone' )
Questonon vabene .
&
è stato aggiunto dinuovoin PHP 4 quandogli oggetti venivanopassati come valori,non come riferimenti. PHP 4 hapiù di dieci annie non è stato supportato da WordPress damoltotempo.Non c'è alcunmotivo per utilizzare
&this
quando si aggiungono hooke filtrie la rimozione del riferimentonon causeràproblemie potrebbepersinomigliorare la compatibilità con le versionifuture PHPUsa questoinvece:
[ $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' ]
-
Ok.Grazie datutto ciò;ho davveroimparato unbelpo '.Adessomi sto davvero sentendo amio agio solo con PHPbasato sulla classe.Questo è quello che hofatto,e funziona,mapotresti dirmi se è una cattivapratica/scorrettain qualchemodo?Ho avviato la classe all'interno di unafunzione statica,all'interno della classe stessa.Quindi hafatto riferimento allafunzione staticain add_action.Vedi questo link: 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
-
sì,potrestifarloin questomodo,anche sepotreievitare di usare "$ class" comenome della variabile,quelleparoletendono adessere riservate.Penso chetuti stiafacendo dituttoperevitare di dire qualcosa di simile a "$ x=new Y ();"nell'ambitoglobale,e stai aggiungendo complessità dovenon ènecessario.Iltuotentativo di ridurre la quantità di codice scritto ha comportato la scrittura dipiù codice!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
-
Vorrei sottolinearein tuttii casiprecedenti,sarebbemeglio usare unafunzionepiuttosto che una classe,poiché quella classe verrà comunque scartatae ha lo stesso scopo.È uno spreco di risorse.Ricorda,crearee distruggere un oggetto ha un costo,vuoipochi oggettie vuoi che durino a lungoI'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
-
Buonpunto.Ha cambiatoilmodoin cui loguardavo.Penso che lo chiameròinvecenell'ambitoglobale,evitandoil codiceextra.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
-
Vorrei aggiungere che seti capita di avermesso latua classein uno spazio deinomi,dovrai aggiungerla anchetu o add_action ()/add_filter ()non latroverà -in questomodo: `` `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
Classe diesempio
Note:
- Inizia la lezione solo una volta
- Chiama conpriorità 0,in modo dapoter utilizzare lo stesso hook con laprioritàpredefinitain seguito
- Avvolgiloin un
! class_exists
perevitare di chiamarlo due voltee inserireil chiamanteinit all'interno
- Crea lafunzione
init
e la classe varstatic
- Chiamail costruttore dall'interno deltuoinit,quando chiami la classe
new self
.
Ecco unesempio
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+
Perfavore ,lasciafuori
&
. Siamogià oltrephp4. :)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(); }
-
Perfavore ** [modifica] latua risposta **e aggiungi una spiegazione: **perché ** questopotrebbe risolvereilproblema?Please **[edit] your answer**, and add an explanation: **why** could that solve the problem?
- 0
- 2018-03-04
- fuxia
-
-
- 2012-04-05
Ingenerale,non aggiungeresti un'intera classe a un hook.Gli hook
add_action()
/add_filter()
si aspettano funzioni di callback,a cui èpossibile fare riferimento all'internouna classe .Supponiamo chetu abbia unafunzione
init()
all'interno dellatua classe,che desideri agganciare all'hookinit
di WordPress.Inserisci latua chiamata
add_action()
all'interno dellatua classe,quindiidentificail callbackin questomodo:add_action( 'init', array( $this, 'init' ) );
(Nota:presumo che latua classe abbia uno spazio deinomi appropriato;in caso contrario,assicurati di utilizzare lo spazio deinomiper lefunzioni di callback.)
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.)
-
E se la classe correntenon ègià statainiziata?Stavo cercando di utilizzare add_actionperiniziareeffettivamente,quindinon devo aggiungere $ var=new MyClass ();in anticipo altrove.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
-
Nonpuoi semplicemente scrivere un callbackperistanziare latua classe su `init` (o ovunqueti serva)?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
Dovrestiesserein grado difarlopassandoilnome della classeinvece dell'oggettoistanziato:
add_action( 'init', array( 'MyClass', '__construct' ) );
(Inteoria,anche l'altra soluzione dovrebbefunzionare
$var = new MyClass(); add_action( 'admin_init', array( $var, '__construct' ) );
Non sono sicuro delmotivoper cuinon lofa.Forse senon chiamiper riferimento?)
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?)
-
Ilprimononfunziona.Rende solo lapagina vuota.Il secondofunziona,ma soloperché la classe è stata avviatanellaprima riga.In qualchemodo sconfigge lo scopo di aggiungere l'azione,perché la classe ègià stata avviata.Manonfa quello che sto cercando difare,che è avviare la classe attraverso l'azione.Nel codiceeffettivo su cui sto lavorando,l'azionenon è "admin_init"ma un'azionepersonalizzata all'interno di un'altra classe.Non voglio che lafunzione "MyClass" venga avviata se l'azionenell'altra classenon èpresente.Scusa semi manca qualcosa;imparandomentre vadoFirst 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
-
Sì,mi sbagliavo.Funziona solo se stai chiamando unmetodo "init" statico.Vedi 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
Puoi attivareeventinellatua classe senza lanecessità di caricarla inizialmente .Questo è utile senon vuoi caricare la classe completain anticipo,ma devi accedere aifiltrie alle azioni di WordPress.
Ecco unesempiomolto semplice
<?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();
Questa è una versionemolto semplificata della risposta di Kaisermamostrain termini sempliciil comportamento.Potrebbeessere utileper chiguarda questo stileper laprima volta.
Altrimetodipossono ancora avviare l'oggetto,senecessario.Personalmente sto utilizzando questometodoper consentire aparti opzionali delmioplugin di accodaregli script,ma attivando l'oggetto solo su una richiesta 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.
Èpossibilefare riferimento a una classeinvece di unafunzionein "add_action"?Non riesco a capirlo.Ecco solo un sempliceesempio dellafunzionein questione.
Quindi sì,nonfunziona.Ho ancheprovato:
E:
Einoltre:
È comunquepossibilefarlo senza dover creare unafunzione separata che carichi la classe?Mipiacerebbeesserein grado dieseguire semplicementeil costruttore di classitramite add_action.Questo ètutto ciò che deveessere caricatoperfargirare lapalla.