Function Documentation

WordPress Function Documentation Progress

Writing Plugins: What is the Class Callback Format?

Prior to WordPress 2.3.0, there was a bug that prevented object referenced method callbacks from being removed. In WordPress 2.3.x and upcoming WordPress 2.5, in order to remove the original method in the class, you have to use the original object reference. In PHP4, where objects are passed by value, this can be a problem, but PHP5 users shouldn’t have much to worry about as long as the variable they are using holds the original class reference.

Explanation of Problem Prior to WordPress 2.3

To demonstrate the problem, take a look at this code. If you were to run this prior to WordPress 2.3, the hook would not be removed because you changed the class property $test.

class MyPlugin
{
    var $test;

    function MyPlugin() {
        $this->test = false;
        add_action('init', array(&$this, '_init'));
        $this->test = true;
    }

    function init() {
        remove_action('init', array(&$this, '_init));
    }
}

This is a poor example, in that the ‘init’ hook will never run again. Other hooks will demonstrate the problem better in real world practice. That said, the method of adding callbacks to the hook array wouldn’t have allowed you to remove the hook until the state of the class was back in its original form prior to the addition of adding the MyPlugin::_init() to the init hook.

It is a little complicated to explain, but basically, once you changed the properties of the class, you wouldn’t be able to remove any hook you added prior to the change. For most plugins this was a huge deal since they had everything in one Singleton class (big mistake, will detail in later post).

How Method Callbacks are handled in WordPress 2.3+

A new private function was introduced to manage object referenced method callbacks. The form of which is below.

$myplugin = new MyPlugin();

add_action( 'init', array(&$myplugin, '_init') );

As you can see, the callback references the $myplugin variable along with the method in the second element. The reason this can cause a problem, is if you unset the variable afterwards.

$myplugin = new MyPlugin();

add_action( 'init', array(&$myplugin, '_init') );

unset($myplugin);

If you think this will magically remove the reference in the hook array, you are mistaken. PHP will retain the reference to the object and will call the method. This will hinder, but not prevent the removal of the object’s callbacks later.

For a workaround, you can recreate the object reference and it should (purely conjecture) recreate the needed hook string to reference to previously added object reference callback. This will not work if two or more object references of the same class were created, so it is assumed that in most cases only one object reference will be created. If only one were created and destroyed, it might be possible to remove the callbacks from the action or filter using the Plugin API.

New format

The new format for the above object referenced method callbacks are always: class name, followed immediately by the method name, followed by the amount of previously added (classname+methodname). For classes, this allows you to add as many object referenced classes and add methods which don’t override each other.

For static method callbacks, the format is always: class name followed immediately by method name. There is no need to protect against overrides because no two classes can have the same class name (yes, I do know there is an exception to this rule).

For functions, nothing changes, it is just the function name.

Advertisements

January 13, 2008 - Posted by | Writing Plugins Series | , , ,

5 Comments »

  1. […] Writing Plugins: Don’t Overuse Singletons! A common class pattern, but one I feel is a mistake in many cases. I’m not quite sure why it is used, other than it is just easier since you don’t have to use the Registry class pattern to store properties. However, using this pattern did cause problems prior to WordPress 2.3. […]

    Pingback by Writing Plugins: Don’t Overuse Singletons! « Function Documentation | January 16, 2008 | Reply

  2. I’m using WordPress 2.7 and I’m having the hardest time running a remove method on a method referenced by an object. What I mean is I have a plugin that has an object ($acsu) and a method I would like to remove that has been added by the object(‘wp_header’).

    I’ve tried the following:

    remove_action(‘wp_head’, array(&$acsu, ‘wp_header’));
    remove_action(‘wp_head’, array($acsu, ‘wp_header’));
    remove_action(‘wp_head’, ‘wp_header’);
    add_action(‘wp_head’, create_function(‘$a’, “remove_action(‘wp_head’, array($acsu, ‘wp_header’));”));

    And none of them seem to work for me. Any ideas or examples you can think of that might help?

    Comment by Bradley G. Smith | April 14, 2009 | Reply

    • The variable has to be the original reference to the object, meaning if it is PHP4, you need the &$acsu and the variable that created the object. This becomes difficult when the original variable is “destroyed” or no variable is given. If you try to create your own instance of the object and try to remove it, then it isn’t going to work, because it should create a new action along side the other.

      I’m not sure I can completely help you, since I don’t have all of the code to reference. I will continue to suggest to people that using the static method or functions is the best way to do actions and filters. Using dynamic methods is a big WTF?

      Comment by Jacob Santos | April 15, 2009 | Reply

  3. Jacob, thanks for the quick response. Can you contact me directly at my email? If you’re up for it, I’d love to share some code and the specific instance of code I’m working on. I don’t imagine it would take too long. I figure we can post our results and solution here.

    Comment by Bradley G. Smith | April 15, 2009 | Reply

  4. Jacob, really good suggestion on remove_action. I wasn’t sure if I would ever solve this. Here’s a recap and some code.

    When I was trying to run a remove_action on the undesired method, I had my method inside of the class I was creating for my own plugin, and I was running a remove_action with my add_action calls. Instead, I did this:

    function remove_acsu_head(){
    global $acsu;
    #var_dump(&$acsu->wp_filter_id); // For debugging. Should be ‘1’ or ‘0’
    remove_action(‘template_redirect’, array(&$acsu, ‘template_redirecter’));
    remove_action(‘wp_head’, array(&$acsu, ‘wp_header’));
    }
    add_action(‘wp_head’, ‘remove_acsu_head’);

    And the method ‘remove_acsu_head’ is outside of the class I created for my own plugin. It is a standalone function. So I just call my ‘add_action(‘wp_head’, ‘remove_acsu_head’);’ with the other add_action calls which reference my own plugin.

    Hope this helps, I’d be open to clarifying this comment if it is a little cloudy. Jacob, thanks again.

    Comment by Bradley G. Smith | April 20, 2009 | Reply


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: