CodingStandards

Contents

Preface

Most stuff was blatantly ripped from the following sources (amongst others):



Why are guidelines important?

First of all, let's make one point crystal clear: it doesn't matter what your guidelines are, so long as everyone understands and sticks to them. It's hard to work on a team where some persons use different coding standards.

It cannot be emphasised enough that guidelines are only useful if they are followed. It's no use having a definitive set of coding guidelines for a joint programming project if everyone continues to write in their own style regardless. It is arguable that you can get away with different coding styles if every team member works on a different section which is encapsulated and therefore their coding style doesn't affect the other developers. Unfortunately, this only holds true until a developer leaves and someone else has to take over their role.

If you are running a joint project, you might consider putting your foot down and basically refuse to accept any code that does not conform to your published guidelines, regardless of its technical merit (or lack thereof). This may sound somewhat draconian and off-putting to developers at first, but once everyone begins to code to the guidelines you'll find it a lot easier to manage the project and you'll get more work done in the same time. It will require a lot of effort from some of your developers who don't want to abandon their coding habits, but at the end of the day different coding styles will cause more problems than they're worth.

Guidelines

Here's some generic instructions on how to write readable, maintainable and acceptable code. These will also promote a consistent look and feel. Keep in mind that the code you're writing will probably be maintained by somebody else at some point. Try to be neat and kind to your fellow coders!


RTFM

Read The Fucking Manual. Really. All relevant stuff is in there. Including most of the practices below. This goes for both the PHP documentation, the MySQL documentation and the documentation of the framework you're using.

Make sure you read and understand the PHP language reference.

Some links to get you started:

Language

Within code use english everywhere!

Use English for names of variables, objects, methods, tables and fields etc. Write comments and commit messages in English too.

SCM

Always write a proper commit message when you are checking in your changes. If possible, refer to the (Trac) bug number that this commit solves.

Pattern

In general, we make use of the Model-View-Controller pattern whereever possible. Model-View-Controller separates the data (Model) from the user interface (View), so that changes to the user interface will not affect data handling, and that the data can be reorganized without changing the user interface. The model-view-controller solves this problem by decoupling data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller.

Code length

Prevent your code from being too long. If your function/method needs over 100 lines, it's a good candidate for refactoring. If your file is over 400 lines, it's a good candidate for refactoring.

Prevent large, cluttered files with lots of misc. junk code. It's completely unmaintainable and will cause lots of grief.

Commenting

