[wp-hackers] Re: [wp-trac] Re: [WordPress Trac] #3875: Proposal for a new plugin architecture

jacobsantos at branson.com jacobsantos at branson.com
Tue Jul 31 20:51:01 GMT 2007

Use Cases (What I expect and not what happens, I will need to do unit 
testing for that part):

The below two will create an additional property on the class to keep 
track of the of the unique id for removal and insertion. This depends on 
the code being accurate, in the handling of the $function_to_add array. 
I tried to reference the array, but I'm starting to think that I should 
have the '&' in the function instead to make it easier.

For array($this, 'method_name'):

Quote (http://us2.php.net/manual/en/language.references.spot.php):
    "In an object method, $this is always a reference to the caller object."

On PHP 4: Should give desired result because it is being passed by 
reference anyway.
On PHP 5: Should work as expected..

For array(&$this, 'method_name'):

The redundancy is from some reason for PHP 4, is lost to me, as I didn't 
bother to learn class references until PHP 5 when it was no longer a 
requirement for classes.

See above. This should be the preferred method, since it won't hurt and 
won't break on wrong information in manual or some PHP 4 bug. For the 
documentation page.

For array($object, 'method_name');

For PHP 4: Bug on plugin author's part and won't give desired result. It 
will create additional copies and won't delete the original. This could 
be fixed, but I'm not up for that now. There is a possible way to fix 
this, but it would require unit testing to be sure. It should also be 
faster, since it wouldn't be creating copies. The fix would only be for 
this use case though and I'm not sure it if it worth fixing a bug on the 
plugin author's fault.

For PHP 5: Should work as expected.

For array(&$object, 'method_name'):

For PHP 4: Should work as expected.
For PHP 5: Should work as expected.

For array('class_name', 'method_name'):

Perhaps the second fastest, just by how much workload and checking is 
done. We don't bother with the checking that the above four do, which 
will append a number to the classname and method name when the objects 
are different.

This is not needed for static method calling as it doesn't and won't 
depend on $this. It would be a bug on the part of the plugin author if 
they expect to be able to use $this in their method afterwards. I don't 
expect this to be used often enough, but it should still be supported.

For regular function passing:

Would work as expected and should only be slightly slower than what it 
is now.

However, only unit testing, code coverage, and profiling will give the 
complete and accurate picture. The use cases can easily be made into 
tests for running the current code and future code against.

The diff is below:

Index: plugin.php
--- plugin.php    (revision 5825)
+++ plugin.php    (working copy)
@@ -19,7 +19,10 @@
     global $wp_filter, $merged_filters;
     // So the format is wp_filter['tag']['array of priorities']['array 
of functions serialized']['array of ['array (functions, accepted_args)]']
-    $wp_filter[$tag][$priority][serialize($function_to_add)] = 
array('function' => $function_to_add, 'accepted_args' => $accepted_args);
+    $fn_idx = _wp_filter_build_unique_id($tag, &$function_to_add, 
+    $wp_filter[$tag][$priority][$fn_idx] = array('function' => 
$function_to_add, 'accepted_args' => $accepted_args);
+    //$wp_filter[$tag][$priority][serialize($function_to_add)] = 
array('function' => $function_to_add, 'accepted_args' => $accepted_args);
     unset( $merged_filters[ $tag ] );
     return true;
@@ -97,7 +100,7 @@
  * @return boolean Whether the function is removed.
 function remove_filter($tag, $function_to_remove, $priority = 10, 
$accepted_args = 1) {
-    $function_to_remove = serialize($function_to_remove);
+    $function_to_remove = _wp_filter_build_unique_id($tag, 
&$function_to_remove, $priority);
     $r = 
@@ -280,4 +283,51 @@
     add_action('deactivate_' . $file, $function);
+function _wp_filter_build_unique_id($tag, $function_to_add, $priority = 10)
+    global $wp_filter;
+    // If function then just skip all of the tests and not overwrite 
the following.
+    $fn_idx = $function_to_add;
+    // Only test if using an array to call a class and method.
+    // Else bypass all of the following checks.
+    if(is_array($function_to_add))
+    {
+        list($obj,$fn) = $function_to_add;
+        // Expect most use cases for $obj to be objects and not strings
+        if(is_object($obj))
+        {
+            // We are going to use $classname more than once, store it
+            $classname = get_class($obj);
+            $fn_idx = $classname.$fn;
+            if(!is_null($function_to_add[0]->wp_filter_id))
+            {
+                $fn_idx .= $function_to_add[0]->wp_filter_id;
+            }
+            // Compare the two object references to see if they are the 
same object.
+            // This is slow however as it will check each property and 
method for similar, much
+            // like an array comparsion. Should work similar to PHP 4 
and PHP 5.
+            if($function_to_add[0] == 
$wp_filter[$tag][$priority][$fn_idx]['function'][0]) {
+                return $fn_idx;
+            } else {
+                $i = count($wp_filter[$tag][$priority]);
+                $function_to_add[0]->wp_filter_id = $i;
+                $fn_idx .= $function_to_add[0]->wp_filter_id;
+            }
+        }
+        // Must mean that it is using static calling.
+        // We can also assume that if they are using static calling
+        // it doesn't matter if they have two or more variables that 
they are trying
+        // to add to the same hooks. The bug would be theirs, we can 
only assume
+        // that they know enough when doing static method call binding 
to know what
+        // to expect.
+        else
+            $fn_idx = $obj.fn;
+    }
+    return $fn_idx;

More information about the wp-hackers mailing list