FastFrame Coding Standards

Indenting

Use an indent of 4 spaces, with no tabs.

Control Structures

These include if, for, while, switch, etc. Here is an example if statement, since it is the most complicated of them:

  
if ((condition1) || (condition2)) {
    action1;
} 
elseif ((condition3) && (condition4)) {
    action2;
} 
else {
    defaultaction;
}

Multi-line if conditions are braced this way:

if ((condition1) || (condition2) || (condition3) ||
    (condition4)) {
    action1;
}

Control statements should have one space between the control keyword and opening parenthesis, to distinguish them from function calls.

Code (this does not include code structures such as }) that comes after an if statement should have one empty line between the ending } and the code:

if (condition) {
    action;
}

action2;

Do not omit the curly braces under any circumstance. In the case of a large number of short tests and actions, the following is acceptable:

if (condition)   { action; }
if (condition 2) { action 2; }
...

For switch statements:

switch (condition) {
    case 1:
        action1;
        break;
     case 2:
        action2;
        break;
     default:
        defaultaction;
        break;
}

Function Calls

Functions should be called with no spaces between the function name, the opening parenthesis, and the first parameter; spaces between commas and each parameter, and no space between the last parameter, the closing parenthesis, and the semicolon. Here’s an example:

$var = foo($bar, $baz, $quux);

As displayed above, there should be one space on either side of an equals sign used to assign the return value of a function to a variable. In the case of a block of related assignments, more space may be inserted to promote readability:

$short         = foo($bar);
$longVariable  = foo($baz);

If assigning a reference to a variable, place the ampersand next to the equal sign, not the referenced object:

$reference =& $foo;
$reference =& foo();

Function Definitions

Function declaractions follow the “one true brace” convention:

function fooFunction($arg1, $arg2 = '')
{
    if (condition) {
        statement;
    }
    return $val;
}

Arguments with default values go at the end of the argument list. Always attempt to return a meaningful value from a function if one is appropriate.

Functions used only in the current script/class (e.g. private member methods) should begin with a ‘_’ character (e.g. _exampleLibrary). This helps distinguish these private function calls from other, public function calls.

All classes should be prefixed with FF_ as a namespace in order to prevent conflicts with other packages.

Private Variables

Variables used exclusively within a class should begin with a underscore (_) character. An example class variable definition:

var $_variablename;

Naming Variables

Variables should always use the studlycaps for naming. Additionally, we use hungarian notation for delimiting what the type of a variable is. The following prefixes should be made to variables: $o_varName - Object $a_varName - Array $s_varName - Scalar $b_varName - Boolean $in_varName - Variable passed to a function $pth_varName - Some kind of file path $tmp_varName - Temporary variable name

Naming Libraries

Libraries (any file located in the ‘lib/’ directory of the application) should be named with capital letters at the beginning of each word. Use studlycaps for naming; a session cache class would be stored in lib/SessionCache.php.

If the library/class is extended, the extending files should be stored in a directory under ‘lib/’ with the same name as the original library. Subclasses follow the exact same naming requirements, except that if the subclass is instantiated by a factory method, it should be all lowercase.

Example: The Example Library library should be saved as lib/ExampleLibrary.php. Any file extending the library/class should be stored in the directory lib/ExampleLibrary/.

VIM Folds

VIM Folds should be placed around all function methods and license comments at the top of classes. A VIM comment improves code readability when set foldmethod=marker is set in one’s .vimrc. A VIM fold looks like this:

// {{{ functionName()

function () { ... }

// }}}

Comments

Inline documentation for classes should follow the Javadoc convention. An overview of the Javadoc standard for PHP can be found here: http://phpdoc.org/manual.php

Including Code

If you are including a class, function library, or anything else which would cause a parse error if included twice, always use require_once. This will ensure that no matter how many factory methods we use or how much dynamic inclusion we do, the library will only be included once.

PHP Code Tags

Always use <?php ?> to delimit PHP code, not the <? ?> shorthand. This is required for PEAR compliance and is also the most portable way to include PHP code on differing operating systems and setups.

Header Comment Blocks

All source code files in the FastFrame distribution should contain the following comment block as the header:

Example for LGPL‘ed FastFrame code:

