'regex',
'#value' => '[^\w_](TRUE|FALSE|NULL)[^\w_]',
'#case-sensitive' => true,
'#warning_callback' => '_coder_performance_case_variabletype_warning',
),
array(
'#type' => 'regex',
'#value' => '.*', // catch anything
'#not' => '\$',
'#source' => 'doublequote',
'#warning_callback' => '_coder_performance_double_quotes_warning',
),
array(
'#type' => 'regex',
'#value' => '\$\w+\+\+',
'#warning_callback' => '_coder_performance_increment_warning',
),
/* array( // I don't think this is true, I saw Rasmus explain this
'#type' => 'regex',
'#value' => 'for\s*\([^,]+;.+count',
'#warning_callback' => '_coder_performance_for_count_warning',
), */
array(
'#type' => 'regex',
'#value' => '\(strlen\(\$\w+\) <=? \d+\)',
'#warning_callback' => '_coder_performance_string_length_comparison_warning',
),
array(
'#type' => 'regex',
'#value' => '[^=] print',
'#warning_callback' => '_coder_performance_print_warning',
),
array(
'#type' => 'regex',
'#value' => 'in_array\(\'\', \$\w+\)',
'#warning_callback' => '_coder_performance_in_array_warning',
),
array(
'#type' => 'regex',
'#value' => '(\(|\|\||\&\&)\s*(count|sizeof)\(\$\w+\)',
'#warning_callback' => '_coder_performance_empty_warning',
),
);
$review = array(
'#title' => 'Performance Optimization',
'#link' => 'http://drupal.org/node/110128',
'#rules' => $rules,
'#severity' => 'minor',
'#description' => t('under development, use with discretion'),
);
return array('performance' => $review);
}
/**
* Define the warning callbacks
*/
function _coder_performance_case_variabletype_warning() {
return array(
'#warning' => t('true
is faster than TRUE
, also applies to FALSE
and NULL
'),
'#description' => t('This is because when looking for constants PHP does a hash lookup for the name as is. And since names are always stored lowercased, by using them you avoid 2 hash lookups.'),
);
}
function _coder_performance_double_quotes_warning() {
return array(
'#warning' => t('\'foo\'
is faster than "foo"
'),
'#description' => t('This is because a double quotes encapsulated string is parsed for variables and escaped characters. Always use single quotes, if not necessarily needed.'),
);
}
function _coder_performance_increment_warning() {
return array(
'#warning' => t('++ $i
is faster than $i ++
'),
'#description' => t('When incrementing or decrementing the value of the variable $i++
happens to be a tad slower than ++$i
. This is something PHP specific and does not apply to other languages, so don\'t go modifying your C or Java code thinking it\'ll suddenly become faster, it won\'t. ++$i
happens to be faster in PHP because instead of 4 opcodes used for $i++
you only need 3. Post incrementation actually causes in the creation of a temporary var that is then incremented. While pre-incrementation increases the original value directly. This is one of the optimization that opcode optimized like Zend\'s PHP optimizer. It is a still a good idea to keep in mind since not all opcode optimizers perform this optimization and there are plenty of ISPs and servers running without an opcode optimizer.'),
);
}
/*function _coder_performance_for_count_warning() {
return array(
'#warning' => t('for ($c = 0, $cc = count($foo); $c < $cc; ++$c)
is faster than for ($c = 0; $c < count($foo); ++$c)
'),
'#description' => t('In PHP a for
loop with a count()
inside the control block is executed on every loop iteration.'),
);
}*/
function _coder_performance_string_length_comparison_warning() {
return array(
'#warning' => t('if (!isset($foo{6}))
is faster than if (strlen($foo) < 5)
or if (strlen($foo) <= 6)
'),
'#description' => t('When working with strings and you need to check that the string is either of a certain length you\'d understandably would want to use the strlen()
function. This function is pretty quick since it\'s operation does not perform any calculation but merely return the already known length of a string available in the zval structure (internal C struct used to store variables in PHP). However because strlen()
is a function it is still somewhat slow because the function call requires several operations such as lowercase & hashtable lookup followed by the execution of said function. Calling isset()
happens to be faster than strlen()
because unlike strlen()
, isset()
is a language construct and not a function meaning that it\'s execution does not require function lookups and lowercase. This means you have virtually no overhead on top of the actual code that determines the string\'s length.'),
);
}
function _coder_performance_print_warning() {
return array(
'#warning' => t('echo
is faster than print
(if return value from print
is not used)'),
'#description' => t('Even both of these output mechanism are language constructs, if you benchmark the two you will quickly discover that print()
is slower than echo()
. The reason for that is quite simple, print
function will return a status indicating if it was successful or not, while echo
simply prints the text and nothing more. Since in most cases (haven\'t seen one yet) this status is not necessary and is almost never used it is pointless and simply adds unnecessary overhead.'),
);
}
function _coder_performance_in_array_warning() {
return array(
'#warning' => t('if (isset($array[\'foo\']))
is faster than if (in_array(\'foo\', $array))
'),
'#description' => t('Another common operation in PHP scripts is array searching. This process can be quite slow as regular search mechanism such as in_array()
or manual implementation work by iterating through the entire array. This can be quite a performance hit if you are searching through a large array or need to perform the searches frequently. So what can you do? Well, you can do a trick that relies upon the way that Zend Engine stores array data. Internally arrays are stored inside hash tables when their array element (key) is the key of the hashtables used to find the data and result is the value associated with that key. Since hashtable lookups are quite fast, you can simplify array searching by making the data you intend to search through the key of the array, then searching for the data is as simple as isset($foo[$bar]))
. This search mechanism is way faster than manual array iteration, even though having string keys maybe more memory intensive than using simple numeric keys.
Example:
$keys = array("apples", "oranges", "mangoes", "tomatoes", "pickles");
if (in_array(\'mangoes\', $keys)) { ... }
vs.
$keys = array("apples" => 1, "oranges" => 1, "mangoes" => 1, "tomatoes" => 1, "pickles" => 1);
if (isset($keys[\'mangoes\'])) { ... }
The bottom search mechanism is roughly 3 times faster.'),
);
}
function _coder_performance_empty_warning() {
return t('if (count($foo)
) and if (sizeof($foo)
) are much slower than if (!empty($foo)
)');
}