Comments should be in English. C style comments (/* */) and standard C++ comments (//) are both fine. Use of Perl/shell style comments (#) is discouraged.

What

Each function/method should be preceded by a comment block in PHPDoc style. The columns of the parameter list should line up for readability!

Here's an example:

/**
 * Function to edit a single entry identified by an ID, sanitizing is done in the controller
 *
 * @param  int           $entryID integer to identify the entry to edit
 * @param  array       an array containing the fields of the entry
 *
 * @return   bool        true on success, false on error
 */
function updateEntry($entryID = 0, $data = array()) 
{
    // retrieve user profile
    $userdata = $user->get();
}

It's also a very good idea to comment separate pieces of code, eg. what is happening inside a loop, or why this method is called. These comments should be placed above the code statement, not behind it for better readability and consistency.

Never try to explain how your code works! Try to explain what your code is doing. Write code so that the working is obvious; it's a waste of time to explain badly written code.

When

Commenting can save a lot of time and grief. Comments are needed when:

  • There is a section that might become outdated (e.g. it fixes a problem for a current browser version)
  • There is a reason why you programmed something in one way while there might be better ones and you want to explain that. Use //FIXME: comments for that.
  • The code section is dependent on another script or gets parameters whose origin may not be obvious at first.

If you are creating a large class file, it can sometimes be a good idea to group and mark certain types of methods. This will make it later easier to spot the part where some maintenance is needed. And warns others to stay away from parts where they don't need to look.


NB: code that is commented out shouldn't be in SVN or CVS. If it's commented out, it's of no use to anybody (apart from being distractive). If your idea is that the code will be used again later, either retrieve it from SVN again at that later time, or document why this redundant info has a right to be in the SCM! For situations like this, document the commented out block with a // FIXME: construction.


Indenting

Also see the chapter below for more information.

  • Give your code a lot of breathing space. Use whitespace and newlines generously.
  • Use one statement per line.
  • Use tabs instead of spaces in the editor. Configure your editor to show tabs as four spaces
  • If possible, break long one-line statements into several statements
  • Break long paragraphs of text at 80 characters.

A bad example:

$data=$model->get($id);
for($i;$i<count($data);$i++){
    if(isset($data['title']))
        echo $data['title'];
    echo $data['content'].' posted at '.$data['postdate'];
}
unset($data);   

A good example, for better readability and maintainability:

$data = $model->get($id);

for ($i; $i < count($data); $i++) {

    if (isset($data['title'])) {
        echo $data['title'];
    }
    echo $data['content'].' posted at '.$data['postdate'];

}

unset($data);   


Quoting strings

Strings in PHP can either be quoted with single quotes ('') or double quotes (""). The difference between the two is that the parser will use variable-interpolation in double-quoted strings, but not with single-quoted strings. If your string contains no variables, use single quotes and save the parser the trouble of attempting to interpolate the string for variables, like so:

// Double quotes
$str = "Avoid this - it just makes more work for the parser.";

// Single quotes
$str = 'This is much better.';

Likewise, if you are passing a variable to a function, there is no need to use double quotes:

foo("$bar"); // No need to use double quotes
foo($bar); // Much better

Finally, when using associative arrays, you should include the key within single quotes to prevent any ambiguities, especially with constants:

$foo = $bar[example]; // Wrong: what happens if 'example' is defined as a constant elsewhere?
$foo = $bar['example']; // Correct: no ambiguity as to the name of the key

However, if you are accessing an array with a key that is stored in a variable, you can simply use:

$foo = $bar[$example];


Shortcut operators

The shortcut operators ++ and -- can be used on a line of their own. However, for readability, you might not want to. The reason for this is that this can cause obscure bugs that are incredibly difficult to track down. The exception here is loops. Example:

// Relies on $i being incremented after the expression is evaluated
$foo[$i++] = $j; 
// Relies on $j being decremented before the expression is evaluated
$foo[--$j] = $i; 

// Or these alternatives
// Obvious when $i is incremented
$foo[$i] = $j;
$i++; 

// Obvious when $j is decremented 
$j--;
$foo[$j] = $i; 

Optional shortcut constructs

As well as the useful increment and decrement shortcuts, there are two other ways in which you can make your PHP code easier to use. The first is to replace if statements where you are assigning one of two values to a variable based on a conditional. You may be tempted to write something like this:

if (isset($_POST['username'])) {
    $username = $_POST['username'];
} else {
    $username = ;
}

if (isset($_POST['password'])) {
    $password = md5($_POST['password']);
} else {
    $password = ;
}

Whilst the above code works and makes it obvious what you are doing, it's not the easiest or clearest way if you want to run through a list of different variables and do a similar thing to all of them. A more compact way would be to use the ternary operator ? : like so:

$username = isset($_POST['username']) ? $_POST['username'] : '';
$password = isset($_POST['password']) ? md5($_POST['password']) : '';

I would recommend using the latter notation wherever you are checking assigning a number of variables one of two values depending on a boolean expression, simply because it makes the code easier to scan and also makes it obvious what you are doing without being unnecessarily verbose.

Use constants where possible

If a value is not going to change throughout the execution of your script, then use a constant rather than a variable to define it. That way, if you do change the value by accident, the PHP parser will output an error and allow you to fix the problem, without it causing any unforeseen side effects.

Remember that constants should never be enclosed in strings, either single or double. You must always use concatenation if you wish to include a constant's value in a string.

Including code

Either use include_once or require_once. Learn the difference between include_once and require_once, and use each as appropriate.

  • Anywhere you are unconditionally including file, use require_once. A good example would be including a template.
  • Anywhere you are conditionally including a file use include_once.

Either of these will ensure that files are included only once. All include functions 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, require, include_once and require_once are statements, not functions. Parentheses should not surround the subject filename.

Turn on all error reporting

It is essential to eliminate all errors, warnings and notices that your code produces. Fixing errors and warnings may seem to be more important than fixing notices, but notices tell you that the code does not completely follow `best practices` or regulations.

Even on production servers it is a good idea to keep this setting intact. But instead of printing the messages in the browser, they should be logged in the background.

What you need to remember as a developer is that the person who uses your script may not have exactly the same php.ini configuration as you so you aim for the worst possible case, i.e. when some awkard person like me has all error reporting enabled. If your code works with E_ALL set, then it will also work with any other error reporting configuration, including when all error reporting is turned off (e.g. on sites where PHP errors are logged to a file instead).

It's not impossible to get scripts to work with all error reporting turned on. If you write proper object oreintated code and make sure that each class doesn't produce any errors, you should be able to make your program as a whole run without errors under normal circumstances.

Refactoring

Know when and how to refactor. Smelly code fragments are a good candidates for refactoring. Learn to identify smelly code and take appropriate measures.



Editor settings

Tabs v. spaces

  • use tabs to nest/indent your code
  • use spaces to align your comments
  • set your editor to use tabs in stead of spaces
  • recommended: use a tab setting of 4 spaces

Linefeeds

The three major operating systems (Unix, Windows and Mac OS) use different ways to represent the end of a line. Unix systems use the newline character (\n), Mac systems use a carriage return (\r), and Windows systems are terribly wasteful in that they use a carriage return followed by a line feed (\r\n).

We use the Unix-style linebreaks (\n). If you develop on Windows, either set up your editor to save files in Unix format or run a utility that converts between the two file formats.



Naming

Naming should always be unambiguous and concise. In general, keep the names of your functions, variables, etc. short and to the point. Prevent abbreviations and longvariablesthatnobodycanread.

Files

Files containing a class definition are prefixed with class. and are lowercase all the way without underscores.

/.
/..
/class.foo.php
/class.extendedfoo.php

All other files are named using all lowercase with underscores between the words.

The context of the file is put in front (e.g. profile, search, shops), followed by the actual action to be taken. This holds true for both controllers scripts and views.

/folders_list.php
/folders_branch.php
/folders_member.php
/folders_new.php
/folders_regional.php
...
/profile_create.php
/profile_update.php
/profile_show.php
/profile_delete.php
...

Using this scheme all actions for a context are grouped together and visible at once.

If there are many files you could also opt for putting the files into subdirectories, named like the prefix one would use otherwise:

/shops/list.php
/shops/new.php
/shops/regional.php
...
/profile/create.php
/profile/update.php
/profile/show.php
...

Classes

Classes are being named with UpperCamelCase.

class ExtendedFoo
{ ...  }

private methods and variables are being prefixed with an underscore.

class Foo
{
    var $public_property = true;
    var $_private_property = 'my private property';

    function publicMethod()
    {
        ...
    }

    function _privateMethod()
    {
        ...
    }
}

Functions and methods

Names of functions and methods are lowerCamelCase.

Make it as obvious possible what the function does from its name, whilst remaining reasonably concise. For example, niceFunctionWhichGetsUserDataFromAFile() would not be appropriate!

It should be possible to tell the main purpose of a function just by looking at the first line, e.g. getUserData($username).

Examples:

function getUserData($username)
{
    // retrieve some userdata
}
function validateFormData($formdata)
{
    // validate stuff
}

Variables, properties and function arguments

Variables (global or local), properties of objects and function arguments are all lowercase with underscore between the words.

Keep the names as short as possible while preserving the information what it is about.

class Videos
{
    var $default_type = 'movie';

    function retrieve($type = null)
    {
        if (is_null($type)) {
            $result = $this->_findVideos($this->default_type);
        } else {
            $result = $this->_findVideos($type);
        }

        return $result;
    }
}


$video_type = 'trailer';
$videos = new Videos();
$result = $videos->retrieve($video_type);

Loop variables

This is the only occassion where short variable names (as small as one character in length) are permitted, and indeed encouraged. Unless you already have a specific counting variable, use $i as the variable for the outermost loop, then go onto $j for the next most outermost loop etc. However, do not use the variable $l (lowercase 'L') in any of your code as it looks too much like the number 'one'.

Example of nested loops using this convention:

for ($i = 0; $i < 5; $i++) {
    for ($j = 0; $j < 4; $j++) {
        for ($k = 0; $k < 3; $k++) {
            for ($m = 0; $m < 2; $m++) {
                foo($i, $j, $k, $m);
            }
        }
    }
}

If, for some reason, you end up nesting loops so deeply that you get to $z, consider re-writing your code. If you use these guidelines in a joint project, you may way to impose an additional rule that states a maximum nesting of x levels for loops and perhaps for other constructs too.

Constants

Constants are all uppercase with underscores. php.net - define syntax

define('MAX_PAGES', 20);

true, false and null that are coming from PHP itself have to be lowercase. These are language constructs and not constants.



Code layout

Including braces

Braces should always be included when writing code using if, for, while etc. blocks. There are no exceptions to this rule, even if the braces could be omitted. Leaving out braces makes code harder to maintain in the future and can also cause bugs that are very difficult to track down.

Some examples of correct/incorrect ways to write code blocks using braces:

/* These are all incorrect */

if ( condition ) foo();

if ( condition )
    foo();

while ( condition )
    foo();

for ( $i = 0; $i < 10; $i++ )
    foo($i);

/* These are all correct */
 
if (condition) {
    foo();
}

while (condition) {
    foo();
}

for ($i = 0; $i < 10; $i++) {
    foo($i);
}

Where to put the braces

This is the standard for 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;
}

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

