Gallery3:Coding Standards - Gallery Codex
Personal tools

Gallery3:Coding Standards

From Gallery Codex

Introduction

The purpose of this document is to lay out a clear set of guidelines for developing code for the Gallery project. The scope of this document is limited mainly to PHP code, although Gallery will occasionally use SQL and HTML.

Why have Code Conventions?

Code conventions are important to programmers for a number of reasons:

  • 80% of the lifetime cost of a piece of software goes to maintenance.
  • Hardly any software is maintained for its whole life by the original author.
  • Code conventions improve the readability of the software, allowing engineers to understand new code more quickly and thoroughly. If you ship your source code as a product, you need to make sure it is as well packaged and clean as any other product you create.

Acknowledgments

This document has been largely created by culling information from the following documents:

Gallery3 Themes

Theme design/coding standards.

Editor Settings / Scripts

VIM

Configuration
" Tabs to spaces
set expandtab 
set smarttab

" 2 Spaces in each case
set tabstop=2
set shiftwidth=2
set softtabstop=2

" Maximum 100 characters in line
set textwidth=99

" Set filetype
set filetype=php
Using global for all PHP files

Add configration above to .vimrc file.

As separate configuration

Make sure Your .vimrc file contain line

filetype plugin indent on

Then create file ~/.vim/ftplugin/g3.vim contain configuration as above. A the end append:

" Set filetype
set filetype=php

After edit file in vim run command :set filetype=g3. After that appropriate config files will be load.

Indentation

