New proposed plugin API

109 views
Skip to first unread message

Rafael Corral

unread,
Jun 24, 2011, 11:34:27 AM6/24/11
to Joomla! Framework Development
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.

Rafael Corral

unread,
Jun 24, 2011, 1:41:19 PM6/24/11
to Joomla! Framework Development
I probably should have posted this towards the top, but this is a POC,
and these tests are ran with a quick component I put together
com_speedster. The hook.php and hook2.php files are located in that
components folder.
>   - Creating plugins:http://localhost/index.php?option=com_speedster&task=createjoomla&amo...
>   - 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&amoun...
>   - 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&a...
>   - Running test:http://localhost/joomlaspeed/index.php?option=com_speedster&task=hook...
> * 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&amou...
>   - 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&...
>   - Running test:http://localhost/joomlaspeed/index.php?option=com_speedster&task=hook...

Paladin

unread,
Jun 25, 2011, 12:32:29 AM6/25/11
to Joomla! Framework Development
Actually, I wouldn't replace JObserver/JObservable, as these don't use
method_exists and they can be used for things besides event
dispatching.

You may have a good point with your approach to event handling,
frankly I'll need more than the quick glance I took to evaluate it
properly. But as I've noted elsewhere, there's more to the Observer
pattern than event processing. Sometimes it's "hey come look I did
something you might be interested in" and the observers come check it
out. JObserver/JObservable, as you note, don't play the method_exists
game, so this isn't a good reason to drop them. I can think (and have
written) of others, but I'd like to preserve the option of using an
Observer pattern without it being an event system, and without
dedicating a class to doing it, but instead "mixing it in" to an
existing class.

Some further points:

A) I would resist with great gusto the static version, on general
principles, unless it can be shown there is no other way to perform
the task. Static method calls have been the largest roadblock to
getting this system under test. I have spent many months going to
lengths I shouldn't have to go to simply because someone wanted to
make a call static (and in the case of the input filters, making a
call static introduced bugs into the system that proved elusive, as
the code *only* failed when being called statically) and I would
consider inserting more of them into the tree without extreme
justification to be little short of a declaration that Joomla has no
intention of ever becoming testable. They also make further extensions
of the system difficult. AFAIC, they're one short step away from
hardcoding data into the code.

B) Remember there's more code than just the platform and the CMS that
depend on this. Replacing existing systems with ones that function
differently requires extensive testing with 3rd party plugins,
something I don't have the resources for, but perhaps someone else
can? If there are plugins that rely on the previous mechanism's
"method discovery" approach, changing it would break them, which, at
least for a point release, is unacceptable.

Hopefully I'll have time this week to take a closer look and be able
to give you a more specific opinion.

Rafael Corral

unread,
Jun 25, 2011, 6:05:09 PM6/25/11
to Joomla! Framework Development
Paladin,

If we need to keep JObserver/JObservable that is fine with me, I was
just trying to make things run as quickly as possible, avoiding
overhead.

A) I agree, lets forget about the hook2.php class.

B) This will probably be our major road block. An idea to help
everyone move to the new mechanism is to still provide JDispatcher for
a release point, this way there would still be backwards
compatibility. Unfortunately this may defeat the whole purpose of
speeding up the plugin API.

I'm looking forward to see what you find from playing around with it.

Steven Pignataro

unread,
Aug 8, 2011, 4:01:04 PM8/8/11
to joomla-dev...@googlegroups.com
Paladin,

I would be interested to find out if you have had some time to look into this. Kind of looks like a stale topic but would like to re-ignite it.

Kindest regards,

--Steven Pignataro

Rafael Corral

unread,
Aug 8, 2011, 7:43:04 PM8/8/11
to Joomla! Framework Development
Hey Guys,

Any thoughts on having this integrated into Joomla 1.8?
Would it be beneficial for me to have this developed on a github fork?

Rafael

Steven Pignataro

unread,
Oct 11, 2011, 4:31:37 PM10/11/11
to joomla-dev...@googlegroups.com
Any movement on this?

Kindest regards,

--Steven Pignataro
Reply all
Reply to author
Forward
0 new messages