As said, you are strongly encouraged to always use curly braces. Having them increases readability and decreases the likelihood of logic errors being introduced when new lines are added.

Function declarations follow the "BSD/Allman style":

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.

Spaces between tokens

There should always be one space on either side of a token in expressions, statements etc. The only exceptions are commas and semi-colons which should have one space after, but none before. If they reside at the end of a line though, no space is following them.

Functions should follow the rules laid out already, i.e. no spaces between the function name and the opening bracket and no space between the brackets and the arguments, but one space between each argument.

Control statements such as if, for, while etc. may have one space on the left side of the opening bracket and one space after the closing bracket. Individual conditions inside these brackets (e.g. ($i < 9) || ($i > 16)) should not have spaces between their conditions and their opening/closing brackets.

Here some good and bad examples:

Wrong:

$i=0;
if(( $i<2 )||( $i>5 ))
foo ( $a,$b,$c )
$i=($j<5)?$j:5

Correct:

$i = 0; 
if (($i < 2) || ($i > 5)) 
foo($a, $b, $c) 
$i = ($j < 5) ? $j : 5

Operator precedence

I doubt very much that any developer knows the exact precedence of all the operators in PHP. Even if you think you know the order, don't guess because chances are you'll get it wrong and cause an unexpected bug that will be very difficult to find. Also, it will make maintaining your program a living nightmare for anyone who doesn't know the precedence tables in so much depth. Always use brackets to make it absolutely clear what you are doing.

