-
Notifications
You must be signed in to change notification settings - Fork 24
Coding Style
This document describes coding style for the project and is loosely based on PEAR coding standards.
Conformance with these guidelines should be automated - run
make code
to run an automated style linter to see what needs to be changed.
All PHP code in the application must use tabs for indentation.
vim users can include following comment at the top of every PHP page, right after first opening PHP tag:
<?php
/* vim: set noexpandtab tabstop=8 shiftwidth=8 softtabstop=8: */
This will allow vim users to automatically enforce indentation of the code.
For formatting the page automatically using VI, use 1GVG=
command sequence.
Complete inline documentation comment blocks (docblocks) must be provided. Further information can be found on the phpDocumentor website.
Non-documentation comments are strongly encouraged. A general rule of thumb is that if you look at a section of code and think "Wow, I don't want to try and describe that", you need to comment it before you forget how it works.
C style comments /* */
and standard C++ comments //
are both fine. Use of Perl/shell style comments (#) is discouraged.
Same as for PEAR project
Even if control block contains only one statement, always use curly braces around that statement.
@TODO Include detailed explanation for the benefits of this
Alternative style for PHP control structures should never be used.
PHP has an option to enable a short open tag: <?
and it's companion short echo tag <?=
While very convenient, it's not turned on by default and will likely be disabled on the servers people use.
Use <?php
and regular echo command <?php echo
instead of short open tag and configure your development environment not to accept short tags to avoid this bug sneaking in (it's very painful to remove them).
When you need to refer to another file within the project (e.g. to include it or read from disk), please use PHP __DIR__
magic constant (with dirname()
function if necessary) to calculate the resulting path of the file.
For example to include file2.php
located in the same folder:
require_once(__DIR__ . '/file2.php');
In order to go up the folder chain, please do not use double dots (/../
) to indicate parent folder, but use nested dirname()
instead.
For example to include file3.php
located one folder above current file:
require_once(dirname(__DIR__) . '/file3.php');
It is important to distinguish objects from object IDs and object IDs from object slugs in the code, in the database and in configuration files.
It is preferred to pass objects when passing from one class to another, but (ideally private) functions within the same class can pass object IDs or object slugs.
Object IDs MUST always be integers while object slugs MUST always be strings.
To allow for better code readability and to avoid confusion between objects, their IDs and their slugs, variables in the code and field names in database should use the following naming convention:
- Object IDs must always have
_id
suffix, e.g.plan_id
- Object slugs must always have
_slug
suffix, e.g.plan_slug
- Variables without
_id
or_slug
suffixes must always refer to objects, e.g.plan
When stored in the database, objects should be identified by ID or by slug.
If object IDs are defined in the code, named constants must be used to help readability, for example:
define('FREE_PLAN', 0);
...
Account::createAccount(FREE_PLAN, ...);
Slugs should be URL-friendly, meaning that they should be the same as their URL-encoded version without resorting to %-encoding.
Slugs should not use camel case, but lower case latin letters and utilize dashes -
(not underscores) in place of spaces.
Do not convert strings into variables and vice versa, all variable assignments should be done through accessing methods that can have documentation with type definitions to allow autocompletion, static code analysis and etc.
This is very important for future debugging, tracing for source of errors and so on.
It's better to have more code and be explicit about your intentions then having smaller code that is harder to read and understand.
It's better to spend time adding more lines of code with type annotations and documentation when you need to add extra field then to spend more time trying to debug the issue and refactor the code to be self descriptive.
Instead of using __get
and __set
magic functions, use explicit accessor (getter and setter) methods.
Best practice for read-only properties:
class MyWidget
{
/**
* @var string name Name of the widget
*/
private $name;
/**
* @return string Name of the widget
*/
function getName() {
return $this->name;
}
}
to allow for IDE autocompletion, automated configuration and so on.
PHP extract()
function allows to convert arrays into variables which makes it impossible to track the origin of some variables, their scope and sometimes even dangerous when you don't control the source of data. Same applies to compact()
function as result is usually used by extract()
.
For converting arrays of data into variables, instead of using a shortcut:
$my_data = array(name => 'John', age => 55, gender => 'male');
extract($my_data); // ambiguous, hides declaration of variables
echo $name . ' is ' . $age . ' years old ' . $gender;
use explicit setting of values as a best practice:
$my_data = array(name => 'John', age => 55, gender => 'male');
// verbose, but specific
$name = $my_data['name'];
$age = $my_data['age'];
$gender = $my_data['gender'];
echo $name . ' is ' . $age . ' years old ' . $gender;