debuggable

 
Contact Us
 

Composing Methods: Replace Temp With Query

Posted on 14/6/07 by Tim Koschützki

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

function calcTax() {
   $basePrice = $this->amount * $this->quantity;
   if ($basePrice > 3000)
       return $basePrice * 0.93;
   else
       return $basePrice * 0.95;
}

After

function calcTax() {
   if ($this->basePrice() > 3000)
       return $this->basePrice() * 0.93;
   else
       return $this->basePrice() * 0.95;
}

function basePrice() {
      return $this->amount * $this->quantity;
}

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! :)

 
&nsbp;

You can skip to the end and add a comment.

[...] a new article from PHP-Coding-Practices.com today, Tim Koschuetzki offers a different sort of solution for [...]

Peter Goodman said on Jun 18, 2007:

I'm on the fence about this piece of advice. At first, I think, what's wrong with temps being local? They get cleaned up when the function goes out of scope, so all is fine. Then I think, why not try to reduce function calls? Essentially, your replacement method is just added an unneeded layer of abstraction.

I think your way could be useful where the targeted getter function is used in more than one place, otherwise it's just overhead. Consider that your getter function doesn't cache its result, so that each time its called the calculation is performed. When compared to the temp variable, which is an implicit caching of the result, I see the temp variable as being more efficient.

I would like to see some benchmarks on this method using something like xdebug where your temp variable/getter function performs a more significant math operation, and then iterate te process a few thousand times to get a visible number.

Otherwise, the getter function you have made is redundant. Making functions where you have made one would only be worthy of existance if you passed a variable to it, where you were using a standardized calculation, but needed to change >= 1 of the variables in it.

This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.