Note: if your code looks as crappy as the example below, it's time to refactor!

// What *is* going on here?!?
$i = $j < 5 || $k > 6 && $m == 9 || $n != 10 ? 1 : 2; 
// Much clearer
$i = ((($j < 5) || ($k > 6)) && (($m == 9) || ($n != 10))) ? 1 : 2; 

Note: If you are using expressions like the one above you should split them up into smaller chunks if possible, even if you are already laying them out in the correct format. No-one should have to debug code like that, there's too many conditions and logic operators.



Queries

All SQL keywords and function calls have to be capitalised (SELECT, DELETE, FROM, WHERE, CASE, GETDATE()). Everything else may be left in the relevant case.

Indenting

Use indentation appropriately in order to distinguish different query parts. If you have complex queries use extra brackets and indentation to group conditions.

SELECT
    Product.ProductId,
    Product.ProductName,
    Product.UnitsInStock,
    Supplier.City,
    Category.Description
FROM
    Product
    LEFT JOIN Supplier ON Supplier.SupplierId = Product.SupplierId
    LEFT JOIN Category ON Category.CategoryId = Product.CategoryId
WHERE
    Product.UnitsInStock > 10
    AND (
        Supplier.City = 'London'
        OR Supplier.City = 'Dublin'
    )
    AND Category.Description IS NOT NULL
