Everything on this post relates to my commit #21671 on my branch:
http://joomlacode.org/svn/joomla/development/branches/rcorral/
A little background: I would like to see more hooks/filters
implemented throughout the Joomla CMS. This would allow 3rd party
developers to create plugins to take advantage of these new hooks,
thus creating a more extendible CMS and avoiding any core hacks. As
the plugin API currently stands we have JEvent, JObserver, JObservable
and JDispatcher, every time any hook is triggered by this call:
"$dispatcher->trigger( 'onAfterRender' );" the dispatcher will loop
through all plugins that have been initialized. Even though the
'onAfterRender' trigger is meant for system plugins, take this for
example: if we are on com_search all of the search plugins are loaded,
the dispatcher will be looking through all of the search plugins to
see if they have the 'onAfterRender' method. So in short, we have two
major problems with the current plugin API, 1) there is no way to tell
JDispatcher to only trigger plugins of a certain type. 2) We have to
constantly be calling method_exists() to see if the observed plugin
has the trigger that we are looking for. These two issues will prevent
us from having more hooks throughout Joomla. The more plugins that are
loaded on each page load, the slower Joomla will load.
Now to the fun fun fun stuff (since it is friday and all). I have
created 2 new hook classes, also referred here as JHook, these should
completely replace JEvent, JObservable, JObserver and JDispatcher. We
only need one of two hook classes that I have created, but I still
need to run more tests to see which will be faster. The only
difference between them is that one of them is meant to be used as a
static class, and the other one as an object. I also created two new
JPlugin classes, JPluginConstruct and JPluginInit, the reason for this
is to test the speed of using the magical __construct method versus an
init function, I also needed to avoid the call to JEvent and
JObserver.
As I said both JHook classes are basically the same. The difference
biggest difference between JHook and the current plugin API, is that
each plugin hook needs to be registered to JHook otherwise it won't
get called, where the current API uses method_exists() to see if the
trigger exists. Here we are relying on developers to register their
plugin before it runs. A simple example of registering a plugin would
be:
JHook::addFilter( 'hook_do_test', array( $this, 'do_test' ) );
This example registers the method 'do_test' for the current object, to
the 'hook_do_test' trigger.
To trigger this hook we would do this:
JHook::trigger( 'hook_do_test', array( $counter ) );
We pass an array of arguments that the 'do_test' method will receive.
JHook::trigger(); would be replacing JDispatcher::trigger();
JHook also has the ability to have priorities for the hooks, but this
can be explained at a later point.
I have created 5 tests, all test give the same end result, each test
contains 2000 plugins. Each plugin has one parameter stored in the DB
called "value" which always contains the value of 1. Each time the
plugin runs, it adds its value to the filtered $counter variable. This
yields the same result each time, 2000.
Each test is described below, I also describe how to test them
yourself:
* joomla test. Runs 2000 plugins using the current Joomla API.
- Creating plugins:
http://localhost/index.php?option=com_speedster&task=createjoomla&amount=2000
- Running test:
http://localhost/joomlaspeed/index.php?option=com_speedster&task=joomla
* hook test. Runs 2000 plugins, each plugin extends to
JPluginConstruct. It uses the hook.php file, uses __construct() to
initialize plugin, and uses JHook as an object.
- Creating plugins:
http://localhost/index.php?option=com_speedster&task=createhook&amount=2000
- Running test:
http://localhost/joomlaspeed/index.php?option=com_speedster&task=hook
* hookinit test. Runs 2000 plugins, each plugin extends to
JPluginInit. It uses the hook.php file, uses init() to initialize
plugin, and uses JHook as an object.
- Creating plugins:
http://localhost/index.php?option=com_speedster&task=createhookinit&amount=2000
- Running test:
http://localhost/joomlaspeed/index.php?option=com_speedster&task=hookinit
* hook2 test. Runs 2000 plugins, each plugin extends to
JPluginConstruct. It uses the hook2.php file, uses __construct() to
initialize plugin, and uses JHook as a static class.
- Creating plugins:
http://localhost/index.php?option=com_speedster&task=createhook2&amount=2000
- Running test:
http://localhost/joomlaspeed/index.php?option=com_speedster&task=hook2
* hook2init test. Runs 2000 plugins, each plugin extends to
JPluginInit. It uses the hook2.php file, uses init() to initialize
plugin, and uses JHook as a static class.
- Creating plugins:
http://localhost/index.php?option=com_speedster&task=createhook2init&amount=2000
- Running test:
http://localhost/joomlaspeed/index.php?option=com_speedster&task=hook2init
Time to execute each test:
* joomla - Time to execute ~1.350 seconds.
* hook - Time to execute ~0.440 seconds.
* hookinit - Time to execute ~0.440 seconds.
* hook2 - Time to execute ~0.440 seconds.
* hook2init - Time to execute ~0.440 seconds.
These are averages, I still need to go through and do more testing on
each to figure out the best one out of the bunch.
So this is it, what it comes down to, you can see the time difference,
about 3 times faster!
I would love for Joomla to have more hooks throughout the CMS, to
allow developers more extendibility, thus avoiding hacking, this is my
end goal.
Rafael
ps. I implemented a fix that just got implemented on github for the /
libraries/plugin/helper.php file line 158-161. The other modifications
to that file, are simply for testing purposes.