// {{{ license

// +----------------------------------------------------------------------+
// | FastFrame Application Framework                                      |
// +----------------------------------------------------------------------+
// | Copyright (c) 2002-2005 The Codejanitor Group                        |
// +----------------------------------------------------------------------+
// | This source file is subject to the GNU Lesser Public License (LGPL), |
// | that is bundled with this package in the file LICENSE, and is        |
// | available at through the world-wide-web at                           |
// | http://www.fsf.org/copyleft/lesser.html                              |
// | If you did not receive a copy of the LGPL and are unable to          |
// | obtain it through the world-wide-web, you can get it by writing the  |
// | Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
// | MA 02111-1307, USA.                                                  |
// +----------------------------------------------------------------------+

// }}}

There’s no hard rule to determine when a new code contributer should be (around 10% to 20% of code changes). Exceptions could be made for rewriting functions or contributing new logic.

Simple code reorganization or bug fixes would not justify the addition of a new individual to the list of authors.

SVN Tags

Include the $Id$ SVN vendor tag in each file. As each file is edited, add this tag if it’s not yet present.

Note, that SVN does not automatically expand the $Id: CODING_STANDARDS 814 2003-09-25 00:28:54Z jrust $ tag by default, so if adding a new file to the repository you must modify it’s properties with following command:

# svn propset "svn:keywords" "Id" foo.php

Example URLs

Use example.com for all example URLs, per RFC 2606.

php.ini settings

All FastFrame code should work with register_globals = Off. This means using $_COOKIE, $_SESSION, $_SERVER, and $_ENV to access all cookie, session, server, and environment data, respectively.

To retrieve and set gpcs data (in the global $_GET, $_POST, $_SESSION, and $_COOKIE variables), you should use FF_Request::getParam() which will automatically get rid of magic quotes and allows you to specify from what variables to retrive the data and a default value. Example:

FF_Request::getParam('foo', 'gps', 'default').

Likewise, setting data to those variables should be done with the FF_Request::setParam() method. Example:

FF_Request::setParam('foo', 'val', 'gp');

All FastFrame code should work with error_reporting = E_ALL. Failure to do so would result in ugly output, error logs getting filled with lots of warning messages, or even downright broken scripts.

No FastFrame code should assume that ‘.’ is in the include path. Always specify either a constant such as FASTFRAME_ROOT, or the path to the current file using dirname(FILE), or use the FF_Registry class to require code from other applications.

XHTML 1.0 Compliance

All tag names and parameters must be lower case including javascript event handlers:

<a href="http://example.com" onmouseover="status=''" onmouseout="status=''">...</a>

Forms should be created with the HTML_QuickForm PEAR class.

All JavaScript tags must have a valid language and type parameters:

<script language="JavaScript" type="text/javascript">
<!--
...
// -->
</script>

Nothing may appear after </html>, therefore include any common footers after all other output.

All images must have an alt attribute:

    <?php $o_output->imgTag('example.gif', 'graphics', array('title' => _('Example'))); ?>

Database Naming Conventions

All database tables used by FastFrame resources and FastFrame applications need to make sure that their table and field names work in all databases. Many databases reserve words like ‘uid’, ‘user’, etc. for internal use, and forbid words that are SQL keywords (select, where, etc.). Also, all names should be lowercase, with underscores (’_’) to separate words, to avoid case sensitivity issues.

Other general guidelines: Table names should be plural (i.e. users); field names should be singular (i.e. user_name).

Regular Expression Use

Always use the preg_* functions if possible instead of ereg_* (and preg_split() instead of split()); they are included in PHP by default and much more efficient and much faster than ereg_*.

Never use a regular expression to match or replace a static string. explode() (in place of split()), str_replace(), strstr(), or strtr() do the job much more efficiently.

Parameter Passing

Objects should be passed by reference. Everything else, including arrays, should be passed by value wherever semantically possible.

[Zend Engine 2: objects should also be passed by value]

This practice takes full advantage of reference counting.

Long Lines

Wrap lines at 80 characters, including comments, unless this severely impacts the clarity of the code. Always wrap comments.

Line Breaks