ORDER BY
    Product.UnitsInStock DESC,
    Supplier.City ASC,
    Category.Description ASC
LIMIT 10,20

Avoid aliasing

Use column and table aliasing only where absolutely necessary, and never as a means of reducing keystrokes, e.g.

SELECT
    Order.OrderId,
    Order.ShippedDate,
    Customer.ContactName,
    Customer.Address
FROM
    Order
    LEFT JOIN Customer ON Customer.CustomerId = Order.CustomerId

and not:

SELECT
    o.OrderId,
    o.ShippedDate,
    c.ContactName,
    c.Address
FROM
    Order o
    LEFT JOIN Customer c ON c.CustomerId = o.CustomerId

Comments

Its OK to put comments within a query. SQL allows for /* */ style comments and if you have to you may use them of course. Other than that, the same commenting rules apply.

Escape everything appropriately

While building queries its necessary to handle all variable values correctly according to their type.

If you have strings, use the best method available for your database-system to escape it (like mysql_real_escape_string()) in order to avoid injection. If the underlying framework has functionality for this in place use it.

If you have fieldnames that are the same as reserved words escape them accordingly (e.g. use backticks for MySQL). Also you may choose to escape all fieldnames consistently.

Query building

Also its wise to avoid string concatenation to glue a query together. It should be avoided in order to maintain readability. One can also use sprintf syntax to interpolate values into queries. If the underlying framework has handy stuff in place to build queries (CodeIgniter ActiveRecord e.g.), use it if possible.

Generally there are several distinct steps to be taken in order to build a query correctly:

  • validate your data
  • prepare your data
  • construct your query
  • execute the query
  • work on the results

where building the query and putting the data inside can often put together by means of string interpolation. In any case do put the query within a variable in order to enable better debugging possibilities and to improve readability.

Example:

// 1. Validate arguments
$username = isset($_POST['username']) ? $_POST['username'] : ; 
$sql_username = trim($username);

if (!empty($sql_username)) {
    return false;
}

// 2. prepare arguments
$sql_username = mysql_real_escape_string($sql_username);

// 3. construct the query
$query = "
    SELECT
        users.password
    FROM
        users
    WHERE
        users.username ='{$sql_username}'
";

// 4. execute the query
$result = mysql_query($query, $db_link);

// 5. work on the results
if (mysql_num_rows($result) == 0) {
    return false;
}

if ($row = mysql_fetch_assoc($result)) {
    if ($row['password'] == $password) {
        return true;
    } else {
        return false;
    }    
}


Example using a database wrapper to building the query and preparing the values for you:

// 1 Validate arguments
if (!is_string($username)) {
    return false;
}

// 2, 3 (prepare) and/or construct the query
$this->db->select('password');
$this->db->from('users');
$this->db->where('username', $username);

// 4 execute the query
$result = $this->db->get();

// 5 work on the results
if ($row = $result->row()) {
    if ($row->password == $password) {
         return true;
    } else {
         return false;
    }
} else {
    return false;
}



HTML & Templates

  • Templates are for display purposes only
  • Don't put view stuff within your business logic
  • Keep templates short and avoid deep nesting
  • Create valid markup
  • Escape output
  • Use a template engine or (in case of PHP) use alternative syntax

Since the main purpose of templates is to separate presentation from logic there is no excuse anymore to include HTML in your code.

To enforce this you can use a template engine. For Perl Template-Toolkit will do the job, in case of Java both JSP's or Velocity are fine. If it comes to PHP, PHP itself is fine, but alternatively you can use the simple template class from this article. In the guideline we will concentrate on PHP.

The example below is simply intolerable.

function echo_loginForm()
{

    echo '<form method="POST" action="login.php">';
    if ($_POST['username']) {
        echo '<input name="username" value="'.$_POST['username'].'">';
    } else {
        echo '<input name="username">';
    }
    echo '<input name="password" type="password"><input type="submit"></form>';
}


The way to go is to use templates in combination with the MVC pattern (see above). A simple action at least consists of a controller, a view and maybe a model. For example:

File: controller/user/details.php

<?php 

    require_once  'model/user.php';

    /**
      * Display user details page.
      */
    function main()
    {
        // Get user details and invoke view.

        $user_details = getUserDetails();

        require_once 'view/user/details.html';
    }

    main();
?>

File: view/user/details.html

<html>
       <head>
               <title>User details</title>

               <link rel="stylesheet" type="text/css" href="style.css" />
               <link rel="stylesheet" type="text/css" href="user/style.css" />
       </head>
       <body id="user-details">
 
               <h1><span>Userdetails</span></h1>
               <h2><span><?php echo $user_details->getName(); ?></span></h2>

               <ul id="menu">
                       <li id="item-user-details">
                               <a href="user/details.php"><span>Details</span></a>
                       </li>
                       <li id="item-reset-password">
                               <a href="user/reset_password.php"><span>Reset password</span></a>
                       </li>
               </ul>
 
               <dl id="user_properties">
                       <?php $properties = $user_details->getProperties(); ?>
                       <?php foreach( $properties as $name => $value ): ?>
                               <dt><?php echo $name; ?></dt>
                               <dd><?php echo htmlspecialchars( $value ); ?></dd>
                       <?php endforeach; ?>
               </dl>
       </body>
</html>


Templates

Just like the rest of your code, templates should be readable. Keep them short and try to avoid deep nesting. Deep nesting and lengthy templates are good candidates for refactoring. Over here the rule is as well: whitespace is your friend. Use tabs for nesting and spaces for alignment.

Don't tear html elements apart and put them into different views! The beginning and the end of a html element should be kept within the same template block in order to avoid confusion.

Create views that contain one contextual block (e.g. a template for the navigation, one for the <head> section and so on). Such blocks should contain both the starting and the closing tag of an element.

PHP

Use PHP alternative PHP syntax and verbose processing instructions (not the shorthands).

For example:

<h3><span><?php echo htmlspecialchars($title); ?></span></h3>
<?php foreach($paragraphs as $paragraph): ?>
        <p><?php echo $paragraph; ?></p>
<?php endforeach; ?>


Escaping output

Note the use of htmlspecialchars. In the example above it is used for the title, but not for the paragraph, since our paragraph might contain markup, but our title shouldn't. Use escaping (e.g. htmlspecialchars) when necessary. If you are not sure it's probably best to use it always. Output that should be escaped but is not will break stuff. Output which is escaped but should not looks crappy but does not break stuff.


Refactoring templates

If templates become to lengthy or certain parts are redundant; refactor!

Refactor, refactor! However take good care of the structure of templates. Again a template should contain a single block/view. That is a title, a menu or a table for example.

Bad, templates start and end just anywhere:

<?php require_once 'view/include/header.html'; ?>
<body onload="setup();">
        <ul>
                <?php echo $items; ?>
        </ul>
        <h1>Hello</h1>
        <p>It works.</p>
<?php require_once 'view/include/footer.html'; ?>


Good:

