działanie dodatkowe odniesienie do klasy

38

Czy można odwoływać się do klasy zamiast funkcji w „add46”? Nie mogę tego rozgryźć. Oto tylko podstawowy przykład omawianej funkcji.

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

Więc tak, to nie działa. Próbowałem też:

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

I:

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

I również:

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

Czy w ogóle mogę to zrobić bez konieczności tworzenia osobnej funkcji, która ładuje klasę? Chciałbym móc po prostu uruchomić konstruktora klas poprzez addodatność. To wszystko, co trzeba załadować, aby piłka się potoczyła.

Matthew Ruddy
źródło

Odpowiedzi:

69

Nie, nie można „zainicjować” ani utworzyć instancji klasy za pomocą haka, a nie bezpośrednio. Zawsze wymagany jest jakiś dodatkowy kod (i nie jest to pożądane, aby móc to zrobić, ponieważ otwierasz puszkę robaków dla siebie).

Oto lepszy sposób na zrobienie tego:

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

Oczywiście można jeszcze stworzyć klasę interfejsu, aby uprościć ją w ogólnym przypadku:

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

Zauważ, że jako interfejs nie możesz bezpośrednio utworzyć obiektu tego typu, ale możesz utworzyć podklasę, pozwalając powiedzieć:

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

Który następnie automatycznie doda wszystkie haki, wystarczy zdefiniować, co dokładnie jest robione w podklasie, a następnie utworzyć!

Na konstruktorach

Nie dodałbym konstruktora jako funkcji przechwytującej, to zła praktyka i może prowadzić do wielu niezwykłych zdarzeń. Także w większości języków konstruktor zwraca obiekt, który jest tworzony, więc jeśli haczyk musi zwrócić coś takiego jak w filtrze, nie zwróci filtrowanej zmiennej, ale zamiast tego zwróci obiekt klasy.

Wywoływanie konstruktora lub destruktora jest bardzo, bardzo, bardzo złą praktyką programistyczną, bez względu na to, w jakim języku się posługujesz, i nigdy nie powinno się go wykonywać.

Konstruktorzy powinni również konstruować obiekty, aby inicjalizować je w gotowości do użycia, a nie do rzeczywistej pracy. Praca do wykonania przez obiekt powinna odbywać się w osobnej funkcji.

Metody klasy statycznej i wcale nie wymagające tworzenia instancji / inicjalizacji

Jeśli twoja metoda klasy jest statyczną metodą klasy, możesz przekazać nazwę klasy w cudzysłowie, a nie $thisjak pokazano poniżej:

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

Zamknięcia i PHP 5.3

Niestety nie można uniknąć linii tworzącej nową klasę. Jedynym innym rozwiązaniem pomijania byłoby kod płyty kotłowej, który wciąż ma tę linię, i wymagałby PHP 5.3+ np .:

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

W którym momencie równie dobrze możesz pominąć klasę i po prostu użyć funkcji:

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

Pamiętaj jednak, że wprowadziłeś teraz spektrum anonimowych funkcji. Nie ma sposobu na usunięcie powyższej akcji za pomocą remove_action, a to może i powoduje wielki ból dla programistów, którzy muszą pracować z kodem innych ludzi.

Na Ampersands

Możesz zobaczyć takie działania:

array( &$this, 'getStuffDone' );

To jest złe . &został dodany z powrotem w PHP 4, gdy obiekty były przekazywane jako wartości, a nie jako referencje. PHP 4 ma ponad dekadę i od dawna nie był obsługiwany przez WordPress.

Nie ma powodu, aby używać go &thispodczas dodawania haków i filtrów, a usunięcie odwołania nie spowoduje żadnych problemów, a nawet może poprawić zgodność z przyszłymi wersjami PHP

Użyj tego zamiast:

array( $this, 'getStuffDone' );
Tom J Nowell
źródło
Dobrze. Dziękuję ci z tego wszystkiego; naprawdę sporo się nauczyłem. Naprawdę czuję się komfortowo dopiero w klasowym PHP. To właśnie zrobiłem i działa, ale czy możesz mi powiedzieć, czy jest to jakaś zła praktyka / nieprawidłowa w jakikolwiek sposób? Zainicjowałem klasę w funkcji statycznej, w samej klasie. Następnie odniósł się do funkcji statycznej w add działań. Zobacz ten link: pastebin.com/0idyPwwY
Matthew Ruddy,
tak, możesz to zrobić w ten sposób, chociaż mógłbym uniknąć używania $classjako nazwy zmiennej, te słowa są zwykle zastrzeżone. Myślę, że robisz wszystko, co w twojej mocy, aby uniknąć mówienia czegoś podobnego $x = new Y();w zakresie globalnym i dodajesz złożoności tam, gdzie nic nie jest konieczne. Próba zmniejszenia ilości napisanego kodu wymagała napisania większej ilości kodu!
Tom J Nowell
Chciałbym wskazać we wszystkich powyższych przypadkach, że lepiej byłoby użyć funkcji niż klasy, ponieważ klasa ta i tak zostanie odrzucona i służy temu samemu celowi. To marnowanie zasobów. Pamiętaj, że tworzenie i niszczenie obiektu wiąże się z pewnymi kosztami, chcesz mieć kilka obiektów i chcesz, aby były długo żywe
Tom J Nowell
Słuszna uwaga. Zmieniłem sposób, w jaki na to patrzyłem. Myślę, że zamiast tego wywołam to w zakresie globalnym, unikając dodatkowego kodu.
Matthew Ruddy,
1
Chciałbym dodać, że jeśli zdarzyło się, że umieściłeś swoją klasę w przestrzeni nazw, będziesz musiał ją dodać, inaczej addr () / add_filter () jej nie znajdzie - tak:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab
10

