Composing Methods: Replace Temp With Query

Posted by Tim Koschützki, on Jun 14, 2007 - in Coding Techniques & Tools » Refactoring

When you are using a temporary variable to hold the result of an expression, extract the expression into a method. Then replace all references to the temp with the new method. The new method can then be used in other methods.

Motivation

The problem with temps is that they are temporary and local. Since they can be seen only in the context of the method they are in, temps tend to encourage longer methods, which is something we want to avoid. By replacing the temp with a query method you can easily ensure that all other methods of your PHP class can get the information that was previously held by the temporary variable.

Of course there are different forms of this. In one case the expression that generates the contents for the temp is free of side effects. You can simply copy that expression to the query method. Other cases are trickier.. for example if the temp is to collect a result, for example by summing over a loop, you need to copy some logic (the entire loop) into the query method. Sometimes a loop is to calculate multiple values. Here you need to duplicate the loop for each temp and then use "Replace Temp With Query" on each of them. As you can guess, there is a thin border to repetitive source code.

Mechanics

Here is a simple case:

  1. Look for a temporary variable that is assigned to once.
  2. Extract the right-hand side of the assignment into a method. Initially mark the method as private - you can easily relax the protection later.
  3. Ensure the extracted method is free of side-effects, meaning it does not modify any object.
  4. Run your tests.
  5. Use Inline Temp on the temporary variable.

Code Examples

Before

php
  1. function calcTax() {
  2.    $basePrice = $this->amount * $this->quantity;
  3.    if ($basePrice > 3000)
  4.        return $basePrice * 0.93;
  5.    else
  6.        return $basePrice * 0.95;
  7. }

After

php
  1. function calcTax() {
  2.    if ($this->basePrice() > 3000)
  3.        return $this->basePrice() * 0.93;
  4.    else
  5.        return $this->basePrice() * 0.95;
  6. }
  7.  
  8. function basePrice() {
  9.       return $this->amount * $this->quantity;
  10. }

As you see we perform the calculation of the base price several times here. You may be concerned with performance issues. However, be aware that nine times out of ten it will not matter. When it does matter, you will fix the problem during your optimisation stage. With your code being refactored you will often find even better optimisation strategies which you would have missed without refactoring, so the refactoring pays for itself already. If you are at the worst case, you can easily put the temp back, anyway.

Have a good one, folks! :)