PHP Coding Standard
Last Modified: 2001-01-23
The PHP Coding Standard is with permission based on Todd Hoff's C++ Coding Standard.Rewritten for PHP by Fredrik Kristiansen / DB Medialab, Oslo 2000-2001.
Using this Standard.If you want to make a local copy of this standard and use it as yourown you are perfectly free to do so. That's why we made it! If you findany errors or make any improvements please email me the changes so I can merge them in. Recent Changes. |
Before you start please verify that you have the most recent document. [Download from original location] |
Contents
- Introduction
- Names
- Documentation
- Complexity Management
- Classes
- Process
- Formatting
- Server configuration
- Miscellaneous
Introduction
Standardization is Important
It helps if the standard annoys everyone in some way so everyonefeels they are on the same playing field. The proposal herehas evolved over many projects, many companies, and literallya total of many weeks spent arguing. It is no particular person's styleand is certainly open to local amendments.Good Points
When a project tries to adhere to common standards a fewgood things happen:- programmers can go into any code and figure out what's going on
- new people can get up to speed quickly
- people new to PHP are spared the need to develop a personal style and defend it to the death
- people new to PHP are spared making the same mistakes over and over again
- people make fewer mistakes in consistent environments
- programmers have a common enemy :-)
Bad Points
Now the bad:- the standard is usually stupid because it was made by someone who doesn't understand PHP
- the standard is usually stupid because it's not what I do
- standards reduce creativity
- standards are unnecessary as long as people are consistent
- standards enforce too much structure
- people ignore standards anyway
Discussion
The experience of many projects leads to the conclusion that usingcoding standards makes the project go smoother. Are standardsnecessary for success? Of course not. But they help, and we need all thehelp we can get! Be honest, most arguments against a particularstandard come from the ego. Few decisions in a reasonable standard reallycan be said to be technically deficient, just matters of taste.So be flexible, control the ego a bit, and remember any projectis fundamentally a team effort.Interpretation
Conventions
The use of the word "shall" in this document requires that any project usingthis document must comply with the stated standard.The use of the word "should" directs projects in tailoring a project-specificstandard, in that the project must include, exclude, or tailor the requirement,as appropriate.
The use of the word "may" is similar to "should", in that it designatesoptional requirements.
Standards Enforcement
First, any serious concerns about the standard should be broughtup and worked out within the group. Maybe the standard is notquite appropriate for your situation. It may have overlookedimportant issues or maybe someone in power vehementlydisagrees with certain issues :-)In any case, once finalized hopefully people will play the adult andunderstand that this standard is reasonable, and has been found reasonableby many other programmers, and therefore is worthy of being followedeven with personal reservations.
Failing willing cooperation it can be made a requirement thatthis standard must be followed to pass a code inspection.
Failing that the only solution is a massive tickling party on theoffending party.
Accepting an Idea
- It's impossible.
- Maybe it's possible, but it's weak and uninteresting.
- It is true and I told you so.
- I thought of it first.
- How could it be otherwise.
Names
Make Names Fit
Names are the heart of programming. In thepast people believed knowing someone's true name gave them magicalpower over that person. If you can think up the true name for something,you give yourself and the people coming after power over the code.Don't laugh!A name is the result of a long deep thought process aboutthe ecology it lives in. Only a programmer who understands the system as a wholecan create a name that "fits" with the system. If the name is appropriateeverything fits together naturally, relationships are clear, meaning is derivable,and reasoning from common human expectations works as expected.
If you find all your names could be Thing and DoIt then you should probablyrevisit your design.
Class Names
- Name the class after what it is. If you can't think of what it is that is a clue you have not thought through the design well enough.
- Compound names of over three words are a clue your design may be confusing various entities in your system. Revisit your design. Try a CRC card session to see if your objects have more responsibilities than they should.
- Avoid the temptation of bringing the name of the class a class derives from into the derived class's name. A class should stand on its own. It doesn't matter what it derives from.
- Suffixes are sometimes helpful. For example, if your system uses agents then naming something DownloadAgent conveys real information.
Method and Function Names
- Usually every method and function performs an action, so the name should make clear what it does: CheckForErrors() instead of ErrorCheck(), DumpDataToFile() instead of DataFile(). This will also make functions and data objects more distinguishable.
- Suffixes are sometimes useful:
- Max - to mean the maximum value something can have.
- Cnt - the current count of a running count variable.
- Key - key value.
For example: RetryMax to mean the maximum number of retries, RetryCnt to mean the current retry count.
- Prefixes are sometimes useful:
- Is - to ask a question about something. Whenever someone sees Is they will know it's a question.
- Get - get a value.
- Set - set a value.
For example: IsHitRetryLimit.
No All Upper Case Abbreviations
- When confronted with a situation where you could use an all upper case abbreviation instead use an initial upper case letter followed by all lower case letters. No matter what.
Do use: GetHtmlStatistic.
Do not use: GetHTMLStatistic.
Justification
- People seem to have very different intuitions when making names containing abbreviations. It's best to settle on one strategy so the names are absolutely predictable.
Take for example NetworkABCKey. Notice how the C from ABC and K from key are confused. Some people don't mind this and others just hate it so you'll find different policies in different code so you never know what to call something.
Example
class FluidOz // NOT FluidOZ
class GetHtmlStatistic // NOT GetHTMLStatistic
Class Names
- Use upper case letters as word separators, lower case for the rest of a word
- First character in a name is upper case
- No underbars ('_')
Justification
- Of all the different naming strategies many people found this one the best compromise.
Example
class NameOneTwo
class Name
Class Library Names
- Now that name spaces are becoming more widely implemented, name spaces should be used to prevent class name conflicts among libraries from different vendors and groups.
- When not using name spaces, it's common to prevent class name clashes by prefixing class names with a unique string. Two characters is sufficient, but a longer length is fine.
Example
John Johnson's complete data structure library could use JJas a prefix, so classes would be:class JjLinkList
{
}
Method Names
- Use the same rule as for class names.
Justification
- Of all the different naming strategies many people found this one the best compromise.
Example
class NameOneTwo
{
function DoIt() {};
function HandleError() {};
}
Class Attribute Names
- Class member attribute names should be prepended with the character 'm'.
- After the 'm' use the same rules as for class names.
- 'm' always precedes other name modifiers like 'r' for reference.
Justification
- Prepending 'm' prevents any conflict with method names. Often your methods and attribute names will be similar, especially for accessors.
Example
class NameOneTwo
{
function VarAbc() {};
function ErrorNumber() {};
var $mVarAbc;
var $mErrorNumber;
var $mrName;
}
Method Argument Names
- The first character should be lower case.
- All word beginnings after the first letter should be upper case as with class names.
Justification
- You can always tell which variables are passed in variables.
Example
class NameOneTwo
{
function StartYourEngines(&$someEngine, &$anotherEngine) {
$this->mSomeEngine = $someEngine;
$this->mAnotherEngine = $anotherEngine;
}
var $mSomeEngine;
var $mAnotherEngine;
}
Variable Names
- use all lower case letters
- use '_' as the word separator.
Justification
- With this approach the scope of the variable is clear in the code.
- Now all variables look different and are identifiable in the code.
Example
function HandleError($errorNumber)
{
$error = OsErr();
$time_of_error = $error->getTimeOfError();
$error_processor = $error->getErrorProcessor();
}
Reference Variables and Functions Returning References
- References should be prepended with 'r'.
Justification
- The difference between variable types is clarified.
- It establishes the difference between a method returning a modifiable object and the same method name returning a non-modifiable object.
Example
class Test
{
var $mrStatus;
function DoSomething(&$rStatus) {};
function &rStatus() {};
}
Global Variables
- Global variables should be prepended with a 'g'.
Justification
- It's important to know the scope of a variable.
Example
global $gLog;
global &$grLog;
Define Names / Global Constants
- Global constants should be all caps with '_' separators.
Justification
It's tradition for global constants to named this way. You must be careful tonot conflict with other predefined globals.Example
define("A_GLOBAL_CONSTANT", "Hello world!");
Static Variables
- Static variables may be prepended with 's'.
Justification
- It's important to know the scope of a variable.
Example
function test()
{
static $msStatus = 0;
}
Function Names
- For PHP functions use the C GNU convention of all lower case letters with '_' as the word delimiter.
Justification
- It makes functions very different from any class related names.
Example
function some_bloody_function()
{
}
Error Return Check Policy
- Check every system call for an error return, unless you know you wish to ignore errors.
- Include the system error text for every system error message.
Braces {} Policy
Of the three major brace placement strategies two are acceptable,with the first one listed being preferable:- Place brace under and inline with keywords:
if ($condition) while ($condition)
{ {
... ...
} }
- Traditional Unix policy of placing the initial brace on the same line as the keyword and the trailing brace inline on its own line with the keyword:
if ($condition) { while ($condition) {
... ...
} }
Justification
- Another religious issue of great debate solved by compromise. Either form is acceptable, many people, however, find the first form more pleasant. Why is the topic of many psychological studies.
There are more reasons than psychological for preferring the first style. If you use an editor (such as vi) that supports brace matching, the first is a much better style. Why? Let's say you have a large block of code and want to know where the block ends. You move to the first brace hit a key and the editor finds the matching brace. Example:
if ($very_long_condition && $second_very_long_condition)
To move from block to block you just need to use cursor down and your brace matching key. No need to move to the end of the line to match a brace then jerk back and forth.
{
...
}
else if (...)
{
...
}
Indentation/Tabs/Space Policy
- Indent using 3, 4 spaces for each level.
- Do not use tabs, use spaces. Most editors can substitute spaces for tabs.
- Indent as much as needed, but no more. There are no arbitrary rules as to the maximum indenting level. If the indenting level is more than 4 or 5 levels you may think about factoring out code.
Justification
- When people using different tab settings the code is impossible to read or print, which is why spaces are preferable to tabs.
- Nobody can ever agree on the correct number of spaces, just be consistent. In general people have found 3 or 4 spaces per indentation level workable.
- As much as people would like to limit the maximum indentation levels it never seems to work in general. We'll trust that programmers will choose wisely how deep to nest code.
Example
function func()
{
if (something bad)
{
if (another thing bad)
{
while (more input)
{
}
}
}
}
Parens () with Key Words and Functions Policy
- Do not put parens next to keywords. Put a space between.
- Do put parens next to function names.
- Do not use parens in return statements when it's not necessary.
Justification
- Keywords are not functions. By putting parens next to keywords keywords and function names are made to look alike.
Example
if (condition)
{
}
while (condition)
{
}
strcmp($s, $s1);
return 1;
Do Not do Real Work in Object Constructors
Do not do any real work in an object's constructor. Inside aconstructor initialize variables only and/or do onlyactions that can't fail.Create an Open() method for an object which completes construction.Open() should be called after object instantiation.
Justification
- Constructors can't return an error.
Example
class Device
{
function Device() { /* initialize and other stuff */ }
function Open() { return FAIL; }
};
$dev = new Device;
if (FAIL == $dev->Open()) exit(1);
Make Functions Reentrant
Functions should not keep static variables that prevent a function from beingreentrant.If Then Else Formatting
Layout
It's up to the programmer. Different bracing styles will yieldslightly different looks. One common approach is:if (condition) // CommentIf you have else if statements then it is usually a good ideato always have an else block for finding unhandled cases. Maybe put a logmessage in the else even if there is no corrective action taken.
{
}
else if (condition) // Comment
{
}
else // Comment
{
}
Condition Format
Always put the constant on the left hand side of an equality/inequalitycomparison. For example:if ( 6 == $errorNum ) ...
One reason is that if you leave out one of the = signs, the pharser will findthe error for you. A second reason is that it puts the value you are looking forright up front where you can find it instead of buried at the end of your expression.It takes a little time to get used to this format, but then it really gets useful.
switch Formatting
- Falling through a case statement into the next case statement shall be permitted as long as a comment is included.
- The default case should always be present and trigger an error if it should not be reached, yet is reached.
- If you need to create variables put all the code in a block.
Example
switch (...)
{
case 1:
...
// FALL THROUGH
case 2:
{
$v = get_week_number();
...
}
break;
default:
}
Use of continue,break and ?:
Continue and Break
Continue and break are really disguised gotos so they are coveredhere.Continue and break like goto should be used sparingly as they are magic incode. With a simple spell the reader is beamed to god knows where forsome usually undocumented reason.
The two main problems with continue are:
- It may bypass the test condition
- It may bypass the increment/decrement expression
Consider the following example where both problems occur:
while (TRUE)Note: "A lot of code" is necessary in order that the problem cannot becaught easily by the programmer.
{
...
// A lot of code
...
if (/* some condition */) {
continue;
}
...
// A lot of code
...
if ( $i++ > STOP_VALUE) break;
}
From the above example, a further rule may be given:Mixing continue with break in the same loop is a sure way to disaster.
?:
The trouble is people usually try and stuff too much codein between the ? and :. Here are a couple ofclarity rules to follow:- Put the condition in parens so as to set it off from other code
- If possible, the actions for the test should be simple functions.
- Put the action for the then and else statement on a separate line unless it can be clearly put on one line.
Example
(condition) ? funct1() : func2();
or
(condition)
? long statement
: another long statement;
Alignment of Declaration Blocks
- Block of declarations should be aligned.
Justification
- Clarity.
- Similarly blocks of initialization of variables should be tabulated.
- The ‘&’ token should be adjacent to the type, not the name.
Example
var $mDate
var& $mrDate
var& $mrName
var $mName
$mDate = 0;
$mrDate = NULL;
$mrName = 0;
$mName = NULL;
One Statement Per Line
There should be only one statement per line unless the statementsare very closely related.Short Methods
- Methods should limit themselves to a single page of code.
Justification
- The idea is that the each method represents a technique forachieving a single objective.
- Most arguments of inefficiency turn out to be false in the long run.
- True function calls are slower than not, but there needs to athought out decision (see premature optimization).
Document Null Statements
Always document a null body for a for or while statement so that it is clearthat the null body is intentional and not missing code.
while ($dest++ = $src++)
; // VOID
Do Not Default If Test to Non-Zero
Do not default the test for non-zero, i.e.is better than
if (FAIL != f())
even though FAIL may have the value 0 which PHP considers to be false. An explicittest will help you out later when somebody decides that a failure return shouldbe -1 instead of 0. Explicit comparison should be used even if the comparisonvalue will never change; e.g., if (!($bufsize % strlen($str))) should bewritten instead as if (0 == ($bufsize % strlen($str))) to reflect the numeric(not boolean) nature of the test. A frequent trouble spot is using strcmp to testfor string equality, where the result should never ever bedefaulted.
if (f())
The non-zero test is often defaulted for predicates and other functions orexpressions which meet the following restrictions:
- Returns 0 for false, nothing else.
- Is named so that the meaning of (say) a true return is absolutely obvious. Call a predicate IsValid(), not CheckValid().
The Bull of Boolean Types
Do not check a boolean value for equality with 1(TRUE, YES, etc.); instead test for inequality with 0 (FALSE, NO, etc.). Mostfunctions are guaranteed to return 0 if false, but only non-zero if true. Thus,
must be written
if (TRUE == func()) { ...
if (FALSE != func()) { ...
Usually Avoid Embedded Assignments
There is a time and a place for embedded assignment statements. In someconstructs there is no better way to accomplish the results without making thecode bulkier and less readable.
while ($a != ($c = getchar()))
{
process the character
}
The ++ and -- operators count as assignment statements. So, for many purposes,do functions with side effects. Using embedded assignment statements toimprove run-time performance is also possible. However, one should considerthe tradeoff between increased speed and decreased maintainability that resultswhen embedded assignments are used in artificial places. For example,
should not be replaced by
$a = $b + $c;
$d = $a + $r;
even though the latter may save one cycle. In the long run the time differencebetween the two will decrease as the optimizer gains maturity, while thedifference in ease of maintenance will increase as the human memory of what'sgoing on in the latter piece of code begins to fade.
$d = ($a = $b + $c) + $r;
Reusing Your Hard Work and the Hard Work of Others
Reuse across projects is almost impossible withouta common framework in place. Objects conform to theservices available to them. Different projectshave different service environments making object reusedifficult.Developing a common framework takes a lot of up frontdesign effort. When this effort is not made, forwhatever reasons, there are several techniquesone can use to encourage reuse:
Don't be Afraid of Small Libraries
One common enemy of reuse is people not makinglibraries out of their code. A reusable class may behiding in a program directory and will never havethe thrill of being shared because the programmerwon't factor the class or classes into a library.One reason for this is because people don't like making smalllibraries. There's something about small libraries thatdoesn't feel right. Get over it. The computer doesn't carehow many libraries you have.
If you have code that can be reused and can't be placed in anexisting library then make a new library. Libraries don't staysmall for long if people are really thinking about reuse.
If you are afraid of having to update makefiles when librariesare recomposed or added then don't include libraries in yourmakefiles, include the idea of services. Base level makefilesdefine services that are each composed of a set of libraries.Higher level makefiles specify the services they want. When thelibraries for a service change only the lower level makefiles willhave to change.
Keep a Repository
Most companies have no idea what code they have. And mostprogrammers still don't communicate what they have done orask for what currently exists. The solution is to keepa repository of what's available.In an ideal world a programmer could go to a web page, browseor search a list of packaged libraries, taking what theyneed. If you can set up such a system where programmersvoluntarily maintain such a system, great. If you have alibrarian in charge of detecting reusability, even better.
Another approach is to automatically generate a repositoryfrom the source code. This is done by using commonclass, method, library, and subsystem headers that can double as manpages and repository entries.
Comments on Comments
Comments Should Tell a Story
Consider your comments a story describing the system. Expectyour comments to be extracted by a robot and formed intoa man page. Class comments are one part of the story,method signature comments are another part of the story,method arguments another part, and method implementationyet another part. All these parts should weave togetherand inform someone else at another point of time justexactly what you did and why.Document Decisions
Comments should document decisions. At every pointwhere you had a choice of what to do place a commentdescribing which choice you made and why. Archeologistswill find this the most useful information.Use Headers
Use a document extraction system like ccdoc .Other sections in this document describe how to use ccdocto document a class and method.These headers are structured in such a way as theycan be parsed and extracted. They are not uselesslike normal headers. So take time to fill them out.If you do it right once no more documentation may benecessary.
Comment Layout
Each part of the project has a specific comment layout.Make Gotchas Explicit
Explicitly comment variables changed out of the normal controlflow or other code likely to break during maintenance. Embeddedkeywords are used to point out issues and potential problems. Consider a robotwill parse your comments looking for keywords, stripping them out, and makinga report so people can make a special effort where needed.Gotcha Keywords
- :TODO: topic
Means there's more to do here, don't forget. - :BUG: [bugid] topic
means there's a Known bug here, explain it and optionally give a bug ID. - :KLUDGE:
When you've done something ugly say so and explain how you would do it differently next time if you had more time. - :TRICKY:
Tells somebody that the following code is very tricky so don't go changing it without thinking. - :WARNING:
Beware of something. - :PHARSER:
Sometimes you need to work around a pharser problem. Document it. The problemmay go away eventually. - :ATTRIBUTE: value
The general form of an attribute embedded in a comment. You can make up your own attributes and they'll be extracted.
Gotcha Formatting
- Make the gotcha keyword the first symbol in the comment.
- Comments may consist of multiple lines, but the first line should be a self-containing, meaningful summary.
- The writer's name and the date of the remark should be part of the comment. This information is in the source repository, but it can take a quite a while to find out when and by whom it was added. Often gotchas stick around longer than they should. Embedding date information allows other programmer to make this decision. Embedding who information lets us know who to ask.
Example
// :TODO: tmh 960810: possible performance problem
// We should really use a hash table here but for now we'll
// use a linear search.
// :KLUDGE: tmh 960810: possible unsafe type cast
// We need a cast here to recover the derived type. It should
// probably use a virtual method or template.
See Also
See Interface and Implementation Documentation for more details on how documentation should be laid out.Interface and Implementation Documentation
There are two main audiences for documentation:- Class Users
- Class Implementors
Class Users
Class users need class interface information which when structuredcorrectly can be extracted directly from a header file. Whenfilling out the header comment blocks for a class, onlyinclude information needed by programmers who use the class.Don't delve into algorithm implementation details unless thedetails are needed by a user of the class. Consider commentsin a header file a man page in waiting.Class Implementors
Class implementors require in-depth knowledge of how a classis implemented. This comment type is found inthe source file(s) implementing a class. Don't worry aboutinterface issues. Header comment blocks in a source file shouldcover algorithm issues and other design decisions. Comment blockswithin a method's implementation should explain even more.Directory Documentation
Every directory should have a README file that covers:- the purpose of the directory and what it contains
- a one line comment on each file. A comment can usually be extracted from the NAME attribute of the file header.
- cover build and install directions
- direct people to related resources:
- directories of source
- online documentation
- paper documentation
- design documentation
- anything else that might help someone
Open/Closed Principle
The Open/Closed principle states a class must be open andclosed where:- open means a class has the ability to be extended.
- closed means a class is closed for modifications other than extension. The idea is once a class has been approved for use having gone through code reviews, unit tests, and other qualifying procedures, you don't want to change the class very much, just extend it.
In practice the Open/Closed principle simply means making good use of ourold friends abstraction and polymorphism. Abstraction to factor out common processesand ideas. Inheritance to create an interface that must be adhered to by derivedclasses.
Server configuration
This section contains some guidelines for PHP/Apache configuration.HTTP_*_VARS
HTTP_*_VARS are either enabled or disabled. When enabled all variables must be accessed throught$HTTP_*_VARS[key]. When disabled all variables can be accessed by the key name.- use HTTP_*_VARS when accessing variables.
- use enabled HTTP_*_VARS in PHP configuration.
Justification
- HTTP_*_VARS is available in any configuration.
- HTTP_*_VARS will not conflict with exsisting variables.
- Users can't change variables by passing values.
PHP File Extensions
There is lots of different extension variants on PHP files (.html, .php, .php3, .php4,.phtml, .inc, .class...).- Use extension .html or .php.
- Always use the extension .php for your class and function libraries.
- Enable .html and .php files to be pharsed by PHP in your webserver configuration.
Justification
- The extension describes what data the user will recive. Pharsed PHP becomes HTML. (Example: If you made a software who encoded mp3 files, you wouldn't use the extension .mysoft for the encoded files)
- The use of .inc or .class can be a security problem. On most servers these extensions aren't set to be run by a pharser. If these are accessed they will be displayed in clear text.
Miscellaneous
This section contains some miscellaneous do's and don'ts.- Don't use floating-point variables where discrete values are needed. Usinga float for a loop counter is a great way to shoot yourself in the foot. Alwaystest floating-point numbers as <= or >=, never use an exact comparison (==or !=).
- Do not rely on automatic beautifiers. The main person who benefits from goodprogram style is the programmer him/herself, and especially in the early designof handwritten algorithms or pseudo-code. Automatic beautifiers can only be appliedto complete, syntactically correct programs and hence are not available when theneed for attention to white space and indentation is greatest. Programmers cando a better job of making clear the complete visual layout of a function or file,with the normal attention to detail of a careful programmer (in other words, someof the visual layout is dictated by intent rather than syntax and beautifierscannot read minds). Sloppy programmers should learn to be careful programmersinstead of relying on a beautifier to make their code readable. Finally, sincebeautifiers are non-trivial programs that must parse the source, a sophisticatedbeautifier is not worth the benefits gained by such a program. Beautifiers arebest for gross formatting of machine-generated code.
- Accidental omission of the second ``='' of the logical compare is a problem.The following is confusing and prone to error.
if ($abool= $bbool) { ... }Does the programmer really mean assignment here? Often yes, but usually no. Thesolution is to just not do it, an inverse Nike philosophy. Instead use explicittests and avoid assignment with an implicit test. The recommended form is to dothe assignment before doing the test:
$abool= $bbool;
if ($abool) { ... }
Use if (0) to Comment Out Code Blocks
Sometimes large blocks of code need to be commented out for testing. The easiestway to do this is with an if (0) block:function example()
{
great looking code
if (0) {
lots of code
}
more code
}
You can't use /**/ style comments because comments can't contain commentsand surely a large block of your code will contain a comment, won't it?
Different Accessor Styles
Implementing Accessors
There are two major idioms for creating accessors.Get/Set
class XGet/Set is ugly. Get and Set are strewn throughout the codecluttering it up.
{
function GetAge() { return $this->mAge; }
function SetAge($age) { $this->mAge = $age; }
var $mAge;
};
But one benefit is when used with messages the set method cantransparently transform from native machine representations tonetwork byte order.
Attributes as Objects
class XAttributes as Objects is clean from a name perspective. Whenpossible use this approach to attribute access.
{
function Age() { return $this->mAge; }
function Name() { return $this->mName; }
var $mAge;
var $mName;
}
$x = new X;
// Example 1
$age = $x->Age();
$r_age = &$x->Age(); // Reference
// Example 2
$name = $x->Name();
$r_name = &$x->Name(); // Reference
Layering
Layering is the primary technique for reducing complexity ina system. A system should be divided into layers. Layersshould communicate between adjacent layers using well definedinterfaces. When a layer uses a non-adjacent layer then alayering violation has occurred.A layering violation simply means we have dependency betweenlayers that is not controlled by a well defined interface.When one of the layers changes code could break. We don'twant code to break so we want layers to work only withother adjacent layers.
Sometimes we need to jump layers for performance reasons.This is fine, but we should know we are doing it and documentappropriately.
Code Reviews
If you can make a formal code review work then my hat is offto you. Code reviews can be very useful. Unfortunately theyoften degrade into nit picking sessions and endless argumentsabout silly things. They also tend to take a lot of people'stime for a questionable payback.My god he's questioning code reviews, he's not an engineer!
Not really, it's the form of code reviews and how they fit intonormally late chaotic projects is what is being questioned.
First, code reviews are way too late to do much ofanything useful. What needs reviewing are requirements anddesign. This is where you will get more bang for the buck.
Get all relevant people in a room. Lock them in. Go over the class designand requirements until the former is good and the latter is being met.Having all the relevant people in the room makes this processa deep fruitful one as questions can be immediately answered andissues immediately explored. Usually only a couple of such meetingsare necessary.
If the above process is done well coding will takecare of itself. If you find problems in the codereview the best you can usually do is a rewrite after someone has sunka ton of time and effort into making the code "work."
You will still want to do a code review, just do it offline. Have acouple people you trust read the code in question and simply makecomments to the programmer. Then the programmer and reviewerscan discuss issues and work them out. Email and quick pointeddiscussions work well. This approach meets the goalsand doesn't take the time of 6 people to do it.
Create a Source Code Control System Early and Not Often
A common build system and source code control system should be put in placeas early as possible in a project's lifecycle, preferably before anyone startscoding. Source code control is the structural glue binding a project together.If programmers can't easily use each other's products then you'll never beable to make a good reproducible build and people will piss away a lot of time.It's also hell converting rogue build environments to a standard system.But it seems the right of passage for every project to build their own customenvironment that never quite works right.Some issues to keep in mind:
- Shared source environments like CVS usually work best in largish projects.
- If you use CVS use a reference tree approach. With this approach amaster build tree is kept of various builds. Programmers checkout source againstthe build they are working on. They only checkout what they need because the makesystem uses the build for anything not found locally. Using the -I and -Lflags makes this system easy to setup. Search locally for any files and librariesthen search in the reference build. This approach saves on disk space and buildtime.
- Get a lot of disk space. With disk space as cheap it is there is no reasonnot to keep plenty of builds around.
- Make simple things simple. It should be dead simple and well documented onhow to:
- check out modules to build
- how to change files
- how to add new modules into the system
- how to delete modules and files
- how to check in changes
- what are the available libraries and include files
- how to get the build environment including all compilers and other tools
Make a web page or document or whatever. New programmers shouldn't have togo around begging for build secrets from the old timers.
- On checkins log comments should be useful. These comments should be collectedevery night and sent to interested parties.
Sources
If you have the money many projects have found Clear Case a good system. Perfectly workable systems have been build on topof GNU make and CVS. CVS is a freeware build environment built on top of RCS.Its main difference from RCS is that is supports a shared file model to buildingsoftware.Create a Bug Tracking System Early and Not Often
The earlier people get used to using a bug tracking system the better. If youare 3/4 through a project and then install a bug tracking system it won'tbe used. You need to install a bug tracking system early so people will use it.Programmers generally resist bug tracking, yet when used correctly itcan really help a project:
- Problems aren't dropped on the floor.
- Problems are automatically routed to responsible individuals.
- The lifecycle of a problem is tracked so people can argue back and forth with good information.
- Managers can make the big schedule and staffing decisions based on the number of and types of bugs in the system.
- Configuration management has a hope of matching patches back to the problems they fix.
- QA and technical support have a communication medium with developers.
Source code control should be linked to the bug tracking system. During the partof a project where source is frozen before a release only checkins accompaniedby a valid bug ID should be accepted. And when code is changed to fix a bugthe bug ID should be included in the checkin comments.
Sources
I recommend Mantis for bug tracking. It is released under thegeneral public license.Honor Responsibilities
Responsibility for software modules is scoped. Modules are either the responsibility of aparticular person or are common. Honor this division of responsibility. Don'tgo changing things that aren't your responsibility to change. Only mistakesand hard feelings will result.Face it, if you don't own a piece of code you can't possibly be in a position tochange it. There's too much context. Assumptions seemingly reasonable to youmay be totally wrong. If you need a change simply ask the responsible personto change it. Or ask them if it is OK to make such-n-such a change. If they say OKthen go ahead, otherwise holster your editor.
Every rule has exceptions. If it's 3 in the morning and you need to make a changeto make a deliverable then you have to do it. If someone is on vacation and no onehas been assigned their module then you have to do it. If you make changes in otherpeople's code try and use the same style they have adopted.
Programmers need to mark with comments code that is particularly sensitive tochange. If code in one area requires changes to code in an another area thensay so. If changing data formats will cause conflicts with persistent storesor remote message sending then say so. If you are trying to minimize memoryusage or achieve some other end then say so. Not everyone is as brilliant as you.
The worst sin is to flit through the system changing bits of code to match yourcoding style. If someone isn't coding to the standards then ask them or askyour manager to ask them to code to the standards. Use common courtesy.
Code with common responsibility should be treated with care. Resist making radicalchanges as the conflicts will be hard to resolve. Put comments in the file on howthe file should be extended so everyone will follow the same rules. Try and usea common structure in all common files so people don't have to guess on whereto find things and how to make changes. Checkin changes as soon as possible soconflicts don't build up.
As an aside, module responsibilities must also be assigned for bug tracking purposes.
PHP Code Tags
PHP Tags are used for delimit PHP from html in a file. There are servalways to do this.<?php ?>, <? ?>, <script language="php"></script>, <% %>, and <?=$name?>. Some of these maybe turnedoff in your PHP settings.- Use <?php ?>
Justification
- <?php ?> is always avaliable in any system and setup.
Example
<?php print "Hello world"; ?> // Will print "Hello world"
<? print "Hello world"; ?> // Will print "Hello world"
<script language="php"> print "Hello world"; </script> // Will print "Hello world"
<% print "Hello world"; %> // Will print "Hello world"
<?=$street?> // Will print the value of the variable $street
No Magic Numbers
A magic number is a bare naked number used in source code. It's magicbecause no-one has a clue what it means including the author inside3 months. For example:if (22 == $foo) { start_thermo_nuclear_war(); }
else if (19 == $foo) { refund_lotso_money(); }
else if (16 == $foo) { infinite_loop(); }
else { cry_cause_im_lost(); }
In the above example what do 22 and 19 mean? If there was a number change or thenumbers were just plain wrong how would you know? Heavy use of magic numbers marks a programmer as an amateurmore than anything else. Such a programmer has never worked in a teamenvironment or has had to maintain code or they would never do sucha thing.
Instead of magic numbers use a real name that means something. You shoulduse define(). For example:
define("PRESIDENT_WENT_CRAZY", "22");
define("WE_GOOFED", "19");
define("THEY_DIDNT_PAY", "16");
if (PRESIDENT_WENT_CRAZY == $foo) { start_thermo_nuclear_war(); }
else if (WE_GOOFED == $foo) { refund_lotso_money(); }
else if (THEY_DIDNT_PAY == $foo) { infinite_loop(); }
else { happy_days_i_know_why_im_here(); }
Now isn't that better? Thin vs. Fat Class Interfaces
How many methods should an object have? The right answer of course is just the right amount, we'll callthis the Goldilocks level. But what is the Goldilocks level? It doesn'texist. You need to make the right judgment for your situation, which is reallywhat programmers are for :-)The two extremes are thin classes versus thick classes. Thinclasses are minimalist classes. Thin classes have as few methods as possible.The expectation is users will derive their own class from the thin class addingany needed methods.
While thin classes may seem "clean" they really aren't. You can't do much witha thin class. Its main purpose is setting up a type. Since thin classes have solittle functionality many programmers in a project will create derived classeswith everyone adding basically the same methods. This leads to code duplicationand maintenance problems which is part of the reason we use objectsin the first place. The obvious solution is to push methods up to the base class.Push enough methods up to the base class and you get thick classes.
Thick classes have a lot of methods. If you can think of it a thick classwill have it. Why is this a problem? It may not be. If the methods are directlyrelated to the class then there's no real problem with the class containingthem. The problem is people get lazy and start adding methods to a class thatare related to the class in some willow wispy way, but would be better factoredout into another class. Judgment comes into play again.
Thick classes have other problems. As classes get larger they may become harderto understand. They also become harder to debug as interactions become less predictable.And when a method is changed that you don't use or care about your code will stillhave to be retested, and rereleased.
Recent Changes
- 2001-05-04. Replaced the recommended bug tracking system with a new gpl bug tracking system named Mantis.
- 2001-01-23. Method Argument Names example code fix. Parts of Different Accessor Styles has been deprecated because there was no support in PHP for these.
- 2000-12-12. HTTP_*_VARS added
- 2000-12-11. Indentation/Tabs/Space Policy has been changed
PHP Code Tags added - 2000-12-05. Method Argument Names has been updated
- 2000-11-16. Release
? Copyright 1995-2001. Todd Hoff and Fredrik Kristiansen. All rights reserved.

