Commit b1434988 authored by webchick's avatar webchick

#619666 by effulgentsia, casey, and catch: Changed Introduce new pattern for...

#619666 by effulgentsia, casey, and catch: Changed Introduce new pattern for drupal_static() in performance-critical functions.
parent 56e35716
......@@ -2086,6 +2086,83 @@ function registry_rebuild() {
/**
* Central static variable storage.
*
* All functions requiring a static variable to persist or cache data within
* a single page request are encouraged to use this function unless it is
* absolutely certain that the static variable will not need to be reset during
* the page request. By centralizing static variable storage through this
* function, other functions can rely on a consistent API for resetting any
* other function's static variables.
*
* Example:
* @code
* function language_list($field = 'language') {
* $languages = &drupal_static(__FUNCTION__);
* if (!isset($languages)) {
* // If this function is being called for the first time after a reset,
* // query the database and execute any other code needed to retrieve
* // information about the supported languages.
* ...
* }
* if (!isset($languages[$field])) {
* // If this function is being called for the first time for a particular
* // index field, then execute code needed to index the information already
* // available in $languages by the desired field.
* ...
* }
* // Subsequent invocations of this function for a particular index field
* // skip the above two code blocks and quickly return the already indexed
* // information.
* return $languages[$field];
* }
* function locale_translate_overview_screen() {
* // When building the content for the translations overview page, make
* // sure to get completely fresh information about the supported languages.
* drupal_static_reset('language_list');
* ...
* }
* @endcode
*
* In a few cases, a function can have certainty that there is no legitimate
* use-case for resetting that function's static variable. This is rare,
* because when writing a function, it's hard to forecast all the situations in
* which it will be used. A guideline is that if a function's static variable
* does not depend on any information outside of the function that might change
* during a single page request, then it's ok to use the "static" keyword
* instead of the drupal_static() function.
*
* Example:
* @code
* function actions_do(...) {
* // $stack tracks the number of recursive calls.
* static $stack;
* $stack++;
* if ($stack > variable_get('actions_max_stack', 35)) {
* ...
* return;
* }
* ...
* $stack--;
* }
* @endcode
*
* In a few cases, a function needs a resettable static variable, but the
* function is called many times (100+) during a single page request, so
* every microsecond of execution time that can be removed from the function
* counts. These functions can use a more cumbersome, but faster variant of
* calling drupal_static(). For benchmarks and background on this variant,
* please see http://drupal.org/node/619666.
*
* Example:
* @code
* function user_access($string, $account = NULL) {
* // Use the advanced drupal_static() pattern, since this is called very often.
* static $drupal_static = array();
* isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
* $perm = &$drupal_static[__FUNCTION__];
* ...
* }
* @endcode
*
* @param $name
* Globally unique name for the variable. For a function with only one static,
* variable, the function name (e.g. via the PHP magic __FUNCTION__ constant)
......@@ -2102,6 +2179,8 @@ function registry_rebuild() {
*
* @return
* Returns a variable by reference.
*
* @see drupal_static_reset()
*/
function &drupal_static($name, $default_value = NULL, $reset = FALSE) {
static $data = array(), $default = array();
......
......@@ -2275,7 +2275,11 @@ function format_interval($timestamp, $granularity = 2, $langcode = NULL) {
* A translated date string in the requested format.
*/
function format_date($timestamp, $type = 'medium', $format = '', $timezone = NULL, $langcode = NULL) {
$timezones = &drupal_static(__FUNCTION__, array());
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$timezones = &$drupal_static[__FUNCTION__];
if (!isset($timezone)) {
global $user;
if (variable_get('configurable_timezones', 1) && $user->uid && $user->timezone) {
......@@ -2512,7 +2516,10 @@ function url($path = NULL, array $options = array()) {
}
global $base_url, $base_secure_url, $base_insecure_url;
$script = &drupal_static(__FUNCTION__);
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$script = &$drupal_static[__FUNCTION__];
if (!isset($script)) {
// On some web servers, such as IIS, we can't omit "index.php". So, we
......@@ -4728,7 +4735,10 @@ function drupal_system_listing($mask, $directory, $key = 'name', $min_depth = 1)
* keyed array as described above.
*/
function drupal_alter($type, &$data, &$context1 = NULL, &$context2 = NULL) {
$functions = &drupal_static(__FUNCTION__, array());
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$functions = &$drupal_static[__FUNCTION__];
// Some alter hooks are invoked many times per page request, so statically
// cache the list of functions to call, and on subsequent calls, iterate
......@@ -6214,8 +6224,10 @@ function drupal_check_incompatibility($v, $current_version) {
* to return an array with info about all types.
*/
function entity_get_info($entity_type = NULL) {
// We statically cache the information returned by hook_entity_info().
$entity_info = &drupal_static(__FUNCTION__, array());
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$entity_info = &$drupal_static[__FUNCTION__];
if (empty($entity_info)) {
if ($cache = cache_get('entity_info')) {
......
......@@ -438,7 +438,10 @@ function module_hook($module, $hook) {
* @see module_implements_write_cache().
*/
function module_implements($hook, $sort = FALSE, $reset = FALSE) {
$implementations = &drupal_static(__FUNCTION__, array());
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$implementations = &$drupal_static[__FUNCTION__];
// We maintain a persistent cache of hook implementations in addition to the
// static cache to avoid looping through every module and every hook on each
......
......@@ -45,14 +45,21 @@ function drupal_path_initialize() {
*/
function drupal_lookup_path($action, $path = '', $path_language = '') {
global $language;
$cache = &drupal_static(__FUNCTION__, array(
'map' => array(),
'no_source' => array(),
'whitelist' => NULL,
'system_paths' => array(),
'no_aliases' => array(),
'first_call' => TRUE,
));
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$cache = &$drupal_static[__FUNCTION__];
if (!isset($cache)) {
$cache = array(
'map' => array(),
'no_source' => array(),
'whitelist' => NULL,
'system_paths' => array(),
'no_aliases' => array(),
'first_call' => TRUE,
);
}
// Retrieve the path alias whitelist.
if (!isset($cache['whitelist'])) {
......@@ -245,7 +252,14 @@ function drupal_get_normal_path($path, $path_language = '') {
* not found.
*/
function arg($index = NULL, $path = NULL) {
$arguments = &drupal_static(__FUNCTION__);
// Even though $arguments doesn't need to be resettable for any functional
// reasons (the result of explode() does not depend on any run-time
// information), it should be resettable anyway in case a module needs to
// free up the memory used by it.
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$arguments = &$drupal_static[__FUNCTION__];
if (!isset($path)) {
$path = $_GET['q'];
......@@ -310,7 +324,10 @@ function drupal_set_title($title = NULL, $output = CHECK_PLAIN) {
* Boolean value: TRUE if the current page is the front page; FALSE if otherwise.
*/
function drupal_is_front_page() {
$is_front_page = &drupal_static(__FUNCTION__);
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$is_front_page = &$drupal_static[__FUNCTION__];
if (!isset($is_front_page)) {
// As drupal_path_initialize updates $_GET['q'] with the 'site_frontpage' path,
......
......@@ -679,7 +679,10 @@ function user_role_permissions($roles = array()) {
*/
function user_access($string, $account = NULL) {
global $user;
$perm = &drupal_static(__FUNCTION__, array());
// Use the advanced drupal_static() pattern, since this is called very often.
static $drupal_static = array();
isset($drupal_static[__FUNCTION__]) || ($drupal_static[__FUNCTION__] = &drupal_static(__FUNCTION__));
$perm = &$drupal_static[__FUNCTION__];
if (!isset($account)) {
$account = $user;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment