PHPAppl Coding Standard

Last Modified: 2001-10-12

The PHPAppl Coding Standard is with permission based on PHP Coding Standard from Todd Hoff and Fredrik Kristiansen

Contents


Names

Make Names Fit

Names are the heart of programming. In the past people believed knowing someone's true name gave them magical power 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 about the ecology it lives in. Only a programmer who understands the system as a whole can create a name that "fits" with the system. If the name is appropriate everything 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 probably revisit your design.

Class Names

Method and Function Names

No All Upper Case Abbreviations

Justification

Example

   class FluidOz             // NOT FluidOZ
   class GetHtmlStatistic       // NOT GetHTMLStatistic


Class Names

Justification

Example

   class NameOneTwo

   class Name


Class Library Names

Example

John Johnson's complete data structure library could use JJ as a prefix, so classes would be:
   class JjLinkList
   {
   }


Method Names

Justification

Example

   class NameOneTwo
   {
      function DoIt() {};
      function HandleError() {};
   }


Class Attribute Names

Justification

Example

   class NameOneTwo
   {
      function VarAbc() {};
      function ErrorNumber() {};
      var $mVarAbc;
      var $mErrorNumber;
      var $mrName;
   }


Method Argument Names

Justification

Example

   class NameOneTwo
   {
      function StartYourEngines(&$someEngine, &$anotherEngine) {
      	$this->mSomeEngine = $someEngine;
      	$this->mAnotherEngine = $anotherEngine;
      }

      var $mSomeEngine;
      var $mAnotherEngine;
   }


Variable Names

Justification

Example

function HandleError($errorNumber)
{
    $error = new OsError;
    $time_of_error = $error->GetTimeOfError();
    $error_processor = $error->GetErrorProcessor();
}


Reference Variables and Functions Returning References

Justification

Example

class Test
{
    var $mrStatus;
    function DoSomething(&$rStatus) {};
    function &rStatus() {};
}


Global Variables

Justification

Example

    global $gLog;
    global &$grLog;


Define Names / Global Constants

Justification

It's tradition for global constants to named this way. You must be careful to not conflict with other predefined globals.

Example


define("A_GLOBAL_CONSTANT", "Hello world!");

Static Variables

Justification

Example

function test()
{
static $msStatus = 0; }


Function Names

Justification

Example

function some_bloody_function()
{
}


Error Return Check Policy


Braces {} Policy

Justification


Indentation/Tabs/Space Policy

Justification

Example

   function func() {
       if (something bad) {
           if (another thing bad) {
               while (more input) {
               }
           }
       }
   }


Parens () with Key Words and Functions Policy

Justification

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 a constructor initialize variables only and/or do only actions that can't fail.

Create an Open() method for an object which completes construction. Open() should be called after object instantiation.

Justification

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 being reentrant.


If Then Else Formatting

Layout

It's up to the programmer. Different bracing styles will yield slightly different looks. One common approach is:
   if (condition) {                   // Comment
   } else if (condition) {            // Comment
   } else {                           // Comment
   }
If you have else if statements then it is usually a good idea to always have an else block for finding unhandled cases. Maybe put a log message in the else even if there is no corrective action taken.

Condition Format

Always put the constant on the left hand side of an equality/inequality comparison. For example:

if ( 6 == $errorNum ) ...

One reason is that if you leave out one of the = signs, the pharser will find the error for you. A second reason is that it puts the value you are looking for right 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

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 covered here.

Continue and break like goto should be used sparingly as they are magic in code. With a simple spell the reader is beamed to god knows where for some usually undocumented reason.

The two main problems with continue are:

Consider the following example where both problems occur:

while (TRUE) {
   ...
   // A lot of code
   ...
   if (/* some condition */) {
      continue;
   }
   ...
   // A lot of code
   ...
   if ( $i++ > STOP_VALUE) break;
}
Note: "A lot of code" is necessary in order that the problem cannot be caught easily by the programmer.

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 code in between the ? and :. Here are a couple of clarity rules to follow:

Example

   (condition) ? funct1() : func2();

   or

   (condition)
      ? long statement
      : another long statement;


Alignment of Declaration Blocks

Justification

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 statements are very closely related.


Short Methods

Justification


Document Null Statements

Always document a null body for a for or while statement so that it is clear that 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.

   if (FAIL != f())
is better than

   if (f())
even though FAIL may have the value 0 which PHP considers to be false. An explicit test will help you out later when somebody decides that a failure return should be -1 instead of 0. Explicit comparison should be used even if the comparison value will never change; e.g., if (!($bufsize % strlen($str))) should be written 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 test for string equality, where the result should never ever be defaulted.

The non-zero test is often defaulted for predicates and other functions or expressions which meet the following restrictions:


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.). Most functions are guaranteed to return 0 if false, but only non-zero if true. Thus,


   if (TRUE == func()) { ...
must be written

   if (FALSE != func()) { ...


Usually Avoid Embedded Assignments

There is a time and a place for embedded assignment statements. In some constructs there is no better way to accomplish the results without making the code 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 to improve run-time performance is also possible. However, one should consider the tradeoff between increased speed and decreased maintainability that results when embedded assignments are used in artificial places. For example,


   $a = $b + $c;
   $d = $a + $r;
should not be replaced by

   $d = ($a = $b + $c) + $r;
even though the latter may save one cycle. In the long run the time difference between the two will decrease as the optimizer gains maturity, while the difference in ease of maintenance will increase as the human memory of what's going on in the latter piece of code begins to fade.


HTTP_*_VARS

HTTP_*_VARS are either enabled or disabled. When enabled all variables must be accessed through $HTTP_*_VARS[key]. When disabled all variables can be accessed by the key name.

Justification


PHP File Extensions

There is lots of different extension variants on PHP files (.html, .php, .php3, .php4, .phtml, .inc, .class...).
When you choose to use the .html extension on all your web documents, you should put all your libraries in files with the extension .php. When compared with the c language, the .c becomes .html and .h becomes .php.

Justification


Use if (0) to Comment Out Code Blocks

Sometimes large blocks of code need to be commented out for testing. The easiest way 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 comments and 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 X {
      function GetAge()        { return $this->mAge; }
      function SetAge($age)    { $this->mAge = $age; }
      var $mAge;
   }
Get/Set is ugly. Get and Set are strewn throughout the code cluttering it up.

But one benefit is when used with messages the set method can transparently transform from native machine representations to network byte order.

Attributes as Objects

   class X {
      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
Attributes as Objects is clean from a name perspective. When possible use this approach to attribute access.


PHP Code Tags

PHP Tags are used for delimit PHP from html in a file. There are serval ways to do this. <?php ?>, <? ?>, <script language="php"> </script>, <% %>, and <?=$name?>. Some of these may be turned off in your PHP settings.

Justification

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 magic because no-one has a clue what it means including the author inside 3 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 the numbers were just plain wrong how would you know?

Heavy use of magic numbers marks a programmer as an amateur more than anything else. Such a programmer has never worked in a team environment or has had to maintain code or they would never do such a thing.

Instead of magic numbers use a real name that means something. You should use 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?