I wrote the following for a software engineering class, while acting as the project code auditor, tester, and quality control person. Feel free to use and learn from it as wanted. Note that PostgreSQL was the assumed database for this standard.

PHP Coding Standards

Overall Design Considerations

The following are the underlying principals to consider when making decisions on trade-offs and courses of action to take

  • Make it work correctly before you add extraneous features
  • Aspects of importance are in the following order from highest importance to least importance: correct operation, security, code readability, ease of use, portability, efficiency, power, features.
  • All components of the system should be designed with the thought of them being used with other programming languages, settings, etc.
  • Choose readable PHP code over readable resultant HTML code.
  • K.I.S.S. (keep it simple stupid)

PHP Code

The following is loosely based on style(9).

  • PHP files will have the extension .php.
  • All files will end lines using \n instead of the \r\n alternative, or related alternatives.
  • Indentation of code block will be two spaces. Tabs should not be used for indenting except for comments between the end of the code on a line and the end of the line. In such cases tabs will be 8 characters wide.
  • The following are how comments will look:
         /*
          * VERY important single-line comments look like this.
          */
    
         /* Most single-line comments which span a whole line will look like this */
    
         Code(); // Comments which are on the same line as code will look like this.
    
         /*
          * Multi-line comments look like this.  Make them real sentences.  Fill
          * them so they look like real paragraphs.
          */
        
  • Each file will begin with the CVS $Id: php_code_standards.ptml,v 1.1.1.1 2002/01/27 21:57:26 srp Exp $ tag, followed by a one line description of the purpose of the file, followed by a listing of the copyright With a list of the authors who worked on the file. This will be followed by a brief description of what the file does including the various way it may be called (what HTTP input it might accept). Comments about the variables may be omitted if their name clearly indicates what will be in the variable and all rules which constrain the given variable; firstname would be a good example of a variable that would not need a comment. The header should conclude with default variables for the file. The following is the start of a file named add_user.php:
         = 1 for warnings and >= 5 to see database queries
    
        
  • Use a single space between the keywords if, while, for and the opening parenthesis. A space must also be placed between a closing parenthesis and the opening bracket which must be on the same line. The closing bracket must be at the same horizontal level of indentation as the first letter of the keyword. The brackets around the block may not be left out around the block of code inside a control structure unless the code block is completely empty.
         for ($i = 0; $i < $max_things; $i++) {
           do_stuff();
         }
    
         while(still_returning_true($arg));
        
  • Do not use spaces after function names. Commas have a space after them. Do not use spaces after ( or [ or preceding ] or ) characters.
         if($error = function($a1, $a2)) {
           print $error;
           exit;
         }
        
  • Unary operators don't require spaces, binary operators do including the assignment operator. Don't use parentheses unless they're required for precedence, the statement is confusing without them. Remember that other people may be confused more easily than you.
  • PHP code must fit within a line width of 80 characters. (Note that this rules doesn't apply to HTML lines including HTML lines which include PHP print statements)
  • When a line break must be made in the middle of the arguments being passwd to a function, the second and further lines must be indented to be aligned with the first variable passed to the function:
         $result = create_user($username, $password, $password2, $firstname, $lastname,
                               $email, $phone);
        
  • The function phpinfo must never be called in any piece of code that is not password protected and only accessible by system administrators.
  • SQL queries in PHP must be assigned to a variable (this allows for easy printing of the query for debugging purposes). The result from a query must always be kept and checked, and appropriate measures taken on warnings and errors. The SQL keywords of SQL queries must be in all capital letters. Queries longer then one line must be broken by the logical breaks between SQL keywords. One line per logical compare should be used in the WHERE part of multi-line queries.
         $query = "SELECT * FROM users"; // one line query
    
         /* multi-line query */
         $query = "SELECT u_username AS username, u_firstname AS firstname, 
                          u_lastname AS lastname
                   FROM users, users_groups_map, groups
                   WHERE 
                     u_id = ugm_u_id
                       AND
                     ugm_g_id = g_id
                       AND
                     g_name = '$desired_group'
                   ORDER BY username ASC";
    
         $r = pg_exec($db, $query);
         if (!$r) {
           print pg_errormessage($res);
         }
        
  • Database error messages should never print the $query unless the a $debug flag is set to specify that such is okay. (Printing a $query might allow users to see details of the database and the query which could potentially allow them to exploit the database and connection code)
  • When referencing string indexes of an array, use quotes around the name of key.
         $tmp = $array[key]; // bad
         $tmp = $array["key"]; // good
        
  • Avoid using array syntax inside of quotes in PHP.
         $str = "It is best not to try to try $things[like_this]";
        
         $str = "It is much better to try " . $thigs["like_this"];
        
  • $GLOBAL variables may never be used in functions or class functions, except for configuration variables.
  • Configuration variables should be included from a special configuration file, and should have minimal variables by using arrays of related options.
  • Proceeding a function should be several lines of comments including a description of the function, the definition and restraints of the arguments, the possible types and values and meanings of return values.
  • All PHP code should assume that magic_quotes_gpc is turned on, and act accordingly.
  • For consistency use the print command rather then the echo command.
  • Avoid many repeated transitions from PHP mode to HTML mode in close proximity of each other.
  • When looping or dealing with conditional blocks of code, either use print statements for HTML output, or consider functionizing the code block for larger sections of HTML.
  • The pg_close function must be called at the end of each php file using PostgreSQL even if pg_pconnect is used.

HTML

The following is based on the XHTML recommendation from http://www.w3.org/.

  • HTML code does not need to fit within an 80 character width boundary; shorter lines are preferred wherever possible.
  • Each level of embededness should be distinguished with an additional space for indentation.
    
         <table>
          <tr>
           <th>Username</th>
          </tr>
          <tr>
           <td>
            sRp
           </td>
          </tr>
         </table>
        
  • Elements and attributes must be all lowercase
  • All must either contain closing tags or, if empty, use the special empty element syntax.
    
         <p>This is a paragraph.     <!-- incorrect -->
         <p>This is a paragraph.</p> <!-- correct -->
         <br>                        <!-- incorrect -->
         <br />                      <!-- correct -->
         <br></br>                   <!-- correct -->
        
  • Elements can not overlap.
    
         <p>here is an emphasized <em>paragraph.</p></em> <!-- incorrect -->
         <p>here is an emphasized <em>paragraph</em>.</p> <!-- correct -->
        
  • Attributes must always have quoted values, even for numbers.
    
         <input type="text" name="username" size="8">
        
  • Attributes without values are not allowed. If no value is needed, use a value identical to the attribute name.
    
         <input type="checkbox" name="enabled" value="t" checked> <!-- incorrect -->
         <input type="checkbox" name="enabled" value="t" checked="checked"> <!-- correct -->
        
  • Do not use line breaks in attribute values.
  • Only make HTML comments which are intended for any users to see, wrap all other comments as PHP comments.
  • Make sure that the rendering of all code looks acceptable even with CSS and JavaScript turned off.
  • Spellcheck even if it is painful with HTML tags and PHP code.
  • All pages must be viewable and functional with the following browsers: Internet Explorer 4 and 5 on Microsoft Windows, Netscape Communicator 4 on Microsoft Windows and Unix, the current release of Mozilla, and Lynx.

Database

  • Table names are all lowercase words separated by underscores.
  • Table names are plural for the items they hold: for instance users instead of user
  • Field names are all lowercase with words separated by underscores
  • Fields are singular unless multiple types are stored in it
  • Fields names are prefixed with the first letter of each word of the table name: for instance a user_group_map table would have a field name of ugm_id field.
  • Each table has a serial index as its primary key, this field is named with the above prefix and has a postfix of id, ugm_id for instance
  • Tables which need bi-directional linking will use a third map table which will contain at least 2 fields: fields which reference the serial fields of the tables it links. Additional fields may be added to a mapping table if so desired.
  • Field references must make use of foreign keys and use appropriate cascading (most likely delete and update)
  • Don't make table name of reserved words. Reserved words are as follows:
    abort add all allocate alter analyze and any are as asc assertion at authorization avg begin between binary bit bit_length both by cascade cascaded case cast catalog char character character_length char_length check close cluster coalesce collate collation column commit connect connection constraint continue convert copy corresponding count create cross current current_date current_session current_time current_timestamp current_user cursor date datetime deallocate dec decimal declare default delete desc describe descriptor diagnostics disconnect distinct do domain drop else end escape except exception exec execute exists explain extend external extract false fetch first float for foreign found from full get global go goto grant group having identity in indicator inner inout input insert intersect interval into is join last leading left like listen load local lock lower max min module move names national natural nchar new no none not notify null nullif numeric octet_length offset on open or order out outer output overlaps partial position precision prepare preserve primary privileges procedure public references reset revoke right rollback rows schema section select session session_user set setof show size some sql sqlcode sqlerror sqlstate substring sum system_user table temporary then timespan to trailing transaction translate translation trim true union unique unknown unlisten until update upper usage user using vacuum value values varchar varying verbose view when whenever where with without work write
    Field names shouldn't be concerned with reserved words as the prefix generally will avoid this problem.
  • Use the text type for all field which are character based and do not fit into other types, unless the size is only always a fixed length or bounded, in which case a varchar or char type may be used.
  • Date type should always be datetime type unless only ever the date part or the time portion is all that is desired (hopefully this will occur infrequently)
  • The bool or boolean type will be used for fields having a true or false value
  • Unless needed, fields should be have the constraint not null placed on them. Such fields should also make an have an appropriate default value.



Copyright 2000-2005 Scott Parish
All rights reserved.