Додати посилання на клас


38

Чи можна посилатись на клас замість функції у "addgery"? Не можу зрозуміти. Ось лише основний приклад функції, про яку йдеться.

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

Так так, це не працює. Я також спробував:

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

І:

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

І також:

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

Чи все-таки я можу це зробити, не створюючи окремої функції, що завантажує клас? Я хотів би мати можливість просто запустити конструктор класів через додавання. Це все, що потрібно завантажувати, щоб куля котилася.

Відповіді:


69

Ні, ви не можете «ініціалізувати» або інстанціювати клас через гачок, а не безпосередньо. Завжди потрібен якийсь додатковий код (і не бажано, щоб це можна було робити, оскільки ви відкриваєте для себе баночку з глистами.

Ось кращий спосіб зробити це:

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

Звичайно, можна створити клас інтерфейсу, щоб ще більше спростити його для загального випадку:

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

Зауважте, що в якості інтерфейсу ви не можете створити об'єкт такого типу безпосередньо, але ви можете створити підклас, що дозволяє:

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

Що б потім автоматично додавати всі гачки, вам просто потрібно визначити, що саме робиться в підкласі, а потім створити його!

На конструкторах

Я б не додав конструктор як функцію гачка, це погана практика і може призвести до багатьох незвичайних подій. Також у більшості мов конструктор повертає об'єкт, який інстанціюється, тому, якщо ваш гачок повинен повернути щось на зразок у фільтрі, він не поверне відфільтровану змінну, як ви хочете, а натомість поверне об’єкт класу.

Виклик конструктора чи деструктора - це дуже, дуже, дуже погана практика програмування, незалежно від того, на якій мові ви перебуваєте, і ніколи цього не слід робити.

Конструктори також повинні будувати об’єкти, щоб ініціалізувати їх готовими до використання, а не для фактичної роботи. Робота, яку повинен виконувати об’єкт, повинна виконувати окрему функцію.

Статичні методи класу, і взагалі не потрібно інстанціювати / ініціалізувати

Якщо метод вашого класу - метод статичного класу, ви можете передати ім'я класу в лапки, а не $thisяк показано нижче:

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

Закриття та PHP 5.3

На жаль, ви не можете уникнути лінії, що створює новий клас. Єдиним іншим рішенням для його пропускання буде включення коду пластини котла, який все ще має цю лінію, і вимагає PHP 5.3+, наприклад:

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

У цей момент ви можете також пропустити клас і просто скористатися функцією:

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

Але майте на увазі, що ви зараз представили привид анонімних функцій. Немає можливості видалити вищезазначені дії, використовуючи remove_action, і це може і справді заподіяти біль для розробників, яким доводиться працювати з кодом інших народів.

На Ampersands

Можливо, ви побачите такі дії:

array( &$this, 'getStuffDone' );

Це погано . &було додано ще в PHP 4, коли об'єкти передавались як значення, а не як посилання. PHP 4 вже більше десяти років, і він не підтримувався WordPress вже дуже давно.

Немає підстав використовувати &thisпри додаванні гаків і фільтрів, а видалення посилання не спричинить жодних проблем і навіть може покращити сумісність з майбутніми версіями PHP

Використовуйте це замість:

array( $this, 'getStuffDone' );

Добре. Дякую від усього цього; дійсно навчився зовсім небагато. Зараз мені дуже комфортно лише на PHP-класі, що базується на уроках. Це те, що я зробив, і це працює, але ви можете мені сказати, чи це погана практика / неправильна в будь-якому випадку? Я ініціював клас всередині статичної функції, всередині самого класу. Потім посилається на статичну функцію в додатку завантаження. Дивіться за цим посиланням: pastebin.com/0idyPwwY
Matthew Ruddy

так, ви могли б зробити це так, хоча я міг би уникнути використання $classв якості імені змінної, ці слова, як правило, зарезервовані. Я думаю, що ви виходите зі свого шляху, щоб уникнути того, щоб сказати щось подібне до $x = new Y();глобальної сфери, і ви додаєте складності там, де нічого не потрібно. Ваша спроба зменшити кількість написаного коду пов'язана з написанням ще коду!
Том Дж. Ноуелл

Я зазначу, що у всіх вищезазначених випадках вам краще використовувати функцію, а не клас, оскільки цей клас все одно буде відкинутий і виконує ту саму мету. Це марнотрата ресурсів. Пам'ятайте, що створення та знищення об’єкта коштує, вам потрібно небагато об’єктів, і ви хочете, щоб вони довго жили
Том Дж. Ноуелл

Влучне зауваження. Змінилося те, як я на це дивився. Думаю, я назову це в глобальному масштабі замість цього, уникаючи зайвого коду.
Метью Рудді

1
Я хотів би додати, що якщо вам здається, що ви кладете свій клас у простір імен, вам також доведеться додати, що він теж не додасть (opens /) / add_filter (), не знайдемо його, як-от так:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab

10

Приклад класу

Примітки:

  • Навчайте клас лише один раз
    • Зателефонуйте за пріоритетом 0, щоб згодом ви могли використовувати той самий гак із пріоритетом за замовчуванням
    • Згорніть його, ! class_existsщоб уникнути його дзвінка та помістіть ініціатор, що телефонує, всередину
  • Складіть initфункцію та клас varstatic
  • Зателефонуйте конструктору зсередини вашого init під час виклику класу new self.

Ось приклад

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+

Будь ласка , залиште &аут. Ми вже поза php4. :)


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

