vBulletin 4 - A Developer’s Perspective (EXTREMELY LONG POST)
Surfing on the official forum of Vbulletin , i found this interesting article about the new version of VB . Vbulletin 4
Preface
Evening everyone. Here we are on the eve of vb 3.7 which promises to be the last member of the vbulletin 3.x branch (security patches not-withstanding). The software has come along way to become one of the strongest PHP software packages of all, and it is backed by one of the best communities online, both user and programmer side. Jelsoft should be justly proud of their accomplishment.Before I begin I’d like to introduce who I am and a bit of my background. vBulletin brought me back to programming after I’d given it up in college, and for that I am thankful. For all intents the programming staff of vbulletin were my teacher and much of my coding style is owed to them. I would not be doing the job I do today where it not for them, and for that I’m grateful. I mention this because in this post I’m going to take a hard look at the 3.x codebase, particularly 3.7beta6 and while much of this look will be with a critical eye I want to establish now that I have nothing but the highest level of respect for the minds behind this code - where it not for their efforts I would not be in a position to do this analysis and make these suggestions.
All the same I’ve branched away from vbulletin and learned to program in Actionscript and leverage the prototype framework. Last year I was tasked by my boss to build from scratch a new framework for use in house. The lessons I learned from this process opened my eyes to new ideas and new implementations.
This post, and the thread it is sure to spawn, are concerned with the code of vBulletin 4 from the point of view of a developer. This post isn’t about individual features per say, but rather the paradigm of the code - how it is, and how it can be changed. I do not expect all of these suggestions to be taken, I hope that some will. This is my way of giving back to the folks at Jelsoft to whom I owe so much.
The Case for PHP 5.2 as a Minimum
As we all know PHP 4 has reached end of life. Many hosts still use it, but by the end of the year the move to PHP 5 should be under full way. Adoption of PHP 5 has been slow in no small part due to how buggy 5.0 was, and 5.1 wasn’t much better. However, PHP 5.2 has closed all of the worst of these problems and forms a solid base on which to stand.
The largest concern about making vbulletin 4 incompatible with PHP 4 is loss of market share. In my opinion this issue isn’t too strong because vbulletin is already leagues ahead with 3.7 and honestly 3.7 pushes PHP 4 about as far as it is going to go.
Further it is my belief that an inability to run vbulletin 4 will cost the hosting companies more money than Jelsoft would lose in this move. vbulletin is a ‘killer ap’ - with enough community and market clout to drive hosts to upgrade or lose customers.
Setting PHP 5.2 as the minimum opens a lot of doors for developers. First is the object model of PHP. Jelsoft will be able to use private, protected and public modifiers to control how 3rd party plug ins interact with the code. This will allow boards to remain more stable. PHP 5 also has class autoloading which as I’ll show in this post offers more to the framework than simply being able to drop requires. Instead it will allow only the code that is needed to be loaded into memory, lowering vbulletin’s monstrous memory footprint.
Many of the suggestions made throughout this post are predicated on PHP 5 functionality that isn’t available in PHP 4, so in a sense this whole post is a “case for PHP 5″ - but even if that wasn’t the case I feel the above is a compelling argument for setting this as the minimum.
A Fully Object Oriented program structure
vbulletin has classes, but as of 3.7 it’s code still has one foot firmly planted in procedural land. Going to PHP 5 facilitates making the whole program class based, and by combining this with autoloading the program can be set up to only pull the libraries it needs.
One sore point is the global variables that vbulletin sets. $db, $phrases, $bbuserinfo, and $vbulletin all reside in the global scope. To protect them vbulletin unsets all vars in $GLOBALS just in case someone left register globals on, but this plays havoc with integration measures.
In vb4 please use a static registry
The registry class is the store point of variables and little more - the three methods of the class could all be static and instead of using the new operator to create a $vbulletin object that needs to be passed like a hot potato in the construct argument of pretty much every class in the program (creating a reference web that bogs down the Zend Engine quite a bit) just use a static class. Hence
With that approach you can’t accidently have more than one db object. Other classes that need to add themselves to the registry follow the same approach. It’s much cleaner and should parse quicker as well. As an added bonus, if you need to debug a class object with print_r($object) you don’t end up with a mile long result from referenced objects not related to the problem at hand.
Using this approach it is possible to avoid putting a variable into $GLOBALS. This in turn makes the value of the register_globals setting irrelevant so the code in place to mitigate it’s influence can be done away with. This in turn increases vbulletin’s integration flexibility.
Models, Views, Controllers, Templates…
Currently vbulletin 3.7 has templates, and it has some amount of database abstraction, but if you wanted to use MSSQL or Oracle for vbulletin you couldn’t do it. Query code and View code alike are mixed in together in a tanged knot.
Take a look at global.php. Much of it’s actions prepare to display forum pages which is a LOT of overhead for extending programs By the time global.php finishes even if your script just says ‘Hello World’ you’ve loaded 3.5 MB. This overhead would persist if Jelsoft ever provided a CMS as an extension to vbulletin - and CMS extensions to vbulletin such as vbadvanced take a performance hit which cannot be easily avoided.
Elements of the code should only activate as needed. For example, if the user isn’t logged in why start the database engine at all to look at forumhome (assuming the contents of that page are cached)?
Many of these problems can be addressed by adopting the model-view-control paradigm. In this approach each viewable file, such as forumdisplay.php, showthread.php or index.php starts a controller that corresponds to the page and also the mode of that page (linear, threaded and hybrid views would be best served with separate controllers). That controller knows the table model(s) it needs to prepare an output array that the view file in turn uses to display the page. Exactly which view file gets loaded is determined by style.
If the database is switched out the model classes would be switched, but the controllers and views wouldn’t be. Similarly the views can be switched to alter the layout of the page in major ways (minor adjustments should be relegated to CSS to resolve).
PHP is a template engine
Speaking of templates - while vbulletin has a powerful and flexible template engine there exists a far faster and more powerful one - PHP itself. Further vbulletin 3.7 is beginning to slow down large boards by introducing templates that aren’t even used to the flow - yet they still have to be eval’ed. And speaking of eval() - it is 5 to 10 times slower than file code because the Zend engine cannot precache it. Avoid the use of this function as much as possible.
Templates are necessary to separate business logic from pure display logic. This said, let the template files be PHP files .
The method is a member of the controller abstract class. If the template has any child templates then include is called in the template to, well, include them. Within the template logic structures are present and used as needed to assemble rows or make layout decisions in the view where it belongs. Making a decision in the controller then transfering the results of that decision to the view through a variable just makes life harder for the programmer, the computer and even the designer to some extent since he doesn’t have an easy way of seeing where that value is coming from.
One final, but huge advantage this has over vb3.x template system is that templates aren’t evaled until board data is on the way out. This gives the programmer of the controller the freedom to evaluate page elements in whatever order he pleases since it will have no impact on the page. For example in the current code you can’t put the navbar in the header template because the navbar is eval’ed next to last. Under this system you can do this if you want, further you can move template pieces around with a great deal of freedom not available in the current system.
A note on CSS - if the templates are written with full CSS in mind then many designs could be accomplished with CSS files alone. I understand layout tables for forum and thread listings - tabular data is what tables are for. But when the navbar is built with tables this is a problem.
More PHP in the templates would make them harder to write - I’ll admit that. The tradeoff in speed and the increased pliability the templates would gain are worth this cost.
Hooks and Prototypes
vbulletin’s hook system is a serviceable way to get into the code but there’s a better way that doesn’t involve use of the costly eval statement. One of these two I’ve already done - prototype emulation. The second is theoretical, but I believe will work. Both of these rely on the code being written a certain way to work so if they are to see the light of day in vb4 they’ll have to be implemented at project start.
Prototype Emulation relies on PHP 5’s autoload. Each class has it’s own file, however each class is started like so
When autoload is called in finds the database by filename and requires it, then checks to see if the class is a prototype. If it is it looks in a folder set aside for ‘overrides’ - these files have the same name as the class they override and the actual class’ name. An override file for the database would begin
If this class can’t be found php uses an eval statement to create an empty shell class around the prototype. Note however that this technique doesn’t work with Abstract classes
To maximize polymorphism in this approach the functions within the class should only perform one action each. This way if someone needs to hook in they extend the class.
This system works great for one mod or mod at a time, but if multiple products need to override the same file then there’s a problem.
Another - theoretical (as in I’ve not coded this so I’m not sure it would work) - approach is to emulate listeners and events. I believe this could be done with the magic __call function.
Essentially you derive each and every class in the system from a basic class which defines __call. When a function is called this method is invoked and this gives it an opportunity to fire an event - onBefore_ClassName_MethodName. It looks in some sort of repository for each function that wants to be called for the event and passes it the arguments and $this. Then it runs the function then it fires onAfter_ClassName_MethodName and again runs those methods.
To make this work all the functions will need their names prefixed with _ - __call only fires when a method that doesn’t exist is fired. Further no function should have internal vars - instead they’d all need to use class member vars so that the listeners can act upon the data.
This method is similar in principle to Joomla 1.5’s approach, except that their approach is horribly complicated by their ‘emulate PHP 5 under PHP 4′ architecture from hell.
Closing
I hope this is useful. vb4 has a difficult road to travel, balancing efficiency needs of large boards with feature richness. I believe this can be accomplished by switching to an architecture that minimizes wasted includes, reduces the use of eval, and leverages the power of the object oriented paradigm. Thank you for your time.
Leave a Reply