add_actionはクラスを参照します


38

'add_action'で関数の代わりにクラスを参照することは可能ですか?理解できないようです。問題の関数の基本的な例を次に示します。

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' );

とにかく、クラスをロードする別の関数を作成せずにこれを行うことができますか?add_actionを介してクラスコンストラクターを実行できるようにしたいだけです。ボールを転がすためにロードする必要があるのはそれだけです。

回答:


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これは、他の人のコードで作業しなければならない開発者にとって大きな痛みを引き起こす可能性があります。

アンパサンドについて

次のようなアクションが表示される場合があります。

array( &$this, 'getStuffDone' );

これは悪いです。&PHP 4では、オブジェクトが参照としてではなく値として渡されたときに追加されました。PHP 4は10年以上前のものであり、WordPressで長い間サポートされていません。

存在しない理由を使用する&thisフックやフィルタを追加するときは、参照を削除しても問題が発生しないだろう、とさえPHPの将来のバージョンとの互換性を向上させることが

代わりにこれを使用してください:

array( $this, 'getStuffDone' );

OK。そのすべてからありがとう。本当に多くを学びました。私はクラスベースのPHPで本当に快適になっています。これは私がやったことであり、動作しますが、それが悪いやり方であるか、何らかの形で間違っているかどうか教えてもらえますか?クラス自体の静的関数内でクラスを開始しました。次に、add_actionで静的関数を参照しました。:このリンクを参照してくださいpastebin.com/0idyPwwY
マシュー・ルディ

はい、そのようにすることができ$classますが、変数名として使用することは避けられますが、これらの単語は予約されている傾向があります。$x = new Y();グローバルな範囲で似たようなことを言うのを避けるためにあなたは邪魔にならないだろうし、何も必要ないところに複雑さを加えていると思います。記述されたコードの量を減らすための試みには、より多くのコードの記述が含まれています。
トムJノウェル

上記のすべてのケースで指摘しておきますが、クラスは破棄され、同じ目的を果たすため、クラスではなく関数を使用する方が良いでしょう。それはリソースの無駄です。作成し、オブジェクトを破壊するコストがあり、覚えておいてください、あなたはいくつかのオブジェクトをしたい、とあなたは彼らが長い間住んでいたことにしたい
トム・J Nowell

いい視点ね。私の見方を変えました。余分なコードを避けて、代わりにグローバルスコープで呼び出すと思います。
マシューラディ

1
私は)あなたが名前空間にクラスを入れているために起こる場合は、あなたがそれもまたはadd_action()/ ADD_FILTERを(追加する必要がありますことを追加したいことを見つけることができません-このような:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab

10

サンプルクラス

ノート:

  • クラスを一度だけ初期化する
    • 優先度0で呼び出すので、後でデフォルトの優先度で同じフックを使用できます
    • ! class_exists2回呼び出すことを避けるためにそれをラップし、内部に初期呼び出し元を配置します
  • 作りinit関数やクラスのVARをstatic
  • classを呼び出すときに、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();
}

回答を編集し、説明を追加してください:なぜそれが問題を解決できるのでしょうか?
FUXIA

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

これはKaiserの答えの非常に単純化されたバージョンですが、簡単な言葉で動作を示しています。このスタイルを初めて見ている人には便利かもしれません。

必要に応じて、他のメソッドでもオブジェクトを開始できます。私は個人的にこのメソッドを使用して、プラグインのオプション部分がスクリプトをキューに入れることを許可していますが、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' ) );

(注:クラスの名前空間は適切に設定されていると想定しています。それ以外の場合は、コールバック関数の名前空間を必ず設定してください。)


現在のクラスがまだ開始されていない場合はどうですか?実際に開始するためにadd_actionを使用しようとしていたので、$ var = new MyClass();を追加する必要はありません。他の場所で事前に。
マシューラディ

クラスinit(または必要な場所)をインスタンス化するためのコールバックを記述することはできませんか?
チップベネット

0

インスタンス化されたオブジェクトの代わりにクラス名を渡すことでそれができるはずです:

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

(理論的には、他のソリューションも機能するはずです

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

なぜそうならないのか、よくわからない。たぶん、あなたが参照で電話しないなら?)


最初のものは動作しません。ページを空白にします。2番目は機能しますが、これはクラスが最初の行で開始されたためです。クラスはすでに開始されているため、アクションを追加する目的をやや損ねます。しかし、それは私がやろうとしていることをしません。それはアクションを通してクラスを開始します。私が取り組んでいる実際のコードでは、アクションは「admin_init」ではなく、別のクラス内のカスタムアクションです。他のクラスのアクションが存在しない場合、関数 'MyClass'を開始しないでください。何かが足りない場合は申し訳ありません。私が行くにつれて学習
マシューラディ

ええ、私は間違っていました。これは、静的initメソッドを呼び出す場合にのみ機能します。参照してくださいwordpress.stackexchange.com/a/48093/14052
ブーン峡
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.