Будь ласка , змініть свій відповідь , і додати пояснення: чому це може вирішити цю проблему?
фуксія

0

Ви можете викликати події у своєму класі без необхідності завантажувати його спочатку . Це зручно, якщо ви не хочете завантажувати повний клас вперед, але вам потрібно отримати доступ до фільтрів і дій WordPress.

Ось дуже простий приклад

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

Це дуже спрощена версія відповіді Кайзера, але простою поведінкою показує поведінку. Можливо, буде корисно тим, хто вперше дивиться на цей стиль.

Інші методи все ще можуть ініціювати об'єкт, якщо потрібно. Я особисто використовую цей метод, щоб дозволити необов'язкові частини мого плагіна запускати скрипти, але лише запускати об'єкт на запит AJAX.


0

Це працює для мене:

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

add_action('foo_bar', array('foo', 'bar'));

0

Взагалі кажучи, ви не додавали б цілий клас до гачка. В add_action()/ add_filter()Гачки очікують на зворотній дзвінок функції , які можуть бути посилання з всередині класу .

Скажімо, у вас є init()функція всередині вашого класу, яку потрібно підключити до гачка WordPress init.

Поставте свій add_action()дзвінок всередині свого класу, а потім ідентифікуйте зворотний дзвінок так:

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

(Примітка. Я припускаю, що ваш клас має правильний простір імен; в іншому випадку не забудьте ввести простір імен для функцій зворотного дзвінка.)


Що робити, якщо поточний клас ще не був ініційований? Я намагався використовувати додавання, щоб насправді ініціювати, тому мені не потрібно додавати $ var = new MyClass (); попередньо в іншому місці.
Меттью Рудді

Чи можете ви не просто написати зворотний дзвінок, щоб інстанціювати свій клас за адресою init(або там, де це потрібно)?
Чіп Беннетт

0

Ви можете це зробити, передавши ім'я класу замість об'єкта, що створюється:

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

(Теоретично, ваше інше рішення теж має працювати

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

Не впевнений в голові, чому це не так. Можливо, якщо ви не телефонуєте за довідкою?)


Перший не працює. Просто робить сторінку порожньою. Другий працює, але лише тому, що клас був ініційований у першому рядку. Це свого роду перемагає мету додавання дії, оскільки клас вже був ініційований. Але це не робить те, що я намагаюся зробити, це ініціювати клас через дію. У фактичному коді, над яким я працюю, дія не 'admin_init', а спеціальна дія в іншому класі. Я не хочу, щоб функція "MyClass" була ініційована, якщо дії в іншому класі немає. Вибачте, якщо я щось пропускаю; навчання, як я йду
Меттью Рудді

Так, я помилявся Це працює лише в тому випадку, якщо ви викликаєте статичний initметод. Дивіться wordpress.stackexchange.com/a/48093/14052
Бунські ущелини
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.