For indentation copy /usr/share/vim/*/indent/php.vim to ~/.vim/indent/ or add to configuration something like

" Set indentation
set autoindent
set smartindent

Emacs

To configure Emacs to use Gallery's PHP style:

  1. Put the following files in your Emacs load path
  2. Put this line in your .emacs flie
    (load "php-style.el")
  3. Restart emacs

Any .php files you open in emacs should be in PHP mode, and it should follow Gallery 3's coding standards. Any .html.php files should be in SGML mode. To automatically indent, hit <tab> and it should do the right thing.

Eclipse PDT

To configure Eclipse PDT to use Gallery's PHP style:

  1. In the Preferences/General/Editors/Text Editors insure the following settings are set:
    • Displayed tab width = 2
    • Insert spaces for tabs should be checked
    • Show print margin should be checked
    • Print margin column = 100
  2. In the Preferences/PHP/Code Style/Formatter insure the following settings are set:
    • Tab policy = Spaces
    • Indentation Size = 2
  3. In the Preferences/Team/Ignored Resources insure that ".cache", ".project", ".buildpath" and ".settings" are ignored.
  4. In Preferences/PHP/Editor/Save Actions set the following:
    • Remove trailing whitespace should be checked
    • Choose All lines

For debugging, it's useful to have a short template that gets expanded to the line used to add entries to Kohana's debug log. To do this:

  1. Go to Preferences/PHP/Templates
  2. Click on New
  3. Enter klog in the name field
  4. Make sure Context is set to PHP and Automatically insert is checked
  5. Enter a description (e.g. Add a string to Kohana's debug log.)
  6. Enter Kohana::log("debug", "${variable}"); in the pattern field

Now every time while editing PHP files you enter klog and press Ctrl+Space, it will get expanded to the text entered in the pattern field above. The cursor will already be between the quotes and you can start typing the log message immediately. Make sure to press Enter after you finish writing in order for Eclipse to properly exit template editing mode.

Indentation

Two spaces is the basic unit of indentation. Tabs are prohibited.

function my_function() {
  // 2 spaces
  code;
  code;

  if (indent_another_level) {
    // Another 2 spaces
    more_code;
    more_code;
  } 
}


Line Length

Avoid lines greater than 100 characters in all PHP files. You can break this exception in View files where we're generating HTML output if it would affect the display.

Wrapping Lines

  • Break after a comma.
  • Break before an operator.
  • Prefer higher-level breaks to lower-level breaks.
  • Align the new line with the beginning of the expression at the same level on the previous line.
  • If the above rules lead to confusing code or to code that's squished up against the right margin, just indent 4 columns instead (not 2 columns).

Here are some examples of breaking method calls:

   some_method(long_expression1, long_expression2, long_expression3,
               long_expression4, long_expression5);

   var = some_method1(long_expression1,
       some_method2(long_expression2, long_expression3));

Following are two examples of breaking an arithmetic expression. The first is preferred, since the break occurs outside the parenthesized expression, which is at a higher level.

   // PREFER
   long_name1 = long_name2 * (long_name3 + long_name4 - long_name5) +
       4 * long_name6;

   // AVOID 
   long_name1 = long_name2 * (long_name3 + long_name4
       - long_name5) + 4 * longname6;

Following are two examples of indenting function declarations. The first is the conventional case where the arguments are indented under the open parenthesis. In the second case, the function name is so long that indenting under the parenthesis would require us to put many parameters on their own line which is not visually appealing. But we can't indent the follow on lines by 2 columns because then it would be hard to differentiate them from the code that follows, so we indent them 4 columns, as we do when indenting wrapping if-clauses (see below).

   // CONVENTIONAL INDENTATION
   function some_function($an_arg, $another_arg, $yet_another_arg,
                          $and_still_another) {
     codeHere;
   }
 
   // INDENT 4 COLUMNS TO AVOID VERY DEEP INDENTS
   function superExtraHorkingLongMethodName($an_arg, $an_arg, $an_arg,
       $another_arg, $yet_another_arg, $yet_more_arg, $an_arg, $an_arg
       $and_still_another) {
     codeHere;
   }

Line wrapping for if statements should generally align with the opening ( of the if ( statement. For example:

   // This is fine
   if ((condition1 && condition2) ||
       (condition3 && condition4) ||
       !(condition5 && condition6)) {
     do_something_about_it();
   }
   // You can put the operators on the continuation line as well
   if ((condition1 && condition2)
       || (condition3 && condition4)
       || !(condition5 && condition6)) {
     do_something_about_it();
   }

Expressions using the ternary operator should be parenthesized. Here are three acceptable ways to format ternary expressions:

   $alpha = (a_long_boolean_expression) ? $beta : $gamma;
         
   $alpha = (a_long_boolean_expression) ? $beta
                                        : $gamma;
         
   $alpha = (a_long_boolean_expression)
            ? $beta
            : $gamma;

Line Termination

Ensure that your editor is saving files in the Unix format. This means lines are terminated with a newline, not with a CR/LF combo as they are on Win32, or whatever the Mac uses. Any decent Win32 editor should be able to do this, but it might not always be the default. Know your editor.

HTML Template File Indention

Same indention rules as for PHP files, except that you can break the 100 column line length if necessary to preserve proper output.

Naming Convention

Naming conventions make programs more understandable by making them easier to read. They can also give information about the function of the identifier-for example, whether it's a constant, package, or class-which can be helpful in understanding the code.

In the block below, we'll refer to a capitalization strategy called under_score. In this strategy, multiple words are combined using an underscore between words, and none of the letters are capitalized. Acronyms should be all upper case.

There are two forms:

  • Upper_Case: The first letter of each word is capitalized. (eg Album_Core)
  • lower_case: no letters are capitalized (eg show_album)
Type Description Example
Files File names are in lower_case with the exception of [[1][libraries]] which are required by Kohana to be Upper_Case. Try to keep your file names simple and descriptive.

Files containing only code (controllers, libraries, helpers, etc) should terminate in .php. Views should terminate in .html.php, so that editors can treat them as HTML files that contain PHP.

album.php
album_add.html.php
Classes Class names are in Upper_Case and should be nouns. Try to keep your class names simple and descriptive. Acronyms should be upper case. The exception to this is helper classes containing only static functions. In this case, the class name is all in lower case. class Album_Controller

class ORM_MPTT

Variables Variables are in lower_case.

Variable names should be short yet meaningful. The choice of a variable name should be mnemonic -- that is, designed to indicate to the casual observer the intent of its use. One-character variable names should be avoided except for temporary "throwaway" variables such as loop indexes.

var $fields;

var $user_information;

Functions Functions are in lower_case and should be verbs. Functions that return boolean values should be in the form of a question as in is_enabled. The noun-verb formation makes code easier to read, eg "Is the user enabled?" becomes if ($user->is_enabled). function some_function()
Constants Constants should be all upper case. define('MIN_WIDTH', 4);
Database Tables Table names should use lower_case and nouns should be pluralized. items

user_roles

Database Fields Field names should use lower_case. last_name

favorite_color

Class and Function Declarations

When coding classes and functions, the following formatting rules should be followed:

  • No space between a method name and the parenthesis "(" starting its parameter list
  • Open brace "{" appears at the end of the same line as the declaration statement
  • Closing brace "}" starts a line by itself indented to match its corresponding opening statement, except when it is a null statement the "}" should appear immediately after the "{"
  • Functions with a leading underscore "_" should be treated as private an not called directly by any code except for unit tests. In order to allow the unit tests to test private methods they have to be scoped so that they can be called by the unit test framework. *Note* It is the expectation that any methods or functions that have a leading underscore can be changed or deleted with causing an API incompatibility.

The above rules are sometimes referred to as the K&R style. Example:

   class Foo {
     function get_bar($a, $b) {
       // code
     }
   }

Statements

Simple Statements

Each line should contain at most one statement. Example:

   $argv++;                // Correct
   $argc--;                // Correct
   $argv++; $argc--;       // AVOID! 


Compound Statements

Compound statements are statements that contain lists of statements enclosed in braces "{ statements }".

The enclosed statements should be indented one more level than the compound statement. The opening brace should be at the end of the line that begins the compound statement; the closing brace should begin a line and be indented to the beginning of the compound statement. Braces are used around all statements, even single statements, when they are part of a control structure, such as an if-else or for statement. This makes it easier to add statements without accidentally introducing bugs due to forgetting to add braces. Example:

   if ($a) {               // Correct
     b();
     c();
   }
   
   if ($a) {               // Correct
     b();
   }
   
   if ($a)                 // AVOID! 
     b();
   
   if ($a) b();            // AVOID! 

"return" Statements

A return statement with a value should not use parentheses unless they make the return value more obvious in some way. Example:

   return;

   return my_disk.size();

   return (size ? size : defaultSize);


"if", "if else", "if else-if else" Statements

The if-else class of statements should have the following form:

   if (condition) {
     statements;
   }

   if (condition) {
     statements;
   } else {
     statements;
   }

   if (condition) {
     statements;
   } else if (condition) {
     statements;
   } else {
     statements;
   }

Note:

  • if statements always use braces {}. Avoid the following error-prone form:
   if (condition) // AVOID! THIS OMITS THE BRACES {}!
     statement;
  • if statements always use "else if" and not "elseif"
  • The opening and closing brace is always on the same line as the if, else if and else lines.

Alternative if: endif; Syntax

The alternative if, elsif, else, endif syntax is used in templates (mixed HTML / PHP templates), but not in pure PHP files.

 <div
   <? if (Foo::hasChanged()): ?> class="changed"
   <? elseif (Foo::isNew()): ?> class="new"
   <? else: ?> class="sameold"
   <? endif; ?>
 >

"for" Statements

A for statement should have the following form:

   for (initialization; condition; update) {
     statements;
   }

An empty for statement (one in which all the work is done in the initialization, condition, and update clauses) should have the following form:

   for (initialization; condition; update);

When using the comma operator in the initialization or update clause of a for statement, avoid the complexity of using more than three variables. If needed, use separate statements before the for loop (for the initialization clause) or at the end of the loop (for the update clause).

"while" Statements

A while statement should have the following form:

   while (condition) {
     statements;
   }

An empty while statement should have the following form:

   while (condition);


"do-while" Statements

A do-while statement should have the following form:

   do {
     statements; 
   } while (condition);


"switch" Statements

A switch statement should have the following form:

   switch (condition) {
   case ABC:
     statements;
     // falls through

   case DEF:
     statements;
     break;

   case XYZ:
     statements;
     break;

   default:
     statements;
     break;
   }

Every time a case falls through (doesn't include a break statement), add a comment where the break statement would normally be. This is shown in the preceding code example with the // falls through comment. Every switch statement should include a default case. The break in the default case is redundant, but it prevents a fall-through error if later another case is added.

White Space

Blank lines improve readability by setting off sections of code that are logically related. Two blank lines should always be used in the following circumstances:

  • Between sections of a source file
  • Between class and interface definitions

One blank line should always be used in the following circumstances:

  • Between methods
  • Between the local variables in a method and its first statement
  • Between logical sections inside a method to improve readability

Blank Spaces

Blank spaces should be used in the following circumstances: A keyword followed by a parenthesis should be separated by a space. Example:

   while (true) {
     ...
   }

Note that a blank space should not be used between a method name and its opening parenthesis. This helps to distinguish keywords from function calls. A blank space should appear after commas in argument lists. All binary operators except . should be separated from their operands by spaces. Blank spaces should never separate unary operators such as unary minus, increment ("++"), and decrement ("--") from their operands. Example:

   $a += $c + $d;
   $a = ($a + $b) / ($c * $d);
   while ($n < $s) {
     $n++;
   }
   print("size is $foo\n");

The expressions in a for statement should be separated by blank spaces. Example:

   for (expr1; expr2; expr3)

Casts should not be followed by a blank space. Examples:

   my_function((int)$a, (int)$b);

Comments

All code should be well commented. Good comments explain why a code is written in a particular way. You don't need to explain how it works -- that much we can figure out from reading the code. The reasoning behind your choices is the interesting part.

    /* This is a good single line comment */
    // This is a good single line comment

    /*
     * This is a good block comment.  Note how the
     * open and closing comment tokens are on their own lines.
     */
    
    // This is a good block comment. All comments should be
    // proper English sentences with proper punctuation.
    /* Bad block comments should have the open and closing
     * comment on their own line
     */

    /* Worse.  Block comments should have the open and closing
     * comment on their own line */
   

