是否可以在“ 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运行类构造函数。这就是使球滚动所需的全部内容。

#1 楼

不,您不能通过挂钩而不是直接“初始化”或实例化该类。总是需要一些额外的代码(因为要自己打开一罐蠕虫,所以做到这一点并非可取。
这是一种更好的方法:
 class MyClass {
     function __construct() {
          add_action( 'admin_init', [ $this, 'getStuffDone' ] );
     }
     function getStuffDone() {
          // .. This is where stuff gets done ..
     }
}
$var = new MyClass();
 

当然,可以为一般情况创建一个接口类来简化它:
 class IGetStuffDone {
    function IGetStuffDone(){
        add_action( 'admin_init', [ $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', [ __NAMESPACE__ . '\MyClass','getStuffDone' ] );
 

请注意,如果您的课程是在名称空间中。
关闭
可悲的是,您无法避免创建新类的行。跳过它的唯一其他解决方案将包括仍然具有该行的样板代码,例如:
 __NAMESPACE__ 

以及跳过该类,只使用一个函数:
 add_action( 'admin_init', function() {
    $var = new MyClass();
    $var->getStuffDone();
} );
 

但是请记住,您现在已经介绍了匿名的幽灵职能。无法使用add_action( 'admin_init', function() { // do stuff } ); 删除上述操作,这对于必须使用其他人的代码的开发人员来说确实会造成极大的痛苦。 br />
 remove_action 

这很糟糕。当对象作为值而不是引用传递时,在PHP 4中又添加了array( &$this, 'getStuffDone' ) 。 PHP 4已有十多年的历史,并且很长一段时间以来一直不受WordPress支持。
添加钩子和过滤器时没有理由使用&,并且删除引用不会造成任何问题,并且甚至可以改善与PHP未来版本的兼容性
使用以下替代方法:
 &this 


评论


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

–马修·鲁迪(Matthew Ruddy)
2012年4月5日14:35

是的,您可以那样做,尽管我可以避免将$ class用作变量名,但是这些词倾向于保留。我认为您应该避免使用类似于$ x = new Y();的方式。在全球范围内,并且您在没有必要的情况下增加了复杂性。您尝试减少编写的代码量涉及编写更多的代码!

– Tom J Nowell♦
2012年5月5日14:45

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

– Tom J Nowell♦
2012年4月5日下午14:47

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

–马修·鲁迪(Matthew Ruddy)
2012年4月5日15:09



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

– jschrab
18年4月27日在22:01

#2 楼

示例类

注意:


仅一次初始化该类

调用优先级0,因此可以将相同的钩子与稍后将使用默认优先级
将其包装在! class_exists中,以避免调用它两次,并将init调用方放在内部。
当您调用类init时,从init内调用构造函数。

这是一个示例

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+

请不要使用static。我们已经超越了php4。 :)

#3 楼

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♦
18年3月4日在14:06

#4 楼

这对我有用:

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

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


#5 楼

您可以触发类中的事件,而无需首先加载它。如果您不想预先加载完整的类,但是需要访问WordPress过滤器和操作,这将很方便。 br />
这是Kaiser答案的非常简化的版本,但以简单的方式显示了行为。第一次使用这种样式的人可能会很方便。

如果需要,其他方法仍然可以初始化对象。我个人使用此方法来允许插件的可选部分进入脚本队列,但仅在AJAX请求上触发对象。

#6 楼

一般来说,您不会将整个类添加到一个钩子中。 add_action() / add_filter()钩子希望有回调函数,可以在类中引用。 br />
将您的init()调用放入您的类中,然后像这样标识回调:

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


(注意:我假设您的类是正确命名空间;否则,请确保对回调函数进行命名空间。)

评论


如果当前的类还没有开始怎么办?我试图使用add_action进行实际初始化,所以不必添加$ var = new MyClass();。事先在其他地方。

–马修·鲁迪(Matthew Ruddy)
2012年4月5日在14:08

您是否可以只编写一个回调以在init(或您需要的地方)实例化您的类?

–芯片Bennett
2012年4月5日15:55

#7 楼

您应该可以通过传递类名而不是实例化的对象来做到这一点:

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


(理论上,您的其他解决方案也应该起作用

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


不知道为什么不这样做。也许您不按引用致电吗?)

评论


第一个无效。只是使页面空白。第二个有效,但仅因为该类已在第一行中启动。因为已经启动了该类,所以这有点不利于添加操作的目的。但这并没有完成我想做的事情,而是通过操作来启动类。在我正在处理的实际代码中,该动作不是'admin_init'而是另一个类中的自定义动作。如果另一个类中的动作不存在,我不希望函数“ MyClass”启动。抱歉,如果我缺少什么;边学边学

–马修·鲁迪(Matthew Ruddy)
2012年4月5日14:15



是的,我错了。仅在调用静态init方法时有效。参见wordpress.stackexchange.com/a/48093/14052

–布恩峡谷
2012年4月5日15:17