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运行类构造函数。这就是使球滚动所需的全部工作。

Answers:


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已经有十多年的历史了,并且很长一段时间以来一直不受WordPress支持。

没有理由使用&this添加时钩子和过滤器,除去基准会引起任何问题,甚至可能改善与PHP的未来版本的兼容性

使用此代替:

array( $this, 'getStuffDone' );

好。谢谢你。真的学到了很多东西。我现在真的只是对基于类的PHP感到满意。这是我所做的,并且可以正常工作,但是您能否以任何方式告诉我这是否是错误的做法/不正确的做法?我已经在类本身内部的静态函数中启动了该类。然后在add_action中引用了静态函数。看到这个链接:pastebin.com/0idyPwwY
Matthew Ruddy'4

是的,您可以那样做,尽管我可以避免将$class您的变量名用作变量名,但这些词倾向于保留。我认为您要避免$x = new Y();使用与全局范围内类似的说法,而正在增加不必要的复杂性。您尝试减少编写的代码量涉及编写更多的代码!
汤姆·J·诺维尔

我要指出的是,在上述所有情况下,最好还是使用函数而不是类,因为该类无论如何都将被丢弃并具有相同的目的。这是浪费资源。请记住,创建和销毁对象需要付出一定的代价,您需要很少的对象,并且希望它们的寿命很长
Tom J Nowell

好点子。改变了我一直在看的方式。我想我会在全局范围内调用它,以避免多余的代码。
马修·鲁迪

1
我想补充一下,如果您碰巧将您的类放在了名称空间中,则也必须添加它,否则add_action()/ add_filter()找不到它-像这样:add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );
jschrab

10

示例类

笔记:

  • 只初始化一次
    • 调用优先级0,因此您以后可以使用具有默认优先级的相同钩子
    • 将其包装在中,! class_exists以避免调用两次,并将init调用方放入其中
  • 使init函数和类变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(或在任何需要的地方)?
Chip Bennett 2012年

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
布恩峡谷
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.