Page 1 of 1

Tip: Keep your XXXXX.module.php files small

Posted: Mon Jun 20, 2011 4:45 pm
by calguy1000
We all know that PHP4's support for Object Oriented programming was 'simplified'... it didn't support private and public members, no static members etc. This didn't make writing modules all that easy, especially if you wanted to keep memory usage low.

Also, CMSMS due to limitations in PHP4 had to load all of the modules in order to do things. They are instantiated upon request. We added a few optimizations over time to mark modules as 'frontend only' or 'has no admin' to only load the modules that absolutely had to load.. but in most production sites today, most of them still have to be.

This meant that for convenience we put most of our extra methods that our modules needed into the main class itself. So that we could call $this->somemethod(...) from our module actions, and everything would still work. Some ambitious developers experimented with various forms of separating the utilities up into separate classes with various forms of lazy loading.... with varying degrees of success.

In PHP5 the OOP mechanisms are much better. We have better constructors, exceptions, static members, classes, and an excellent lazy loading mechanism (the autoload stuff). This gives us alot more power to split things up and only load what is needed when it's needed.

CMSMS 1.10 will institute lazy loading for the modules themselves. Modules aren't loaded until they are explicitly called, with some limitations (modules that register routes or create additional smarty plugins can't be lazy loaded in 1.10 yet). This is a big deal in the admin, as we've instituted a mechanism to cache the data needed to build the admin navigation, most requests won't require loading all of the modules. With the obvious exception of 'Extensions >> Modules'.

So in 1.10 we have some big improvements, but there is still a need to be smart about how we program our modules... so I have some advice on how to layout your XXXXX.module.php files to reduce memory needed for simple requests (like building navigations, or iterating through modules).

The simple explanation is.... put your extra functions into other classes, and try to keep the XXXX.module.php as small as reasonably possible (while still keeping it readable, and documented). I use ancillary classes in my 'lib' directory. to do most of the grunt work now.

Below I'll outline (via use of gross oversimplification) the old way we used to do things, and the way I am now doing things in my modules to help keep memory utilization low.

The Old way:
your MyModule.module.php file:

Code: Select all

class MyModule extends CmsModule
{
    // a bunch of (small) stub functions that override methods in the CmsModule classes

    function myHelperFunction()
    {
       $setting = $this->GetPreference('some_preference',0);
       // probably do some database queries, and return some results
    }
}
your action.dosomething.php file:

Code: Select all

if( !isset($gCms) ) exit;
$data = $this->myHelperFunction();
$smarty->assign('some_data',$data);
The New Way:
Your MyModule/lib/class.mymodule_utils.php file

Code: Select all

final class mymodule_utils
{
   protected static function __construct() {}

   public static function myHelperFunction()
   {
       $mod = cms_utils::get_module('MyModule');
       $setting = $mod->GetPreference('some_preference',0);
       $db = cmsms()->GetDb();
       // probably do some database queries, and return some results
   }
}
Your action.do_something.php file:

Code: Select all

if( !isset($gCms) ) exit;

$data = mymodule_utils::myHelperFunction();
$smarty->assign('some_data',$data);
-- End of gross oversimplification --

The autoloader in CMSMS 1.10 will automatically look for class files in a module's lib directory. Modules derived from CGExtensions have had this capability for a while.

This means that the mymodule_utils class is not even loaded into memory until it is called (in this grossly oversimplified example) until it's called in the action.do_something.php file. And that the MyModule.module.php file remains small and lightweight if it does have to be loaded into memory.

Now typically you will have more than one function in your utils class. Or you may have multiple classes that separate functionality based on frontend or backend functionality... you get the idea.

Hope this helps you.

Re: Tip: Keep your XXXXX.module.php files small

Posted: Tue Jun 21, 2011 8:25 pm
by Duketown
calguy1000,

I've looked at the oversimplified example and took module 'Availability' as one of your modules that seems to be split according to this method. I instantly noticed I still have a lot to learn.

Being a developer that keeps a number of modules up and running I see a lot of work ahead, but not yet the glory.
Let me put it differently: I don't understand yet where the real benefit is. Is it in the better performance in the back end? Does a visitor of sites that use my modules notice it?

I would like to follow some sort of standard in the modules that I write or extensions/modifications that I make on existing modules. Am I wrong in seeing this is a real lot of work (I mean the rewriting toward a 1.10 version of my modules and of course the testing).

What do other developers have in mind how to transfer/crossover/upgrade/update?

Duketown

Re: Tip: Keep your XXXXX.module.php files small

Posted: Mon Oct 31, 2011 5:38 pm
by Foaly*
calguy1000 wrote: The New Way:
Your MyModule/lib/class.mymodule_utils.php file

Code: Select all

final class mymodule_utils
{
   protected static function __construct() {}

   public static function myHelperFunction()
   {
       $mod = cms_utils::get_module('MyModule');
       $setting = $mod->GetPreference('some_preference',0);
       $db = cmsms()->GetDb();
       // probably do some database queries, and return some results
   }
}
__construct() cannot be static!