<html>
        <?php require_once 'view/include/head.html'; ?>
        <body onload="setup()">
               <?php require_once 'view/include/nav.html'; ?>
               <h1>Hello</h1>
               <p>It works.</p>
               <?php require_once 'view/include/disclaimer.html'; ?>
       </body>
</html>

Note that the above seems to imply that you have to write the structure of your pages over and over. However this is not the case, using a simple but efficient way of wrapping you can avoid this:

<?php // user/details.php
function userDetails()
{
   $main = '/view/user/details.html';

    require_once 'view/include/master.html';
}
?>
<html>
    <head>
        <title><?php echo $title; ?></title>
    </head>
    <body>
        <?php require_once 'view/include/nav.html'; ?>
        <?php require_once $main; ?>
    </body>
</html>

Bad, not a single view:

<tr>
       <th>Name</th>;
       <th>Role</th>
</tr>
<?php foreach( $users as $user ): ?>
       <tr>
               <td><?php echo $user->getName(); ?></td>
               <td><?php echo $user->getRole(); ?></td>
       </tr>
<?php endforeach; ?>


Good:

<table id="users">
       <tr>
               <th>Name</th>
               <th>Role</th>
       <</tr>
       <?php foreach( $users as $user ): ?>
               <tr>
                       <td><?php echo $user->getName(); ?></td>
                       <td><?php echo $user->getRole(); ?></td>
               </tr>
       <?php endforeach; ?>
</table>


Bad, $items contains one or even more views, and where did it come from?

<ul id="menu">
       <?php echo $items; ?>
</ul>


HTML and CSS - Creating valid markup

HTML should be as semantic as possible, styling should be done using CSS.

Use a doctype if possible and stick with it. Further reading on which doctype to choose:

With the doctype in mind, create valid markup! When using xhtml for example always close tags and take care of script tags with <![CDATA[ ]]> sections.

Validate the document via an online validator (http://validator.w3.org/).

Using 'id' and 'class' attributes allow HTML to be styled in a clear and flexible way. It is important to know the difference between class and id, since both can be used to identify elements in a stylesheet and might be confused.

Ids identify a specific element and must be unique on the page. A class marks an element as member of a group and may be used multiple times. So if you want to define a style for multiple elements (such as typematic definitions) it always should be defined by a 'class'. For example:

<body id="login-page">
       <div class="Container">
 
               <ul id="menu">
                       <li id="item-login" class="left">
                               <a href="login"><span>login</span></a>
                       </li>
                       <li id="item-about" class="center">
                               <a href="about"><span>about</span></a>
                       </li>
                       <li id="item-contact" class="right">
                               <a href="contact"><span>contact</span></a>
                       </li>
               </ul>
  
               <h1><span>Login</span></h1>
 
               <form id="login-form">
                       <dl>
                               <dt class="top">Username</dt>
                               <dd class="top"><input class="text-box"
                                      name="username"
                                      value="<?php echo htmlspecialchars($username) ?>" /></dd>

                               <dt class="middle">Password</dt>
                               <dd class="middle"><input class="text-box"
                                      name="username"
                                      type="password" /></dd>

                               <dt class="bottom"></dt>
                               <dd class="bottom"><input class="button"
                                      value="Login"
                                      type="submit" /></dd>
                       </dl>
               </form>
       </div>
</body>

The example above contains a few noteworthy concepts.

Use of class and id. A class defines a type or a property of an element. To create separate styling for the first and last menu items these simply can be assigned class 'left' or 'right'. Another interesting concept is that the id's and classes given can be used to style the current item different from the rest.

#menu li {
    border-left: solid 1px black;
    border-right: solid 1px black;
}

#menu li.left  { border-left: none; }
#menu li.right { border-right: none; }

#login-page #item-login { font-size: 200%; }


Links

Interesting (and recommended) reads on HTML and CSS:



Javascript

  • Prevent inline Javascript functions; place them within in a .js file
  • When using an XHTML doctype, make sure you embed your javascript inside <![CDATA[ ]]>