Use of Perl/shell style comments (#) are not allowed. Multiple line C style comments should see the asterisks aligned in a column (including the first line).

In addition, commenting any tricky, obscure, or otherwise not-immediately-obvious code is clearly something we should be doing. Especially important to document are any assumptions your code makes, or preconditions for its proper operation. Any one of the developers should be able to look at any part of the application and figure out what's going on in a reasonable amount of time.

Class/Package Comments

These should appear at the beginning of every file, and help to explain the purpose of the file, and its place in the Gallery hierarchy. For example, the Gallery's core module is named the GalleryCore package. Files in the classes directory are part of the Classes subpackage. When these comments apply to classes, they become the class comments. Such a comment might look like:

   /**
    * Short explanation (1 line!)
    *
    * Some more text which explains in more detail what
    * the file does and who might be interested
    * in understanding that.
    *
    * @version $Id: coding-standards.xml,v 1.6 2005/05/22 22:54:29 bharat Exp $
    * @package GalleryCore
    * @subpackage Classes
    * @module GalleryModuleName
    */


  • The first line should be short but meaningful.
  • The longer explanation may span several lines. Currently HTML markup is not retained, so try to avoid it.
  • An @author statement might be present. see function comments below for details.
  • The @version statement should be used unchanged. Subversion will magically transform this into the actual version info of the file.
  • The @package statement identifies the file with its package.
  • The @subpackage statement further classifies the file.
  • The @module statement gives the file a more meaningful name. Usually it should be the filename without the suffix .php. Dots are not allowed in the name, so convert them to underscore if needed.

Function/Method Comments

These explain in detail what a function does, what parameters it expects and what is returned by the function. Function comments apply to classes as well, here they magically turn into method comments. Such a comment appears directly above a function definition looks like this:

   /**
    * Short explanation (1 line!)
    *
    * Some more text which explains in more detail what
    * the function does and who might be interested
    * in understanding that.
    *
    * @author Name <email address>
    * @author Name2 <other email address>
    * @param type description
    * @return type description
    * @throws IllegalArgumentException
    */
   function functionName( ...
  • The first line should be short but meaningful.
  • The longer explanation may span several lines. Currently HTML markup is not retained, so try to avoid it.
  • Use one @author statement per author, consisting of his/her name and optionally the email address in < and > signs. If given, the email address will be converted into a hyperlink automagically.
  • One or more @param statements describing the arguments the function expects. They must be given in the order in which they appear in the function definition. A @return statement, if the function returns something.

Class Variable and Include File Comments

These are simple: They just quickly explain what a class varibale is used for, or what an included file does, or why we need it. These comments may be longer, if you have to explain more. They should appear just above the corresponding variable or include/require statement. They can be just one line and look like this:

   /**
    * Some explanation of the variable or file just below this comment.
    */

Document Header

All files should contain the following text in a form where it will not interfere with the purpose of the file (i.e., commented out). In this example, it's presented in a commented out form for inclusion into PHP files.

   <?php 
   /* 
    * Gallery - a web based photo album viewer and editor 
    * Copyright (C) 2000-2008 Bharat Mediratta 
    * 
    * This program is free software; you can redistribute it and/or modify 
    * it under the terms of the GNU General Public License as published by 
    * the Free Software Foundation; either version 2 of the License, or (at 
    * your option) any later version. 
    * 
    * This program is distributed in the hope that it will be useful, but 
    * WITHOUT ANY WARRANTY; without even the implied warranty of 
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
    * General Public License for more details. 
    * 
    * You should have received a copy of the GNU General Public License 
    * along with this program; if not, write to the Free Software 
    * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA. 
    */ 
   ?>

Special Comments

Occasionally you wind up checking in code that's not totally satisfactory. Sometimes this is inevitable. In order to locate these bits of code so that we find and resolve it later, use the following tags in a comment, above the code in question:

  • REVISIT: this is an optimization waiting to happen, or something that could be improved on later. Optionally. If we're bored. And have itchy C-x v v fingers.
  • TODO: this is missing functionality (so by definition, it's broken) that needs to be addressed at some point.
  • FIXME: this is stubbed/broken functionality, but I need to commit. It can limp for now.

Keep in mind that you may not get back to this code for a while. You may not even be the one to fix the thing, so the more information that you provide while it's still fresh in your mind, the better. Potential solutions or workarounds are great, and may prove invaluable to whomever gets around to addressing the issue.

If the comment isn't clear it may be ignored and eventually deleted.

At some point in the future this will enable us to dictate the following:

  • No point release with FIXMEs
  • No major release with TODOs

PHP-Specific Guidelines

Associative Array Keys In PHP, it's legal to use a literal string as a key to an associative array without quoting that string. We don't want to do this; the string should always be quoted to avoid confusion. Note that this is only when we're using a literal, not when we're using a variable. Examples:

   $foo = $assoc_array[blah];   // WRONG

   $foo = $assoc_array["blah"]; // RIGHT


Heredoc

Using the Heredoc string format is not recommended. One reason why is because it breaks the indention model.

Including Code

Anywhere you are unconditionally including a class file, use require_once(). Anywhere you are conditionally including a class file (for example, factory methods), use include_once(). Either of these will ensure that class files are included only once. They share the same file list, so you don't need to worry about mixing them. A file included with require_once() will not be included again by include_once().

Note: include_once() and require_once() are statements, not functions. You don't need parentheses around the filename to be included.

PHP Code Tags

In PHP files, use <?php at the beginning of the file and omit the ?> at the end. Example:

 <?php
 class Some_Code {
   function doSomething() {
     return "Hello";
   }
 }

This looks weird, but it's important because it prevents a particular problem where you accidentally put extra characters after a closing ?>. Those characters then get printed out to the browser and interfere with the UI, or worse.

Template files (files mixing HTML and PHP named .html.php) should use short PHP open tags. Example:

 <?= Some_Code::doSomething()?>
 <?= $variable ?>
 <? comment::ShowComments() ?>

Uninitialized Variables

Don't use uninitialized variables. Gallery uses a high level of run-time error reporting. This will mean that the use of an uninitialized variable will be reported as an error. This will come up most often when checking which HTML form variables were passed. These errors can be avoided by using the built-in isset() function to check whether a variable has been set. Examples:

   // wrong
   if ($forum) ...
   if (!$forum) ...

   // correct
   if (isset($forum)) ...
   if (empty($forum)) ...

Miscellaneous

Magic Numbers

Don't use them. Use named constants for any literal value other than obvious special cases. Basically, it's OK to check if an array has 0 elements by using the literal 0. It's not OK to assign some special meaning to a number and then use it everywhere as a literal. This hurts readability and maintainability. Included in this guideline is that we should be using the constants true and false in place of the literals 1 and 0. Even though they have the same values, it's more obvious what the actual logic is when you use the named constants.

Shortcut Operators

The only shortcut operators that cause readability problems are the shortcut increment ($i++) and decrement ($j--) operators. These operators should not be used as part of an expression. They can, however, be used on their own line. Using them in expressions is just not worth the headaches when debugging. Examples:

   // WRONG
   $array[++$i] = $j;
   $array[$i++] = $k;

   // RIGHT
   $i++;
   $array[$i] = $j;

   $array[$i] = $k;
   $i++;

Operator Precedence

Do you know the exact precedence of all the operators in PHP? Neither do I. Don't guess. Always make it obvious by using brackets to force the precedence of an equation so you know what it does.

   // what's the result? who knows.
   $bool = ($i < 7 && $j > 8 || $k == 4);

   // now you can be certain what I'm doing here.
   $bool = ($i < 7 && ($j < 8 || $k == 4))

Capitalization of Strings

Gallery 3 uses sentence-style capitalization rules. For sentence-style capitalization:

  • Always capitalize the first word of a new sentence, form label, menu option, stand-alone link, button value, or block title. Exceptions include proper nouns and acronyms.
    • Forgot your password?
    • Search the gallery
    • Print this with Digibug
  • Labels and option lists separated by slashes should have initial words capitalized after all slashes, ex. Users/Groups.
  • Don't capitalize the word following a colon unless the word is a proper noun, or the text following the colon is a complete sentence.
  • Don't capitalize the word following an em-dash unless it is a proper noun, even if the text following the dash is a complete sentence.
  • Always capitalize the first word of a new sentence following any end punctuation. Rewrite sentences that start with a case-sensitive lowercase word.

Reference: http://msdn.microsoft.com/en-us/library/aa511441.aspx#SentenceCaps