Drupal Without Functions: A Proposal for D8

Apr 1 2011

Drupal 8 is in the early stages of planning, and I have a proposal to add -- a proposal which, if implemented, would make Drupal the first of a new breed of faster, leaner, meaner and simpler web applications. Now is the time to grab the bull by the horns, and steer fate.

In my tireless fight against unnecessary complexity, I have argued in the past that OO and Drupal do not mesh well. But upon further reflection, I have come to see the bigger picture. Drupal's number one hinderance is it's reliance upon an antiquated abstraction called the function. And only when we completely eliminate userland functions will Drupal be able to entirely fulfill its true potential.

Let me give an example of a function anti-pattern that appears throughout the Drupal codebase. In the following code sample, I show the fundamental way that previous versions of Drupal have gone astray. <!--break-->

<?php
function foo($a, $b) {
  $c = $a + $b;
  return $c
}
?>

Somewhere else in the code, we might call this:

<?php
  $my_a = 1;
  $my_b = 2;
  $bar = foo($my_a, $my_b);

  print $bar;
?>

What's wrong with the above? Lots. Let me give you a short list:

  • Confusing: In order to understand the second code block, you have to read the entire function call for foo. That's hard.
  • Needless symbol table clutter: Why do we need six variables when three will do? Why clutter the function table with yet another name? Strip out the wanton complexity!
  • Memory intensive: The sample above must register a function name in the function lookup table. Both $a and $b are passed by value, which means memory is needlessly used simply to meet the requirements of this antiquated abstraction level.
  • Debugging is hard: With all those variable names ($mya, $myb, $bar, $a, $b, $c...) it takes a rocket scientist to figure out what the code above is doing.

What I'm arguing is that we remove all functions from Drupal 8. Let's KISS functions goodbye and say hello to a new streamlined powerhouse version of Drupal.

At this point I can hear critics asking, "with what do you propose we replace functions?" (It is well known that critics do not end their sentences with prepositions.) Let me tell you the answer.

Includes are the new functions

Instead of using functions, with all their evil and confusing abstractions, Drupal 8 should use the include directive and strategically structured files. Goodbye functions, hello diffuse use of include statements.

The best way to explain this is by rewriting the complex code we saw earlier into this new simple include paradigm.

File foo.php:

<?php
$c = $a + $b;
?>

Now the calling code:

<?php

$a = 1;
$b = 2;

include 'foo.php';

print $c;

?>

See how much easier this is? Immediately you will notice several improvements:

  • We don't needlessly copy variables. It's like magic.
  • There are fewer errors, thanks to PHP's lazy initialization (just don't turn on E_STRICT). Even if we forget to define a few variables, PHP will keep processing.
  • The code is ever so easy to read. And consistent. $a in the calling file is the same as $a in foo.php.

Welcome to the power and simplicity that comes when we distrust abstractions and go with the flow!

But wait! What about built-in functions?

I already hear the critics pointing out that we will always have to use PHP's built-in function calls for some things, and this will needlessly confuse developers.

There's an answer for that: wrappers.

Consider a call to the built-in strtr function. According the the antiquated paradigm, we used to call it directly: strtr($src, $to_replace, $replace_with) We now handle that by creating an include file:

File strtr.php

<?php

$res = strtr($a, $b, $c);

?>

Now a call to strtr can be expressed eloquently:

<?php

$a = 'some string!';
$b = array('!' => '?');
$c = NULL;

include 'strtr.php';

print $res; // Will print 'some string?'

?>

Beautiful and elegant. No parenthesis to confuse people. No return values. No confusion. Even though PHP itself may be hindered by it's misconceived notion of functions, we can still overcome this limitation and ease the burden on the developer. DX comes first, after all.

Claws: The New Style Hooks

The hook system in Drupal was a nice way of trying to emulate the techniques I've already shown. But now we can replace the hook system with a better, simpler, more powerful system.

This new system is called the CLAW system, since it's like hooks, only totally wicked. The claw system can accomplish all that the hook system could, but without messy function_exists and call_user_func_array calls.

For example, let's say that we are implementing claw_view, the new alternative to hook_view. This is done by creating the correct file.

Here's how you define a claw:

File mymoduleview.php

<?php
/**
 * Implements claw_view.php
 */

// set a new title on the node. 
$node->title = 'This is the new title.';

?>

Now that code will automatically be executed each time claw_view is executed:

<?php

$nid = 1234;
// We get our $node from node_load.php
include 'node_load.php';

// Now we prepare it for viewing by calling The Claw:
$claw = 'view';
include 'the_claw.php';

// Now this will be 'This is the new title'
print $node->title;
?>

Yes, that's all there is to the new claw system! It's vastly simpler than the old hook system. Also, since everything is in one long continues script, it's far easier to debug. Stack traces and function traces are also much cleaner. And since every feature is broken down into its own file, it will be much easier to find segments of functionality. IDE friendly, too!

And where does all the magic happen? In The Claw, of course.

Internals of The Claw

Hard core developers are already asking how the new claw system will work. Here's the magic in action:

<?php
/**
 * The Claw
 * 
 * This expects that $claw is set.
 */

// Get a list of all files.
$all_files_in_drupal = array();
include 'fetch_all_php_filenames.php';

// Get all of the filenames per module:
foreach ($all_files_in_drupal as $module_name => $filenames) {

  // For each file, see if it matches the claw pattern (e.g. claw_view)
  foreach ($filenames as $filename) {

    $target_include = $module_name . '_' . $claw;

    // If we find a match, include it.
    if ($filename == $target_include) {
      include $module_name . '/' . $target_include;
    }
  } 
}
?>

Amazing in it's simplicity, but endlessly powerful.

Conclusion

The days of procedural programming are over. As Drupal begins its next major development cycle, I urge all developers to abandon antiquated OOP and procedural concepts and switch to include-driven programming. And happy April Fools day.