add_action引用一个类
7 个回答
- 投票数
-
- 2012-04-05
否,您不能通过挂钩而不是直接"初始化"或实例化该类.总是需要一些其他代码(能够做到这一点并不是可取的事情,因为您正在为自己打开一罐蠕虫.
这是一种更好的方法:
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 } );
但是请记住,您现在已经介绍了匿名函数的幽灵.无法使用
remove_action
删除上述操作,这对于必须使用其他人的代码的开发人员来说确实会造成极大的痛苦.在&符上
您可能会看到这样使用的动作:
array( &$this, 'getStuffDone' )
这很糟糕.当对象作为值而不是引用传递时,
&
在PHP 4中重新添加. PHP 4已经有十多年的历史了,并且很长一段时间以来一直没有WordPress支持.在添加挂钩和过滤器时,没有没有理由使用
&this
,删除引用不会造成任何问题,甚至可能会改善与将来版本的兼容性PHP改为使用此:
[ $this, 'getStuffDone' ]
No, you cannot 'initialise' or instantiate the class through a hook, not directly. Some additional code is always required ( and it is not a desirable thing to be able to do that, as you're opening a can of worms for yourself.
Here is a better way of doing it:
class MyClass { function __construct() { add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } function getStuffDone() { // .. This is where stuff gets done .. } } $var = new MyClass();
Of course one could create an interface class to simplify it for the general case even further:
class IGetStuffDone { function IGetStuffDone(){ add_action( 'admin_init', [ $this, 'getStuffDone' ] ); } public abstract function getStuffDone(); }
Note that as an interface, you can't create an object of this type directly, but you could create a sub-class, letting you say:
class CDoingThings extends IGetStuffDone { function getStuffDone(){ // doing things } } $var = new CDoingThings();
Which would then automatically add all the hooks, you just need to define what exactly is being done in a subclass and then create it!
On Constructors
I wouldn't add a constructor as a hook function, it's bad practice, and can lead ot a lot of unusual events. Also in most languages a constructor returns the object that is being instantiated, so if your hook needs to return something like in a filter, it will not return the filtered variable as you want, but instead it will return the class object.
Directly calling a constructor or a destructor is very, very, very bad programming practice, no matter which language you're in, and should never be done.
Constructors should also construct objects, to initialise them ready for use, not for actual work. Work to be done by the object should be in a separate function.
Static class methods, and not needing to instantiate/initialise at all
If your class method is a static class method, you can pass the name of the class in quotes rather than
$this
as shown below:class MyClass { public static function getStuffDone() { // .. This is where stuff gets done .. } } add_action( 'admin_init', [ __NAMESPACE__ . '\MyClass','getStuffDone' ] );
Note the use of
__NAMESPACE__
which is required if your class is inside a namespace.Closures
Sadly you cannot avoid the line creating the new class. The only other solution to skipping it would involve boiler plate code that still has that line e.g.:
add_action( 'admin_init', function() { $var = new MyClass(); $var->getStuffDone(); } );
At which point you may as well skip the class, and just use a function:
add_action( 'admin_init', function() { // do stuff } );
But keep in mind you have now introduced the spectre of anonymous functions. There is no way to remove the above action using
remove_action
, and this can and does cause great pain for developers who have to work with other peoples code.On Ampersands
You may see actions used like this:
array( &$this, 'getStuffDone' )
This is bad.
&
was added back in PHP 4 when objects were passed as values, not as references. PHP 4 is more than a decade old, and hasn't been supported by WordPress in a very long time.There is no reason to use
&this
when adding hooks and filters, and removing the reference will cause no issues, and may even improve compatibility with future versions of PHPUse this instead:
[ $this, 'getStuffDone' ]
-
好.谢谢你.真的学到了很多东西.我现在真的只是对基于类的PHP感到满意.这就是我所做的,并且可以正常工作,但是您能告诉我这是不好的做法还是任何方式的错误?我已经在类本身内部的静态函数中启动了该类.然后在add_action中引用了静态函数.看到这个链接:http://pastebin.com/0idyPwwYOk. Thank you from all of that; really learnt quite a bit. I'm really only getting comfortable in class based PHP now. This is what I have done, and it works, but could you tell me if it is bad practice/incorrect in any way? I've initiated the class inside a static function, within the class itself. Then referenced the static function in the add_action. See this link: http://pastebin.com/0idyPwwY
- 0
- 2012-04-05
- Matthew Ruddy
-
是的,您可以那样做,尽管我可以避免使用$ class作为变量名,但是这些词倾向于保留.我认为您要避免在全局范围内避免使用类似于`$ x=new Y();`的方法,并且在没有必要的情况下增加了复杂性.您尝试减少编写的代码量涉及编写更多的代码!yes you could do it that way, though I could avoid using `$class` as your variable name, those words tend to be reserved. I think you're going way out of your way to avoid saying something similar to `$x = new Y();` in the global scope, and you're adding complexity where none is necessary. Your attempt to reduce the amount of code written has involved writing more code!
- 0
- 2012-04-05
- Tom J Nowell
-
我要指出的是,在所有上述情况下,最好使用函数而不是类,因为该类将被丢弃并且具有相同的目的.这是浪费资源.请记住,创建和销毁对象需要付出一定的代价,您需要很少的对象,并且希望它们长寿I'd point out in all of the above cases, you would be better off using a function rather than a class, as that class will be discarded anyway and serves the same purpose. It's a waste of resources. Remember, there is a cost to creating and destroying an object, you want few objects, and you want them to be long lived
- 0
- 2012-04-05
- Tom J Nowell
-
好点子.改变了我一直在看的方式.我想我会在全局范围内调用它,以避免多余的代码.Good point. Changed the way I've been looking at it. I think I'll call it in the global scope instead, avoiding the extra code.
- 0
- 2012-04-05
- Matthew Ruddy
-
我想补充一点,如果您碰巧将类放在命名空间中,则也必须添加它,否则add_action()/add_filter()将找不到它-像这样:```add_action('admin_init',array('MyNamespace \ MyClass','getStuffDone'));```I would like to add that if you happen to have put your class in a namespace, you will have to add that too or add_action()/add_filter() won't find it - like this: ```add_action( 'admin_init', array('MyNamespace\MyClass','getStuffDone' ) );```
- 1
- 2018-04-27
- jschrab
-
- 2012-04-05
示例类
注意:
- 只初始化一次课程
- 调用优先级0,因此您以后可以使用具有默认优先级的同一个钩子
- 将其包装为
! class_exists
避免调用两次,并将init调用方放在其中
- 进行
init
函数和varstatic
类
- 调用类
new self
时,从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 +
请,请保留
&
.我们已经超越了php4. :)Example class
Notes:
- Init the class only once
- Call on priority 0, so you can use the same hook with the default priority later
- Wrap it up in a
! class_exists
to avoid calling it twice and place the init caller inside
- Make the
init
function and the class varstatic
- Call the constructor from inside your init, when you call the class
new self
.
Here's an example
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+
Please, leave the
&
out. We're already beyond php4. :) -
- 2018-03-04
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(); }
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(); }
-
请** [编辑]您的答案**,并添加说明:**为什么**可以解决问题?Please **[edit] your answer**, and add an explanation: **why** could that solve the problem?
- 0
- 2018-03-04
- fuxia
-
-
- 2012-04-05
通常来说,您不会将整个 class 添加到一个钩子中.
add_action()
/add_filter()
挂钩需要回调功能,可以从内引用 一个课程.比方说,您的类中有一个
init()
函数,您想连接到WordPress的init
钩子.将您的
add_action()
放在类内 中,然后像这样标识回调:add_action( 'init', array( $this, 'init' ) );
(注意:我假设您的类已正确命名,否则请确保对回调函数进行命名.)
Generally speaking, you wouldn't add an entire class to a hook. The
add_action()
/add_filter()
hooks expect callback functions, which can be referenced from within a class.Let's say that you have an
init()
function inside your class, that you want to hook into the WordPressinit
hook.Put your
add_action()
call inside your class, and then identify the callback like so:add_action( 'init', array( $this, 'init' ) );
(Note: I'm assuming your class is properly namespaced; otherwise, be sure to namespace your callback functions.)
-
如果当前的类还没有开始怎么办?我试图使用add_action进行实际初始化,所以不必添加$ var=new MyClass();.事先在其他地方.What about if the current class hasn't already been initiated? I was trying to use add_action to actually initiate, so I don't have to add $var = new MyClass(); beforehand elsewhere.
- 0
- 2012-04-05
- Matthew Ruddy
-
您是否可以只编写一个回调来在`init`(或您需要的地方)上实例化您的类?Can you not just write a callback to instantiate your class at `init` (or wherever you need it)?
- 0
- 2012-04-05
- Chip Bennett
-
- 2012-04-05
您应该可以通过传递类名而不是实例化的对象来做到这一点:
add_action( 'init', array( 'MyClass', '__construct' ) );
(理论上,您的其他解决方案也应该有效
$var = new MyClass(); add_action( 'admin_init', array( $var, '__construct' ) );
不确定为什么不这样做.也许您不按参考致电?)
You should be able to do it by passing the class name instead of the instantiated object:
add_action( 'init', array( 'MyClass', '__construct' ) );
(In theory, your other solution should work too
$var = new MyClass(); add_action( 'admin_init', array( $var, '__construct' ) );
Not sure off the head why it doesn't. Maybe if you don't call by reference?)
-
第一个无效.只是使页面空白.第二个有效,但仅因为该类已在第一行中启动.因为已经启动了该类,所以它不能达到添加操作的目的.但这并没有完成我想做的事情,而是通过操作来启动类.在我正在处理的实际代码中,该动作不是'admin_init'而是另一个类中的自定义动作.如果另一个类中的动作不存在,我不希望函数" MyClass"启动.对不起,如果我缺少什么;边学边学First one doesn't work. Just makes the page go blank. The second works, but only because the class has been initiated in the first line. It sort of defeats the purpose of adding the action, because the class has already been initiated. But it doesn't do what I'm trying to do, which is initiate the class through the action. In the actual code I'm working on, the action isn't 'admin_init' but a custom action within another class. I don't want the function 'MyClass' to be initiated if the action in the other class isn't there. Sorry if I'm missing something; learning as I go
- 0
- 2012-04-05
- Matthew Ruddy
-
是的,我错了.仅在调用静态`init`方法时有效.参见http://wordpress.stackexchange.com/a/48093/14052Yeah, I was wrong. That only works if you're calling a static `init` method. See http://wordpress.stackexchange.com/a/48093/14052
- 0
- 2012-04-05
- Boone Gorges
-
- 2014-12-22
您可以触发类中的事件,而无需初始化.如果您不想预先加载完整的类,但是需要访问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请求上触发对象.
You can trigger events in your class without the need to load it initially. This is handy if you don't want to load the full class up front, but need to access the WordPress filters and actions.
Here's a very simple example
<?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();
This is a very simplified version of Kaiser's answer but shows in simple terms the behaviour. Might be handy for those looking at this style for the first time.
Other methods can still initiate the object if required. I'm personally using this method to allow optional parts of my plugin to enqueue scripts, but only triggering the object on an AJAX request.
是否可以在" add_action"中引用类而不是函数?似乎无法弄清楚.这只是所讨论功能的基本示例.
是的,那是行不通的.我也尝试过:
并且:
还有:
无论如何,我是否可以执行此操作而不必创建一个单独的函数来加载该类?我希望能够通过add_action运行类构造函数.这就是使球滚动所需的全部内容.