views:

327

answers:

5

Does Drupal parse (and/or run) hooks that are unrelated to the content being loaded by the current user?

For example, say I had a module foo installed and active with the following hooks:

<?php 
// .. stuff ...    
function foo_menu() {
      $items = array();
      $items['foo/show'] = array(
        'title' => t('Foo!'),
        'page callback' => 'foo_display_all',
        'description' => 'All our foo are belong to you',
        'type' => MENU_NORMAL_ITEM,
      );
      return $items;
    }

    function foo_display_all() {
    // About 100 lines of code
    }
// ... stuff ...

Would Drupal parse (and thus effect the load time) for pages that aren't listed in foo_menu? Put another way, would the length and complexity of foo_display_all effect how www.example.com/bar loads?

At risk of having two different questions here, I'll say I would be grateful for an explanation (or link to an explanation) of how and why Drupal does or does not parse, rather than a yes/no answer.

+4  A: 

hook_menu is used to tell drupal about what to do at specific urls, so the result of that is cached.

Drupal will only execute the content of the hooks themselves not the entire content of the file they are located in. So when hook menu is invoked in the above example, on the foo_menu() function will be run. You can take a look at the intro text at the Hooks API

Edit: In order for PHP to execute the function, it needs to include the file where it is located. So when Drupal wants to execute a hook, PHP would need to parse the code in that file. That is just how PHP is designed, so haven't got much to do with Drupal.

This is also the reason why a lot of modules make a lot of inc files, to limit the amount of code needed to be parsed when hooks are fired.

googletorp
Thanks. But, I was more wondering if the files would be read and parsed -- I'm grateful that Drupal is smart enough not to actually execute unused functions, but I don't know if it reads/parses them and then ignores them, or if it doesn't read them at all unless they're needed.Perhaps this is what you meant?
anschauung
I think it is, if you don't want it to user an inc file.
Jeremy French
Thanks for the explanation. Your answer about using .inc files somewhat contradicts Craig's answer below, but I'll post a new question to resolve that.
anschauung
+3  A: 

Drupal includes all of the MODULE.module files (and anything they include) for every module for every request.

The only way for Drupal core to know if the module has any hooks it needs to call is to load the file. This will take time and memory.

Craig
Thanks for the explanation. Your comment about using .inc files somewhat contradicts @googletorp's answer, but I suppose a new question is the best way to resolve that.
anschauung
If the .module file has the include statement inside a function then the included file is only read when the function is called. If the include is at global scope the include file is always read.
Craig
+3  A: 

Firs of all, I'm not an experienced Drupal developer, second, it is not a nice implementation and third, I have not tried this, but should work

function foo_display_all() {
    include("foo_display_all_body.php");
}

This way the hooks are parsed every time, + one additional php file with the function body.

Fourth, it's micro optimization. Might be better to avoid it if not absolutely necessary, as the additional complexity (and the +1 file read) can cost more for you in the long run than it saves on parsing.

If you want to make the php code parsing faster, you should use an opcode cache

Csaba Kétszeri
+3  A: 

Yes. As others have noted, splitting things out into include files that are loaded conditionally is the only way to cut that down. Starting in Drupal 6, it became possible to move theme_whatever() functions, as well as hook_menu() page callbacks, into separate include files. Drupal will automatically load them when they're needed without you doing any explicit require_once() juggling.

See the hook_menu() and hook_theme() documentation for details.

It's also important to note that if you're running an opcode cache like APC, splitting things into a bunch of conditional includes is actually worse -- APC can do all of the parsing and compiling of the PHP source in one go and persist it between requests. Splitting things out conditionally just gives it multiple discrete 'codebases' to compile depending on what's being done.

In the currently-under-development Drupal 7, a general Code registry has been added that allows any hook implementation to be split out into a separate include file. However, the overhead of managing that internal cache of functions and .inc locations, and loading them on the fly, eats up the performance gains of the smaller-to-parse codebase. The only real payoff is reduced memory usage for those on shared hosts with tight 12-16 meg memory limits; it's unclear whether the change will survive through to the final release of Drupal 7 given the tradeoffs.

The upshot: in Drupal 6, split out the menu callbacks that build custom pages into a separate .inc file, and it will only be loaded when those pages are built. Do the same with any theme functions. And if you're using an opcode cache like APC, remember that your separate .inc files are only good for organizational purposes -- they won't give you any performance boost.

Eaton
Great answer -- thanks for the detailed explanation!
anschauung
A: 

APC now seems to cache .inc files as well as php, which DOES give a great performance boost.

dfg