1 Indenting
Use tab indents at line beginnings. A tab is expected to represent four spaces. For inline spacing, use spaces, not tabs.
if (condition) {
action; // indented with one tab
}
$foo = "far"; //lined up with spaces
$foo_bar = "foobar"; //lined up with spaces
Since inline content is lined up with spaces, a mono spaced font is always used when editing code.
2 Control Structures
These include if, for, while, switch, etc. Here is an example if statement, since it is the most complicated:
if ((condition1) || (condition2)) {
action1;
} elseif ((condition3) && (condition4)) {
action2;
} else {
defaultaction;
}
Note the use of 'elseif', not 'else if'.
Multi-line if conditions are braced this way:
if ((condition1) || (condition2) || (condition3) ||
(condition4)) {
action1;
}
Control statements have one space between the control keyword and opening parenthesis, to distinguish them from function calls.
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, cases are indented one level. Case actions are indented two levels.
switch (condition) {
case 1:
action1;
break;
case 2:
action2;
break;
default:
defaultaction;
break;
}
3 Function Calls
Functions are 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 is 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, using spaces not tabs, may be inserted to promote readability:
$short = foo($bar); $long_variable = foo($baz);
If assigning a reference to a variable, place the ampersand next to the referenced object, not the equal sign:
$reference = &$foo; $reference = &foo();
4 Function and Class Definitions
Function declarations follow the "one true brace" convention:
function foo_function($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 on the current page begin with a _ character (e.g. _example_function), and placed at the bottom of the page. This helps distinguish functions defined on the current page from user-defined functions in included files.
Class declarations also follow the one true brace convenction:
class MyObject
{
//....
}
5 Naming Libraries and Classes
Function libraries and user-defined class files are placed in the /includes/ directory of the application.
Function and configuration files are named with all lowercase letters and underscores, following the same rules as function names Example: /includes/store_functions.php.
Class files are named [ObjectName].class.php, following the same rules as class names. If the class is extended, the extending files are stored in a directory under /includes/ with the same name as the original object. Subclasses follow the exact same naming requirements.
Tester scripts are named [ObjectName].test.php
Common user defined functions are stored in /includes/base.functions.php
6 Comments
Inline documentation for classes follows the Javadoc convention.
6.1 Comments for Functions
Static functions are commented like this:
/** * Description of function. * * @param datatype $variablename Description of variable. * @param datatype $variable2name Description of variable2. * @return datatype Description of return value. */
6.2 Comments for Classes
The class header block at the top of the class file are commented like this:
/** * ObjectName - description * * Copyright 1999-2005 iMarc LLC * * @version 0.0.2 * * @author Original Author [initials] <author@example.com> * @author Your Name [initials] <you@example.com> * * @todo description * * @changes 0.0.2 Description [initials, YYYY-MM-DD] * @changes 0.0.1 Description [initials, YYYY-MM-DD] */
Any edit that noted in the changelog requires new authors to add their name and initials to the @authors list
Comment class variables like this:
/** * Variable description * * @var datatype */
Class methods are commented similar to functions, with some additional information.
/** * The description of the method goes here. * * @since version number * * @param datatype $variablename Description of variable. * @param datatype $variable2name Description of variable2. * @return datatype Description of return value. */
6.3 Versioning
All class files are versioned with three revision numbers.
[major].[minor].[bugfix]
- [bugfix] increases if a bug has been fixed, but no new feature has been added
- [minor] increases if a new feature has been added while maintaining backward compatibility
- [major] increases if backward compatibility breaks or a number of major features have been added
7 Including Code
With the exception of HTML and template files, included files 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.
If you are dynamically including a filename, or want the code to only be used conditionally (an optional template), use include.
8 PHP Code Tags
In class files, 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.
On general pages it's OK to use shorthand tags (<?= $var ?>), but keep in mind that using shorthand tags makes your code less portable with short_open_tag turned off.
Break out of PHP if the majority of line is outputting HTML or text.
<?php
// do stuff in PHP
?>
Are you sure that you want to delete <?= $thing ?>
<?php
// more php
?>
If an opening tag is printed outside of PHP, it's closing counterpart is output the same way.
<table>
<tr>
<?php
// do stuff in PHP
?>
<tr>
<table>
9 Header Comment Blocks
All other source code files contain the following comment block as the header:
/* --------------------------------------------------------------------- */ /* (optional) Page description /* /* @author Original Author [initials] <user@example.com> /* @author New Author [initials] <user@example.com> /* --------------------------------------------------------------------- */
Generally, page skeletons should follow this structure:
- header comment block
- requires, object initiation
- template, print header
- body comment block
- body
- footer comment block
- print footer
<?php
/* --------------------------------------------------------------------- */
/* @author Dave Tufts [dt] <dave@imarc.net>
/* --------------------------------------------------------------------- */
require_once($_SERVER['DOCUMENT_ROOT'] . "/includes/init.php");
$db = new Database();
$session = new Session();
$template = new Template("template", "Title");
$template->printHeader();
/* --------------------------------------------------------------------- */
/* Body
/* --------------------------------------------------------------------- */
?>
content...
<?php
$foo = (isset($_REQUEST['foo'])) ? $_REQUEST['foo'] : '';
$error = '';
?>
<?php
/* --------------------------------------------------------------------- */
/* Footer
/* --------------------------------------------------------------------- */
$template->printFooter();
?>
10 Example URLs and IPs
Use example.com for all example URLs, per RFC 2606.
Use the IP range 192.0.2.0/24 for all example IP addresses, per RFC 3330. If you just need a single IP address use 192.0.2.1
11 php.ini settings
All code must work with register_globals disabled. This means using $_COOKIE, $_SESSION, $_SERVER and $_ENV to access all cookie, session, server and environment data, respectively.
To retrieve submitted data, you can use $_GET, $_POST or $_REQUEST
All class files must work with error_reporting = E_ALL and E_STRICT. Failure to do so would result in ugly output, error logs getting filled with lots of warning messages, or even downright broken scripts.
No code assumes that '.' is in the include path. The preferred way to include a file is to specify it's full server path using DOCUMENT_ROOT:
require_once($_SERVER['DOCUMENT_ROOT'] . "/path/to/file.php");In certain cases a relative path is needed. Always specify './' in front of a filename when you are including a file in the same directory.
12 XHTML 1.0 Compliance
All tag names and parameters must be lower case including javascript event handlers:
<div style="color:#000;">...</div> <a href="http://example.com" onmouseover="status=''" onmouseout="status=''">...</a>
All tag parameters must be of a valid parameter="value" form (numeric values must also be surrounded by quotes). For parameters that had no value in HTML, the parameter name is the value. For example:
<input type="checkbox" checked="checked" />
<select name="example">
<option selected="selected" value="1">Example</option>
</select>
<td nowrap="nowrap">Example</td>
All tags must be properly closed. Tags where closing is forbidden must end with a space and a slash:
<br /> <hr /> <img src="example.gif" alt="Example" /> <input type="submit" value="Example" />
All form definitions must be on their own line and either fully defined within a <td></td> pair or be outside table tags. Forms must also always have an action parameter:
<form action="http://example.com/example.cgi" method="post">
<table>
<tr><td>example</td></tr>
</table>
</form>
<table>
<tr>
<td>
<form action="/foo.php" method="get">
</form>
</td>
</tr>
</table>
All JavaScript tags must have a valid type parameter:
<script 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:
<img src="/images/foo.gif" alt="Foo" />
Input fields of type "image" also require an alt attribute, but do not allow the border attribute.
External cascading style sheets are save in the /css/ directory for that site
External javascript files are save in the /js/ directory for that site
Images are saved in the /images/ directory for that site. If desired, images can be broken up into sub-directories, all under the main /images/ directory
13 Database Naming Conventions
Name your database after the primary domain it serves. Since database names can't contain periods, replace the domain's period(s) with underscores.
Domain: example.com Database Name: example_com Domain: wiki.example.com Database Name: wiki_example_com
All database tables 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.).
All names (database, table, and column names) are lowercase, with underscores ('_') to separate words, to avoid case sensitivity issues.
Table names are plural (users).
Column names are singular (user_name).
The primary key column is named the singular of table name followed by _id:
Table Name: users Primary Key: user_id
14 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(), strpos(), or strtr() do the job much more efficiently.
15 Parameter Passing
Objects are passed by reference. Everything else, including arrays, is passed by value wherever semantically possible.
[Zend Engine 2: objects are also be passed by value]
This practice takes full advantage of reference counting.
16 Long Lines
Wrap comments and SQL statements at 80 characters. Try to keep lines of code and HTML as clear and readable as possible.
17 Line Breaks
Only use UNIX style of line-break (\n), not Windows/DOS/Mac style (\r\n).
Using vi, to convert from DOS style type:
:g/^M/s///g
Using Dreamweaver:
Under the "Preferences" menu,
select the category, "Code Format".
Select "LF (Unix)" as the line break type.
18 Private Variables
In PHP 5, make all class variables private or protected (unless there's a really good reason not to). Create setXxx() methods to set private class variables, and getXxx() methods to retrieve their data
class Foo {
private $bar;
public setBar($in) {
$this->bar = $in;
}
public getBar() {
return $this->bar;
}
}
19 Array Definitions
When defining arrays, or nested arrays, use the following format, where indentation is noted via the closing parenthesis characters:
$arrayname['index'] = array(
'name1' => 'value1',
'name2' => array(
'subname1' => 'subvalue1',
'subname2' => 'subvalue2'
)
);
The only exception is for empty or short arrays that fit on one line, which may be written as:
$arrayname['index'] = array();
20 Error checking
Where possible, use try/catch blocks.
try {
if (empty($foo)) {
throw new Exception ("Error message");
}
...
} catch (Exception $e) {
echo $e->getMessage();
}
For simple checks, use the variable $error to flag errors. On any page that checks for $error set $error at the top of the page:
$error = '';
...
if ($error) {
action
}
21 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)) { }
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.
22 Quotes
Use your judgement when quoting strings. The following are all considered good practice at iMarc.
$foo = "value";
$foo = "Isn't it neat?";
$foo = 'Bob said, "I like that"';
$foo = "Name\tEmail\tZip\n";
echo "Hello World";
echo 'Hello World';
$foo['bar'] = "someval";
if ($var == 'something') { action; }
$db->simpleSelect('*', 'table', 'this', 'that');
PHP does treat single quotes and double quotes differently:
- 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'; - Backslash (
\) characters do not need to be escaped when single quoted:echo 'c:\\temp';
- Double Quotes:
-
- Parses and expands variables in the string.
- Uses advanced (sprintf-style) escape sequences like
\n,\$,\t, etc. - Should be used in the gettext shortcut
_("")format. - Use with care, as many correct looking strings are really invalid.
- To specify a
\(backslash) character in a double quoted string, escape it with another backslash::echo "c:\\\\temp";
23 define()
Constants that are set in an included file (/includes/config/local.config.php, for example), use ALL CAPITAL LETTERS. Constants defined on an individual page, use all capital letters preceded by an underscore. The preceding underscore tells future developers that it's defined on the current page
define("MY_VARIABLE", "foo"); // defined in included file
define("_MY_VARIABLE", "foo"); // defined on current page
24 Optimizations
The following optimizations are used, if possible:
24.1 Concatenate strings
Building a string with concatenation (the "." operator) using single-quoted strings and variables is faster than using an interpolated string (a string inside double quotes with variables inside the string itself).
That said, iMarc implements concatenation using double-quoted strings. Concatenation is easier to read than embedding variables when auditing code for logic and security problems.
24.2 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.
$entries = array(...);
// slower
for ($i = 0; $i < count($entries); ++$i) {
echo $entries['foobar'];
}
// faster
$length = count($entries);
$foobar = $entries['foobar'];
for ($i = 0; $i < $length; ++$i) {
echo $foobar;
}
With large arrays, array_key_exists() seems very slow.
// slower (with large arrays)
if (array_key_exists($key, $array)) { ... }
// faster
if (is_array($array) && isset($array[$key])) { ... }
25 Setting Variables
For security and readability, set all non-superglobal page variables at the top of each page.
$foo = (isset($_REQUEST['foo'])) ? $_REQUEST['foo'] : '';
$bar = request_value('bar'); // *see note below
$error = '';
*request_vaule() is only available in iMarc's base.functions.php framework file.
26 Naming Conventions
File naming conventions are descibed above in Naming Libraries, for programming files, and below in File Naming for HTML, CSS, and other file non-programming files. Database naming conventions are described in Database Naming Conventions
The following describes how PHP variables, functions, classes, and methods should be named
26.1 Variable Naming
Variable names must be meaningful. One letter variable names must be avoided, except for places where the variable has no real meaning or a trivial meaning (e.g. for ($i=0; $i<100; ++$i)).
Variable names should be in lowercase and use underscores to separate words.
$page_function = "foo"; $database_user = "mysql"; $i = 0;
26.2 Function Names
User defined functions should be in lowercase, with words underscore to separate words. Take care to minimize the letter count, but do not use abbreviations, because they greatly decrease the readability of the function name itself.
// GOOD Examples
function mcrypt_self_test { ... }
function mysql_list_fields { .... }
// BAD Examples
function hw_GetObjectByQueryCollObj { ... }
function jf_n_s_i { ... }
26.3 Class Names
Classes should be given descriptive names. Avoid using abbreviations where possible. Each word in the class name should start with a capital letter, without underscore delimiters (CamelCaps starting with a capital letter).
// GOOD Examples
class Curl { ... }
class FooBar { ... }
// BAD Examples
class foobar { ... }
class foo_bar { ... }
26.4 Method Names
Method names follow the 'studlyCaps' (also referred to as 'bumpy case' or 'camel caps') naming convention, with care taken to minimize the letter count. The initial letter of the name is lowercase, and each letter that starts a new 'word' is capitalized.
// GOOD Examples
function public connect() { ... }
function public getData() { ... }
// BAD Examples
function public get_Data() { ... }
function public buildsomewidget { ... }
27 File Naming Conventions
Also see Naming Libraries, for programming file naming standards.
27.1 CSS Files
CSS files are typically be saved in the website's /css/ directory or in a subdirecory of /includes/ or /lib/.
It's encouraged to split style selectors into multiple files.
/css/base.css† - (optional) basic, styles used over multiple templates, core branding selectors./css/[template-name].css- if the template is called 'site', /css/site.css should contain styles used in by that template/css/calendar.css- (optional) styles that are only used on a specific page – in this example, the Calendar page. If there are only a couple of these styles, keep them in the [template-name].css, but if a particular page or tool requires a large number of css styles, break them out to their own css file and include it only on the page(s) that use them.
† Note: Sites commonly only use two templates – public and sitemanager – with no common syles shared between the two. In such cases, the site does not need a base.css.
28 Markup Standards
- Use XHTML Strict 1.0.
- Use a DOCTYPE declaration. It should be strict rather than transitional unless there is a overriding reason why this cannot be.
- The html tag should contain the lang attribute (or xml:lang if it is XHTML) and the appropriate ISO code. The encoding type should be specified in the meta tag as in the following: <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- All CSS and XHTML output must be validated.
- CSS: http://jigsaw.w3.org/css-validator/ ∞
- HTML: http://validator.w3.org/∞
- Tables/rows/cells:
- width, height, align, and background attributes should be removed to CSS.
- Data container tables should contain a summary attribute: summary="Table containing main toolbar items (icons and links)." Tables used for formatting only do not need summaries.
- For tables where identifying values by row and column are pivotal to understanding the data as a whole, the table and columns in the first row should use the scope attribute.
- All style rules should be in CSS rather than included in a style attribute for a given element.
- All form elements need label tags.
- Do not use !important in CSS unless it is absolutely necessary. CSS2 favors a user's stylesheet over the page author's but this specifier can change the precedence.
- Form elements should not contain other form elements.
- Font size, specified in CSS, should be in relative measures whenever possible. If you must force specific font sizes, specify a base font in pixel height (perhaps in the .body{} CSS declaration), and use relative fonts after that.
- All pages should work in every browser, even if they don't look the same across all browsers.
- New windows should not be opened via the target attribute in an a tag. Instead it should be controlled through JavaScript.
- All JavaScript functions and CSS should be in external files rather than in the head element, unless it's a single page script or style.
28.1 CSS Class and ID Names
CSS class and id names should describe the content they reference not how the content is laid out. Naming references to visual design such as 'leftcolumn' or 'redtext' should be avoided.
// GOOD CSS Class Names
.pullquote { ... }
.minor_navigation { ... }
.secondary { ... }
// BAD CSS Class Names
.blue_quote { ... }
.left_nav { ... }
.column { ... }
28.2 Inline CSS Styles
Avoid inline CSS styles wherever possible. Never reference a CSS selector and add to or override elements with inline style. The following code is pure evil.
// Pure EVIL <div class="blue_quote" style="color: #f00;"> Foobar </div>
28.3 Mimimal Markup
Minimize the use of HTML markup and CSS classes and ids.
// Bad example (HTML and CSS)
<div class="headertitle">...</div>
<div class="headerdescription">...</div>
<div class="headerlinks">...</div>
.headertitle { ... }
.headerdescription { ... }
.headerlinks { ... }
// Better example (HTML and CSS)
<div id="header">
<h3>...</h3>
<p>...</p>
<ul>...<ul>
</div>
#header h3 { ... }
#header p { ... }
#header ul { ... }
28.4 iMarc HTML Head
iMarc pages should also include a meta credits tag, stating "Design, programming, and hosting by iMarc. More info at http://imarc.net"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta name="credits" content="Design, programming, and hosting
by iMarc. More info at http://imarc.net" />
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Title</title>
</head>