Index: includes/common.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/common.inc,v retrieving revision 1.1005 diff -u -p -r1.1005 common.inc --- includes/common.inc 3 Oct 2009 19:16:03 -0000 1.1005 +++ includes/common.inc 4 Oct 2009 04:20:08 -0000 @@ -4208,52 +4208,44 @@ function drupal_system_listing($mask, $d } /** - * Hands off structured Drupal arrays to type-specific *_alter implementations. + * Hands off alterable variables to type-specific *_alter implementations. * - * This dispatch function hands off structured Drupal arrays to type-specific - * *_alter implementations. It ensures a consistent interface for all altering - * operations. + * This dispatch function hands off the passed in variables to type-specific + * hook_TYPE_alter() implementations in modules. It ensures a consistent + * interface for all altering operations. + * + * A maximum of 7 arguments is supported. In case more arguments need to be + * passed, modules may pass multiple arguments in a single argument: + * @code + * $context = array( + * 'something' => $something, + * 'otherthing' => $otherthing, + * // ... + * ); + * drupal_alter('mymodule_data', $data, $context); + * @endcode * * @param $type - * The data type of the structured array. 'form', 'links', - * 'node_content', and so on are several examples. - * @param $data - * The structured array to be altered. + * The data type of the structured array. 'element_info', 'form', and + * 'node_content' are several examples. * @param ... - * Any additional params will be passed on to the called - * hook_$type_alter functions. + * A variable amount of arguments to be altered or to provide as context, + * which will be passed on to hook_$type_alter() functions. */ -function drupal_alter($type, &$data) { - // PHP's func_get_args() always returns copies of params, not references, so - // drupal_alter() can only manipulate data that comes in via the required first - // param. For the edge case functions that must pass in an arbitrary number of - // alterable parameters (hook_form_alter() being the best example), an array of - // those params can be placed in the __drupal_alter_by_ref key of the $data - // array. This is somewhat ugly, but is an unavoidable consequence of a flexible - // drupal_alter() function, and the limitations of func_get_args(). - // @todo: Remove this in Drupal 7. - if (is_array($data) && isset($data['__drupal_alter_by_ref'])) { - $by_ref_parameters = $data['__drupal_alter_by_ref']; - unset($data['__drupal_alter_by_ref']); - } - - // Hang onto a reference to the data array so that it isn't blown away later. - // Also, merge in any parameters that need to be passed by reference. - $args = array(&$data); - if (isset($by_ref_parameters)) { - $args = array_merge($args, $by_ref_parameters); - } - - // Now, use func_get_args() to pull in any additional parameters passed into - // the drupal_alter() call. - $additional_args = func_get_args(); - array_shift($additional_args); - array_shift($additional_args); - $args = array_merge($args, $additional_args); - +function drupal_alter($type, &$arg1 = NULL, &$arg2 = NULL, &$arg3 = NULL, &$arg4 = NULL, &$arg5 = NULL, &$arg6 = NULL, &$arg7 = NULL) { foreach (module_implements($type . '_alter') as $module) { $function = $module . '_' . $type . '_alter'; - call_user_func_array($function, $args); + // drupal_alter() is called a lot of times in a single request; even more + // times when caches are rebuilt, so we do not use call_user_func_array(). + switch (func_num_args()) { + case 2: $function($arg1); break; + case 3: $function($arg1, $arg2); break; + case 4: $function($arg1, $arg2, $arg3); break; + case 5: $function($arg1, $arg2, $arg3, $arg4); break; + case 6: $function($arg1, $arg2, $arg3, $arg4, $arg5); break; + case 7: $function($arg1, $arg2, $arg3, $arg4, $arg5, $arg6); break; + case 8: $function($arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7); break; + } } } Index: includes/form.inc =================================================================== RCS file: /cvs/drupal/drupal/includes/form.inc,v retrieving revision 1.378 diff -u -p -r1.378 form.inc --- includes/form.inc 3 Oct 2009 20:17:46 -0000 1.378 +++ includes/form.inc 4 Oct 2009 04:06:55 -0000 @@ -669,20 +669,11 @@ function drupal_prepare_form($form_id, & } } - // Normally, we would call drupal_alter($form_id, $form, $form_state). - // However, drupal_alter() normally supports just one byref parameter. Using - // the __drupal_alter_by_ref key, we can store any additional parameters - // that need to be altered, and they'll be split out into additional params - // for the hook_form_alter() implementations. - // @todo: Remove this in Drupal 7. - $data = &$form; - $data['__drupal_alter_by_ref'] = array(&$form_state); - drupal_alter('form_' . $form_id, $data); - - // __drupal_alter_by_ref is unset in the drupal_alter() function, we need - // to repopulate it to ensure both calls get the data. - $data['__drupal_alter_by_ref'] = array(&$form_state); - drupal_alter('form', $data, $form_id); + // Invoke hook_form_FORM_ID_alter() implementations. + drupal_alter('form_' . $form_id, $form, $form_state); + + // Invoke hook_form_alter() implementations. + drupal_alter('form', $form, $form_state, $form_id); } Index: modules/simpletest/tests/common.test =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common.test,v retrieving revision 1.77 diff -u -p -r1.77 common.test --- modules/simpletest/tests/common.test 3 Oct 2009 19:16:04 -0000 1.77 +++ modules/simpletest/tests/common.test 4 Oct 2009 04:11:23 -0000 @@ -2,6 +2,59 @@ // $Id: common.test,v 1.77 2009/10/03 19:16:04 dries Exp $ /** + * @file + * Tests for common.inc functionality. + */ + +/** + * Tests for URL generation functions. + */ +class DrupalAlterTestCase extends DrupalWebTestCase { + public static function getInfo() { + return array( + 'name' => 'drupal_alter() tests', + 'description' => 'Confirm that alteration of arguments passed to drupal_alter() works correctly.', + 'group' => 'System', + ); + } + + function setUp() { + parent::setUp('common_test'); + } + + function testDrupalAlter() { + $array = array('foo' => 'bar'); + $object = new stdClass; + $object->foo = 'bar'; + + // Verify alteration of a single argument. + $array_copy = $array; + $array_expected = array('foo' => 'Drupal'); + drupal_alter('drupal_alter', $array_copy); + $this->assertEqual($array_copy, $array_expected, t('Single array was altered.')); + + $object_copy = clone $object; + $object_expected = clone $object; + $object_expected->foo = 'Drupal'; + drupal_alter('drupal_alter', $object_copy); + $this->assertEqual($object_copy, $object_expected, t('Single object was altered.')); + + // Verify alteration of multiple arguments. + $array_copy = $array; + $array_expected = array('foo' => 'Drupal'); + $object_copy = clone $object; + $object_expected = clone $object; + $object_expected->foo = 'Drupal'; + $array2_copy = $array; + $array2_expected = array('foo' => 'Drupal'); + drupal_alter('drupal_alter', $array_copy, $object_copy, $array2_copy); + $this->assertEqual($array_copy, $array_expected, t('First argument to drupal_alter() was altered.')); + $this->assertEqual($object_copy, $object_expected, t('Second argument to drupal_alter() was altered.')); + $this->assertEqual($array2_copy, $array2_expected, t('Third argument to drupal_alter() was altered.')); + } +} + +/** * Tests for URL generation functions. */ class CommonURLUnitTest extends DrupalUnitTestCase { Index: modules/simpletest/tests/common_test.module =================================================================== RCS file: /cvs/drupal/drupal/modules/simpletest/tests/common_test.module,v retrieving revision 1.3 diff -u -p -r1.3 common_test.module --- modules/simpletest/tests/common_test.module 5 Sep 2009 13:05:30 -0000 1.3 +++ modules/simpletest/tests/common_test.module 4 Oct 2009 04:06:55 -0000 @@ -10,7 +10,6 @@ * Implement hook_menu(). */ function common_test_menu() { - $items = array(); $items['common-test/drupal_goto'] = array( 'title' => 'Drupal Goto', 'page callback' => 'common_test_drupal_goto_land', @@ -71,6 +70,37 @@ function common_test_drupal_goto_alter(& } /** + * Implement hook_TYPE_alter(). + */ +function common_test_drupal_alter_alter(&$data, &$arg2 = NULL, &$arg3 = NULL) { + // Alter first argument. + if (is_array($data)) { + $data['foo'] = 'Drupal'; + } + elseif (is_object($data)) { + $data->foo = 'Drupal'; + } + // Alter second argument, if present. + if (isset($arg2)) { + if (is_array($arg2)) { + $arg2['foo'] = 'Drupal'; + } + elseif (is_object($arg2)) { + $arg2->foo = 'Drupal'; + } + } + // Try to alter third argument, if present. + if (isset($arg3)) { + if (is_array($arg3)) { + $arg3['foo'] = 'Drupal'; + } + elseif (is_object($arg3)) { + $arg3->foo = 'Drupal'; + } + } +} + +/** * Implement hook_theme(). */ function common_test_theme() {