Only use UNIX style of linebreak (\n), not Windows/DOS/Mac style (\r\n). Using vim, to convert from dos style type

:set ff=unix

Using vi, to convert from dos style type

:g/^M/s///g

(Note that the ^M is a control character, and to reproduce it when you type in the vi command you have to pad it first using the special ^V character.)

Array Definitions

When defining arrays, or nested arrays, use the following format:

$arrayname['index'] = array(
    'name1' => 'value1',
    'name2' => array(
        'subname1' => 'subvalue1',
        'subname2' => 'subvalue2'));

The only exception should be for empty arrays, which may be written on a single line such as:

$arrayname['index'] = array();

Internationalization (I18n)

Mark all strings presented to the user as gettext strings by calling the gettext shortcut function ( _() ):

    echo _('Hello world');

Don’t use the gettext functions for strings that will be written to a log file or otherwise presented to the administrator.

Error checking

FastFrame code should return a FF_Result object with the success flag set to false and the appropriate messages added to the object. For example:

$o_result =& new FF_Result();
$o_result->setSuccess(false);
$o_result->addMessage(_('Problems here.'));
return $o_result;

For these cases, use the following style of code block to check for success after any call which could generate an error condition:

$o_result =& $o_something->call('may error');
if (!$o_result->isSuccess()) {
    // Handle error condition.
} 
else {
    // Succeeded.
}

Existence checking

Often you’ll need to check whether or not a variable or property exists. There are several cases here:

a. If you need to know if a variable exists at all and is not null, use isset():

// Check to see if $param is defined.
if (isset($param)) {
    // $param may be false, but it's there.
}

b. If you need to know if a variable exists AND has a non-empty value (not null, 0, false, empty string or undefined), use !empty():

// Make sure that $answer exists, is not an empty string, and is not 0:
if (!empty($answer)) {
    // $answer has some non-false content.
} 
else {
    // (bool)$answer would be false.
}

As pointed out in the comment of the else clause, empty() essentially does the same check as isset() - is this variable defined in the current scope? - and then, if it is, returns what the variable would evaluate to as a boolean. This means that 0, while potentially valid input, is “empty” - so if 0 is valid data for your case, don’t use !empty().

c. If you know you are working with a mixed variable then using just isset() and empty() could cause unexpected results, for example if testing for a key and the variable is actually a string:

$foo = 'bar';
if (isset($foo['somekey'])) {
    // This will evaluate to TRUE!
}

If you know that there is a possibility of a mixed type variable the solution in this case would be to add an is_array() check in the if() statement.

d. Use array_key_exists() when you want to check if an array key is defined even if it has a value of null:

// Make sure we have a charset parameter. Value could also be null.
if (!array_key_exists('charset', $params)) {
    trigger_error('Incomplete configuration.');
}

Please note that array_key_exists() is a performance hit (25%-100%) and should only be used when necessary. Instead try to use !empty() or isset() instead.

Quotes

You should always use single quote (‘) characters around strings, except where double quote () characters are required. All literal strings should be in single quotes. A comparison of single and double quote usage follows:

Single Quotes:

  • Variables in the string are not parsed or expanded.
  • New line symbols can be included as literal line ends (not recommended).
  • To include a single quote character, escape it with a \ (backslash) character as in:
    echo 'Here\'s an example';
  • To specify a \ (backslash) character, double it:
    echo 'c:\\temp';

Double Quotes:

  • Parses and expands variables in the string.
  • Uses advanced (printf style) escape sequences like \n, \$, \t, etc.
  • Use with care, as many correct looking strings are really invalid. For example, the following are all incorrect:
echo "Today is the $date['day'] of $date['month']"
$_SESSION[index] = $_SESSION["old_index"];

define()

Surprisingly enough, define() is a somewhat slow function in PHP (as of PHP 4.3.x) so excessive use is discouraged.

Using define() in classes should be OK - we will sacrifice a tiny bit of speed for readability of code. For anything else, use your best judgment.

Optimizations

The following optimizations should be used, if possible:

  • loops: Make sure that you do not continue to define the same variable within a loop. Instead, declare the variable a single time before the loop is run.
 
coding_standards.txt · Last modified: 2005/07/06 15:44 by jrust
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki