Deprecated: preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /share/CACHEDEV1_DATA/Web/www/libraries/UBBcode/text_parser.class.php on line 228
Writing maintainable code in PHP

Comments Blog About Development Research Sites

Writing maintainable code in PHP

May 8, 2008
One of the greatest annoyances for any programmer is having to maintain (or more often fix) code written by a bad programmer. The trouble is that even badly written code can still work exactly as intended, and management seldom sees the difference between a good programmer and a bad one, at least untill they compare the time it takes both to fix a simple bug some time after they have written the original code.

I am one of the countless coders that have to live with it but perhaps by writing down what I found usefull there will be a few less bad programmers out there. A man can dream, can he not?

1. Abstract when you can.
Do not write huge functions that perform complex tasks. Instead write small functions that only perform one simple task. It is sometimes very tempting to add some functionality to a function and moreso to just jot in the code. Never do this. Instead, create new functions that perform the subtasks required. This is generally more work but in the end it's worth it.

As a rule of thumb my functions always fit on my screen, including comments. This means a maximum of ~50 lines for everything, and even that's stretching it. If a function does tend to get bigger it's almost always because it is trying to do several things at once, like load pictures and a description or log in a user and validate him, etc.

2. Not only write but also use Object Oriented Code
I often see people claiming to write OO code who then create one big class of several hundred(or thousand in one case) lines of code with a lot of functions refering back to eachother. What they effectively do is write functional code inside an object container, using object variables as a form of globals. What is worse, the code to decide what to do and to actually do it is often so mixed that figuring out what happens when is a complete nightmare.

It takes a great deal of experience to improve on this and the key once again lays in abstraction. Create small classes for objects that are controlled by other classes. Don't create a database class that loads it's own connection and has a few query functions. Instead create a database class that loads a databaseConnection object (a singleton for preference) and creates a new databaseQuery object for each query - which should return a databaseResult object after execution. As a rule of thumb your classes should never exceed ~150 lines of code including comments.

3. Document and document well.
Nobody likes writing comments, at least, no sane person does. Writing good comments is even more difficult since you actually have to think about your code. Yet it is the most basic and easy way to better your code and, eventually, yourself as a programmer.

First of all, don't bother documenting each line. Any programmer can see what a line of code does, writing it down helps nobody unless they're really complex, in which case you shouldn't comment them but simplify them. Focus on explaining what a function or class does, to such an extend that somebody who hasn't read the code but only the comments can, in theory, write the same function. This also means noting exceptions, list all parameters (and their type!) and all possible return values.

4. Beware of long argument lists and huge return arrays.
If your function takes more than two or three parameters you are most likely either writing functional code in a class container (see point 2) or creating functions that do too much at once (see point 1). Try to pass by reference or let methods work on class variables.

For example, don't call a function databaseConnect('username', 'password', host') but instead create a new databaseConnect object, assign a username, password and host to it (either by accessing it's public variables or, even better, creating public methods to set private variables) and then call a connect function. Who knows, perhaps later on you'll want to set additional parameters and you'll end up calling functions with half a dozen false / NULL arguments just to get to the one parameter you need. Moreso, somebody else will always have to go trough your code / documentation for the exact argument order which is both anoying and time consuming.

Likewise, a function should return either true or false if it only modifies or loads existing data. The only exception holds for interface classes that for instance can return the username corresponding to a given user ID or the result object from a database query, though those too should never return array's of different variables and their values. Keep it simple.

5. Don't submit unfinished code.
If your code already has to go trough inspection / QA before it's added to the main branche you don't have to worry about this. For everyone else, be sure to complete your code. Really complete it. This means no functions that dangle around on the side doing nothing, no undocumented members and especially no functionality you wrote but didn't test. And, most importantly, make sure that if you commit general functionality you do not change it's working. There is nothing more frustrating than seeing your code break because it relied on an external function that got changed somewhere between releases.

If you really must give your function extra functionality (which you generally shouldn't, see point 1) give it an optional argument or object parameter which, if unset, makes the function behave exactly as it did without. In PHP the easiest way to do this is by giving a parameter a default value, ie, function foo(bar = false) { }.

6. Use descriptive variable names.
Never ever use numerical pre- or postfixes in your variable names. Just now I had to debug code which had a $price1, $price2 and $prijs variable in one function (the last one being dutch for price) - and not surprisingly the problem lay in the mixing up of $price1 and $prijs. Likewise I have developed a twitch every time I see a $query1, $query3 and $query4_really_this_time_I_mean_it. Don't say what a variable is, say what it does. For instance, use $getUserQuery, $userId, $accommodationSubTypeId, etc.

On that same note, write out your variables. If you think my twitch on seeing $query3 is bad, check out my expression when I see one-char variable names like $x, $z, $c. They don't tell you anything and you will constantly have to refer back to their declaration to know what they do. This is not limited to PHP by the way - SQL queries are no different in this aspect that selecting 'table users as u' is a bad thing to do. Yes, it saves typing, but how long does it take you to type 5 characters (about 1 second for a decent programmer), compare that against the amount of time the next guy will spend looking for it's meaning each and every time he needs to verify it.

7. Whitespace is your friend.
Always remember to indent, always remember to tab right (and use spaces for tabs by preference so someone with a different editor doesn't get his layout all screwed up) and always do so consistently.

Moreover, don't be reluctant to allign in several columns, it greatly increases readability. Example:
Code (php) (nieuw venster):
private function getRequestString () {
  $header = (string) $this -> requestHeader;
  $body   = (string) $this -> requestBody;

Again, don't limit this to just PHP! No SQL query should ever be written on just one line, but more often than not I seep people trying it nonetheless. Write out your queries, let them span several lines, it really doesn't hurt.

In the end good programming is a matter of interest, experience and to some degree talent. A bad programmer won't suddenly become a good one by reading a few guides (though they could help). But if you do work on your bad points and always focus on getting better you're halfway there already.

FragFrog out!

Aug 26, 2008 karscie

Hear! Hear!
Except for the documentation part... thats just Utopia ;)

Aug 26, 2008 karscie

O... and don't use descriptive names for variables for simple things like loops ... that only makes the code less readable
(And for them don't use characters like l,I,0,o because they are easy to mix up with other chars)

New comment

Your name: