Difference between revisions of "Coding style"

Jump to: navigation, search
(Document which versions new APIs were added in)
(TODO comments must link to a tracker issue)
Line 550: Line 550:
 
// TODO MDL-123 need a better algorithm here.
 
// TODO MDL-123 need a better algorithm here.
 
</code>
 
</code>
comments that mark things in the code that are incomplete. However, every TODO in the code must have an associated task in the http://tracker.moodle.org/ tracker] and the tracker issue may not be resolved while there are still related TODOs in the code.
+
comments that mark things in the code that are incomplete. However, every TODO in the code must have an associated task in the [http://tracker.moodle.org/ tracker] and the tracker issue may not be resolved while there are still related TODOs in the code.
  
 
If you have a big task that is nearly done, apart a few TODOs, and you really want to mark the big task as finished now. You first need to file new tracker tasks for each TODO and change the TODOs comments to point at the new issue numbers.
 
If you have a big task that is nearly done, apart a few TODOs, and you really want to mark the big task as finished now. You first need to file new tracker tasks for each TODO and change the TODOs comments to point at the new issue numbers.

Revision as of 02:19, 13 July 2009

Overview

Scope

This document describes style guidelines for developers working on or with Moodle code. It talks purely about the mechanics of code layout and the choices we have made for Moodle.

For details about using the Moodle API to get things done, see the coding guidelines.

Goals

Consistent coding style is important in any development project, and particularly when many developers are involved. A standard style helps to ensure that the code is easier to read and understand, which helps overall quality.

Abstract goals we strive for:

  • simplicity
  • readability
  • tool friendliness, such as use of method signatures, constants, and patterns that support IDE tools and auto-completion of method, class, and constant names.

When considering the goals above, each situation requires an examination of the circumstances and balancing of various trade-offs.

Note that much of the existing Moodle code may not follow all of these guidelines - we continue to upgrade this code when we see it.

File Formatting

PHP tags

Always use "long" php tags. However, to avoid whitespace problems, DO NOT include the closing tag at the very end of the file.

<?php
 
include('config.php');

Indentation

Use an indent of 4 spaces with no tab characters. Editors should be configured to treat tabs as spaces in order to prevent injection of new tab characters into the source code.

Don't indent the main script level:

GOOD:

<?php
$a = required_param('a', PARAM_INT);
if ($a > 10) {
    call_some_error($a);
} else {
    do_something_with($a);
}

BAD:

<?php
    $a = required_param('a', PARAM_INT);
    if ($a > 10) {
        call_some_error($a);
    } else {
        do_something_with($a);
    }

Maximum Line Length

The key issue is readability.

Aim for 80 characters if it is convenient, but lines up to 120 characters are fine. It's very unusual to need more.

Wrapping Arrays

Use a break after each key=>pair or after every few array elements, always after a comma, lining up with the first element with an indent of 8 spaces, like this:

$plugin_info['preferences'][$plugin] = array(
        'id' => $plugin, 
        'link' => $pref_url, 
        'string' => $modulenamestr);

Wrapping function declarations

If you have many parameters, indent them in line with the first parameter:

public function graded_users_iterator($course, $grade_items = null, $groupid = 0,
                                      $sortfield1 = 'lastname', $sortorder1 = 'ASC',
                                      $sortfield2 = 'firstname', $sortorder2 = 'ASC') {

Wrapping Control Structures

If you have too many conditions in one control structure, try setting some variables before the start of the structure to improve readability.

GOOD:

$coursecategory = $element['object']->is_course_item() or $element['object']->is_category_item();
$scalevalue = in_array($element['object']->gradetype, array(GRADE_TYPE_SCALE, GRADE_TYPE_VALUE));
 
if ($coursecategory and $scalevalue) {

BAD:

if (($element['object']->is_course_item() or $element['object']->is_category_item())
    and ($element['object']->gradetype == GRADE_TYPE_SCALE
    or $element['object']->gradetype == GRADE_TYPE_VALUE)) {

Line Termination

Use standard Unix text format. Lines must end only with a linefeed (LF). Linefeeds are represented as ordinal 10, or hexadecimal 0x0A.

Do not use carriage returns (CR) like Macintosh computers (0x0D).

Do not use the carriage return/linefeed combination (CRLF) as Windows computers (0x0D, 0x0A).

Lines should not contain trailing spaces. In order to facilitate this convention, most editors can be configured to strip trailing spaces, such as upon a save operation. However, if you are editing an existing Moodle file and are planning to submit your changes to CVS, please switch off that feature so that whitespace changes do not pollute CVS history (other developers will have trouble viewing what you've done if every other line has been edited for whitespace).

Naming Conventions

Filenames

Filenames should :

  • be whole english words
  • be as short as possible
  • use lowercase letters only
  • end in .php, .html, .js, .css or .xml

Classes

Class names should always be lowercase english words, separated by underscores:

class some_custom_class {
    function class_method() {
        echo "foo";
    }
}

Functions and Methods

Function names should be simple English lowercase words, and start with the name of the module to avoid conflicts between modules. Words should be separated by underscores.

Verbosity is encouraged: function names should be as illustrative as is practical to enhance understanding.

Note there is no space between the function name and the following (brackets).

function forum_set_display_mode($mode = 0) {
    global $USER, $CFG;
 
    if ($mode) {
        $USER->mode = $mode;
    } else if (empty($USER->mode)) {
        $USER->mode = $CFG->forum_displaymode;
    }
}

Function Parameters

Parameters are always simple lowercase English words (sometimes more than one, like $initialvalue), and should always have sensible defaults if possible.

Use "null" as the default value instead of "false" for situations like this where a default value isn't needed.

public function foo($required, $optional = null)

However, if an optional parameter is boolean, and its logical default value should be true, or false, then using true or false is acceptable.

Variables

Variable names should always be easy-to-read, meaningful lower-case English words. If you really need more than one word then run them together, but keep them short as possible. Use plural names for arrays of objects.

GOOD: $quiz
GOOD: $errorstring
GOOD: $assignments (for an array of objects)
GOOD: $i (but only in little loops)
BAD: $Quiz
BAD: $camelCase
BAD: $aReallyLongVariableNameWithoutAGoodReason
BAD: $error_string

Core global variables in Moodle are identified using uppercase variables (ie $CFG, $SESSION, $USER, $COURSE, $SITE, $PAGE, $DB and $THEME). Don't create any more!

Constants

Constants should always be in upper case, and always start with the name of the module. They should have words separated by underscores.

define('FORUM_MODE_FLATOLDEST', 1);

Booleans and the null Value

Use lower case for true, false and null.


Strings

Since string performance is not an issue in current versions of PHP, the main criteria for strings is readability.

Single quotes

Always use single quotes when a string is literal, or contains a lot of double quotes (like HTML):

$a = 'Example String'; 
echo '<span class="'.s($class).'"></span>'; 
$html = '<a href="http://something" title="something">Link</a>';

Double quotes

These are a lot less useful in Moodle.

Use double quotes when you need to include plain variables or a lot of single quotes. In Moodle 2.0 or later you won't need to be doing a lot of single quotes for SQL so that's not an issue.

echo "<span>$string</span>"; 
$statement = "You aren't serious!";

Variable substitution

Variable substitution can use either of these forms:

$greeting = "Hello $name, welcome back!";
 
$greeting = "Hello {$name}, welcome back!";

String concatenation

Strings must be concatenated using the "." operator.

$longstring = $several.$short.'strings';

If the lines are long, break the statement into multiple lines to improve readability. In these cases, put the "dot" at the end of each line.

$string = 'This is a very long and stupid string because '.$editorname.
          " couldn't think of a better example at the time.";

Arrays

Numerically indexed arrays

Negative numbers are not permitted as indices.

An indexed array may start with any non-negative number, however all base indices besides 0 are discouraged.

When declaring indexed arrays with the array function, a trailing space must be added after each comma delimiter to improve readability:

$myarray = array(1, 2, 3, 'Stuff', 'Here');

Multi-line indexed arrays are fine, but pad each successive lines as above with an 8-space indent:

$myarray = array(
        1, 2, 3, 'Stuff', 'Here',
        $a, $b, $c, 56.44, $d, 500);

Associative arrays

Use multiple lines if this helps readability. For example:

$myarray = array(
    'firstkey' => 'firstvalue',
    'secondkey' => 'secondvalue'
);

Classes

Class declarations

  • Classes must be named according to Moodle's naming conventions.
  • The brace should always be written on the line beside the class name.
  • Every class must have a documentation block that conforms to the PHPDocumentor standard.
  • All code in a class must be indented with 4 spaces.
  • Only one class is permitted in each PHP file.
  • Placing additional code in class files is permitted but discouraged. In such files, two blank lines must separate the class from any additional PHP code in the class file.
An example:
/**
 * Documentation Block Here
 */
class sample_class {
    // all contents of class
    // must be indented 4 spaces
}

Class member variables

Member variables must be named according to Moodle's variable naming conventions.

Any variables declared in a class must be listed at the top of the class, above the declaration of any methods.

The var construct is not permitted. Member variables always declare their visibility by using one of the private, protected, or public modifiers. Giving access to member variables directly by declaring them as public is permitted but discouraged in favor of accessor methods (set/get).

Functions and methods

Function and method declaration

Functions must be named according to the Moodle function naming conventions.

Methods inside classes must always declare their visibility by using one of the private, protected, or public modifiers.

As with classes, the brace should always be written on same line as the function name.

Don't leave spaces between the function name and the opening parenthesis for the arguments.

The return value must not be enclosed in parentheses. This can hinder readability, in additional to breaking code if a method is later changed to return by reference.

/**
 * Documentation Block Here
 */
class sample_class {
 
    /**
     * Documentation Block Here
     */
    public function sample_function() {
        // all contents of function
        // must be indented four spaces
        return true;
    }
}

Function and method usage

Function arguments should be separated by a single trailing space after the comma delimiter.

threeArguments(1, 2, 3);

Control statements

In general, use white space liberally between lines and so on, to add clarity.


If / else

Put a space before and after the control statement in brackets, and separate the operators by spaces within the brackets. Use inner brackets to improve logical grouping if it helps.

Indent with four spaces.

Don't use elseif !

Always use braces (even if the block is one line and PHP doesn't require it).

if ($x == $y) {
    $a = $b;
} else if ($x == $z) {
    $a = $c;
} else {
    $a = $d;
}

Switch

Put a space before and after the control statement in brackets, and separate the operators by spaces within the brackets. Use inner brackets to improve logical grouping if it helps.

Always indent with four spaces. Content under each case statement should be indented a further four spaces.

switch ($something) {
    case 1:
        break;
 
    case 2:
        break;
 
    default:
        break;
}


Foreach

As above, uses spaces like this:

foreach ($objects as $key => $thing) {
    process($thing);
}

Require / include

Each file should start by including the main config.php file.

require_once('../config.php');

Any other include/require should use an absolute path beginning with $CFG->dirroot or $CFG->libdir, not relative includes, which sometimes behave strangely under PHP.

Includes should generally only be done at the top of files or inside functions/methods that need them, it's insecure to use include/require in the middle of file in global scope.

Documentation and comments

Inline documentation explains the code flow and the purpose of functions and variables. Use it whenever practical.

Moodle uses the phpDoc format. This allows our code documentation to be generated automatically (see phpdocs.moodle.org.

Inline comments

Inline comments should use the // style, laid out neatly so that it fits among the code and lines up with it.

function forum_get_ratings_mean($postid, $scale, $ratings = null) {
    if (!$ratings) {
 
        $ratings = array();     // Initialize the empty array
 
        $rates = $DB->get_records('forum_ratings', array('post' => $postid));
 
        // Process each rating in turn
        foreach ($rates as $rate) {
            ...
        }
 
        // Do something else here 
        something_else();
 
     ... etc.

Files

All files that contain PHP code should contain a full GPL copyright statement at the top, plus a separate docblock right under it containing a:

  1. short one-line description of the file
  2. longer description of the file
  3. @package tag, describing the part of Moodle this part of
  4. @copyright tag, with year and copyright holder (creator) of the original file
  5. @license tag, which must contain "http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later"
<?php
 
// This file is part of Moodle - http://moodle.org/
//
// Moodle 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 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 
/**
 * This is a one-line short description of the file                    (1)
 *
 * You can have a rather longer description of the file as well,
 * if you like, and it can span multiple lines.                        (2)
 *
 * @package   moodlecore                                               (3)
 * @copyright 2008 Kim Bloggs                                          (4)
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later (5)
 */

Packages

The package keyword MUST be included and tags a file as being part of a group of files. Conventions are:

  1. If it's part of Moodle core libraries, use moodlecore
  2. If it's part of a plugin, use the path of the plugin with hyphens: eg mod-forum or grade-report-visual
  3. Unit test code should be placed in the same package as the code being tested.

Classes

All classes should have a docblock with the following minimum information:

/**
 * Short description for class                                          (1)
 *
 * Long description for class (if any)...                               (2)
 *
 * @copyright 2008 Kim Bloggs                                           (4)
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later  (5)
 */

Functions

All functions and methods should have a docblock like this:

/**
 * The description should be first, with asterisks laid out exactly
 * like this example. If you want to refer to a another function,
 * do it like this: {@link clean_param()}. Then, add descriptions
 * for each parameter and the return value as follows.
 *
 * @param int   $postid The PHP type is followed by the variable name
 * @param array $scale The PHP type is followed by the variable name
 * @param array $ratings The PHP type is followed by the variable name
 * @return mixed
 */

Document which versions new APIs were added in

When adding a new classes or function to the Moodle core libraries (or adding a new method to an existing class), use a @since tag to document which version of Moodle it was added in. For example

/**
 * ...
 * @since Moodle 2.0
 */

When deprecating an old API, use a @deprecated tag to document which version of Moodle it was deprecated in. For example

/**
 * ...
 * @deprecated Moodle 2.0. Please do not call this function any more.
 *             Use {@link new_function()} instead.
 */

If it is important that developers update their code, consider also adding a debugging('...', DEBUG_DEVELOPER); call to repeat the deprecated message. If the old function can no longer be supported at all, you may have to throw a coding_exception. There are examples of the various options in lib/deprecatedlib.php.

TODO comments must link to a tracker issue

You may use

// TODO MDL-123 need a better algorithm here.

comments that mark things in the code that are incomplete. However, every TODO in the code must have an associated task in the tracker and the tracker issue may not be resolved while there are still related TODOs in the code.

If you have a big task that is nearly done, apart a few TODOs, and you really want to mark the big task as finished now. You first need to file new tracker tasks for each TODO and change the TODOs comments to point at the new issue numbers.

Exceptions

Use exceptions to report errors, especially in library code.

Throwing an exception has almost exactly the same effect as calling print_error, but it is more flexible. For example, the caller can choose to catch the exception and handle it in some way. It also makes it easier to write unit tests.

Any exception that is not caught will trigger an appropriate call to print_error, to report the problem to the user.

Do not abuse exceptions for normal code flow. Exceptions should only be used in erroneous situations.

Exception classes

We have a set of custom exception classes. The base class is moodle_exception. You will see that the arguments you pass to new moodle_exception(...) are very similar to the ones you would pass to print_error. There are more specific subclasses for particular types of error.

To get the full list of exception types, search for the regular expression 'class +\w+_exception +extends' or ask your IDE to list all the subclasses of moodle_exception.

Where appropriate, you should create new subclasses of moodle_exception for use in your code.

A few notable exception types:

moodle_exception 
base class for exceptions in Moodle. Use this when a more specific type is not appropriate.
coding_exception 
thrown when the problem seems to be caused by a developer's mistake. Often thrown by core code that interacts with plugins. If you throw an exception of this type, try to make the error message helpful to the plugin author, so they know how to fix their code.
dml_exception (and subclasses) 
thrown when a database query fails.
file_exception 
thrown by the File API.

Credits

This document was drawn from the following sources:

  1. The original Coding guidelines page
  2. The Zend guidelines and
  3. Feedback from all core Moodle developers

See also

  1. Coding
  2. CodeSniffer