Przykładowa klasa

Uwagi:

  • Rozpocznij zajęcia tylko raz
    • Zadzwoń na priorytet 0, abyś mógł później użyć tego samego haka z domyślnym priorytetem
    • Zawinąć w, ! class_existsaby uniknąć podwójnego wywołania i umieścić wywołującego init w środku
  • Ustaw initfunkcję i klasę varstatic
  • Wywołaj konstruktora z wnętrza twojego init, kiedy wywołasz klasę new self.

Oto przykład

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+

Proszę , zostaw to &. Jesteśmy już poza php4. :)

kajzer
źródło
2
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();
}
Zakir Sajib
źródło
Proszę edytować swoje odpowiedzi i dodać wyjaśnienie: dlaczego to może rozwiązać problem?
fuxia
0

Możesz wywoływać zdarzenia w swojej klasie bez konieczności początkowego ładowania . Jest to przydatne, jeśli nie chcesz ładować pełnej klasy z góry, ale potrzebujesz dostępu do filtrów i akcji WordPress.

Oto bardzo prosty przykład

<?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();

Jest to bardzo uproszczona wersja odpowiedzi Kaisera, ale w prosty sposób pokazuje zachowanie. Może być przydatny dla tych, którzy patrzą na ten styl po raz pierwszy.

Inne metody mogą nadal inicjować obiekt, jeśli jest to wymagane. Osobiście używam tej metody, aby umożliwić opcjonalnym częściom mojej wtyczki kolejkowanie skryptów, ale wyzwalanie obiektu tylko na żądanie AJAX.

John Reid
źródło
0

To działa dla mnie:

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

add_action('foo_bar', array('foo', 'bar'));
Jonathan
źródło
0

Ogólnie rzecz biorąc, nie dodawalibyście całej klasy do haka. W add_action()/ add_filter()haki oczekiwać zwrotnych funkcje , które mogą się odwoływać od wewnątrz klasy .

Powiedzmy, że masz init()funkcję w swojej klasie, którą chcesz podłączyć do haka WordPress init.

Umieść add_action()połączenie w klasie, a następnie zidentyfikuj połączenie zwrotne w następujący sposób:

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

(Uwaga: Zakładam, że twoja klasa ma odpowiednią przestrzeń nazw; w przeciwnym razie pamiętaj o przestrzeni nazw swoich funkcji zwrotnych).

Chip Bennett
źródło
Co jeśli obecna klasa nie została jeszcze zainicjowana? Próbowałem użyć add działań do faktycznej inicjacji, więc nie muszę dodawać $ var = new MyClass (); wcześniej gdzie indziej.
Matthew Ruddy,
Czy możesz nie tylko napisać oddzwonienie, aby utworzyć instancję swojej klasy w init(lub gdziekolwiek jej potrzebujesz)?
Chip Bennett,
0

Powinieneś być w stanie to zrobić, przekazując nazwę klasy zamiast obiektu instancji:

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

(Teoretycznie inne rozwiązanie również powinno działać

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

Nie jestem pewien, dlaczego tak nie jest. Może jeśli nie zadzwonisz przez referencję?)

Wąwozy Boone
źródło
Pierwszy nie działa. Sprawia, że ​​strona staje się pusta. Drugi działa, ale tylko dlatego, że klasa została zainicjowana w pierwszym wierszu. W pewnym sensie pokonuje cel dodania akcji, ponieważ klasa została już zainicjowana. Ale nie robi tego, co próbuję zrobić, czyli inicjuje klasę poprzez akcję. W rzeczywistym kodzie, nad którym pracuję, akcja nie jest „admin_init”, ale jest akcją niestandardową w innej klasie. Nie chcę, aby funkcja „MyClass” była inicjowana, jeśli nie ma akcji w innej klasie. Przepraszam, jeśli coś przeoczyłem; uczę się jak idę
Matthew Ruddy,
Tak, myliłem się. Działa to tylko wtedy, gdy wywołujesz initmetodę statyczną . Zobacz wordpress.stackexchange.com/a/48093/14052
Boone Gorges