- Code Structure
- Spaces
- Ternary Operator
- String Literals
- Assignment Expressions
- C borrowings
- Alternative syntax for control structures
- Naming
- Functions
- Variables
- Pitfalls
- empty()
- isset()
- Boolean conversion
- Equality operators
- Comments and Documentation
- Visibility
- Global Objects
- Static methods and properties
- Classes
- Error handling
Code structure
Spaces
Put spaces on either side of binary operators,
eg) $a = $b + $c;
Put spaces next to parentheses on the inside, except where the parentheses are empty. Do not put a space following a function name.
Examples:
$a = getFoo( $b );
$c = getBar();
Put spaces in brackets when declaring an array, except where the array is empty. Do not put spaces in brackets when accessing array elements.
Examples:
$a = [ 'foo', 'bar' ];
$c = $a[0];
$x = [];
Control structures such as if, while, for, foreach, and switch, as well as the catch keyword, should be followed by a space:
Example:
if ( isFoo() ) {
$a = 'foo';
}
When type casting, do not use a space within or after the cast operator:
Example: (int)$foo;
In comments there should be one space between the # or // character and the comment.
// Proper inline comment
/***** Do not comment like this ***/
Ternary operator
The ternary operator can be used profitably if the expressions are very short and obvious:
$value = isset( $this->variable[key] ) ? $this->variable[key] : false;
But if you're considering a multi-line expression with a ternary operator, please consider using an if () block instead. Remember, disk space is cheap, code readability is everything, "if" is English and ?: is not.
String literals
For simple string literals, single quotes are slightly faster for PHP to parse than double quotes. Also for people using US/UK qwerty keyboards, they are easier to type, since it avoids the need to press shift. For these reasons, single quotes are preferred in cases where they are equivalent to double quotes.
However, do not be afraid of using PHP's double-quoted string interpolation feature: $elementId = "myextension-$index"; This has slightly better performance characteristics than the equivalent using the concatenation (dot) operator, and it looks nicer too.
Assignment expressions
Using assignment as an expression is surprising to the reader and looks like an error. Do not write code like this:
if ( $a = foo() ) {
bar();
}
Space is cheap, and you're a fast typist, so instead use:
$a = foo();
if ( $a ) {
bar();
}
Using assignment in a while() clause used to be legitimate, for iteration:
$res = $dbr->query( 'SELECT * FROM some_table' );
while ( $row = $dbr->fetchObject( $res ) ) {
showRow( $row );
}
This is unnecessary in new code; instead use:
$res = $dbr->query( 'SELECT * FROM some_table' );
foreach ( $res as $row ) {
showRow( $row );
}
C borrowings
The PHP language was designed by people who love C and wanted to bring souvenirs from that language into PHP. But PHP has some important differences from C.
In C, constants are implemented as preprocessor macros and are fast. In PHP, they are implemented by doing a runtime hashtable lookup for the constant name, and are slower than just using a string literal. In most places where you would use an enum or enum-like set of macros in C, you can use string literals in PHP.
PHP has three special literals for which upper-/lower-/mixed-case is insignificant in the language (since PHP 5.1.3), but for which our convention is always lowercase : true, false and null.
Use elseif not else if. They have subtly different meanings:
// This:
if ( $foo == 'bar' ) {
echo 'Hello world';
} else if ( $foo == 'Bar' ) {
echo 'Hello world';
} else if ( $baz == $foo ) {
echo 'Hello baz';
} else {
echo 'Eh?';
}
// Is actually equivalent to:
if ( $foo == 'bar' ) {
echo 'Hello world';
} else {
if ( $foo == 'Bar' ) {
echo 'Hello world';
} else {
if ( $baz == $foo ) {
echo 'Hello baz';
} else {
echo 'Eh?';
}
}
}
And the latter has poorer performance.
Alternative syntax for control structures
PHP offers an alternative syntax for control structures using colons and keywords such as "endif", "endwhile", etc.:
if ( $foo == $bar ):
echo "<div>Hello world</div>";
endif;
This syntax should be avoided, as it prevents many text editors from automatically matching and folding braces. Standard syntax should be used instead:
if ( $foo == $bar ) {
echo "<div>Hello world</div>";
}
Naming
Use lowerCamelCase when naming functions or variables. For example:
private function doSomething( $userPrefs, $editSummary )
Use UpperCamelCase when naming classes: class ImportantClass. Use uppercase with underscores for global and class constants: DB_MASTER, Revision::REV_DELETED_TEXT. Other variables are usually lowercase or lowerCamelCase; avoid using underscores in variable names.
There are also some prefixes used in different places:
Functions
sf (sample functions) – top-level functions, e.g.
function sfFuncname() { ... }
ef (extension functions) = global functions in extensions, although "in most cases modern style puts hook functions as static methods on a class, leaving few or no raw top-level functions to be so named." (-- brion in Manual_talk:Coding_conventions#ef_prefix_9510)
Verb phrases are preferred: use getReturnText() instead of returnText().
Variables
$gv – global variables, e.g. $gvVersion, $gvTitle. Always use this for new globals, so that it's easy to spot missing "global $gvFoo" declarations. In extensions, the extension name should be used as a namespace delimiter. For example, $gvAbuseFilterConditionLimit, not $gvConditionLimit.
Global declarations should be at the beginning of a function so dependencies can be determined without having to read the whole function.
It is common to work with an instance of the Database class; we have a naming convention for these which helps keep track of the nature of the server to which we are connected. In development environments there is usually no difference between the two types, which can conceal subtle errors.
Pitfalls
empty()
The empty() function should only be used when you want to suppress errors. Otherwise just use ! (boolean conversion).
empty( $var ) essentially does !isset( $var ) || !$var.
Common use case: Optional boolean configuration options that default to false. $this->enableFoo = !empty( $options['foo'] );
Beware of boolean conversion pitfalls.
It suppresses errors about undefined properties and variables. If only intending to test for undefined, use !isset(). If only intending to test for "empty" values (e.g. false, zero, empty array, etc.), use !.
isset()
Do not use isset() to test for null. Using isset() in this situation could introduce errors by hiding misspelled variable names. Instead, use $var === null.
Boolean conversion
if ( !$var ) {
...
}
Study the rules for conversion to boolean. Be careful when converting strings to boolean.
Do not use it to test if a string is empty, because PHP considers '0' and similar expressions to be falsy. Use === '' instead.
Equality operators
Be careful with double-equals comparison operators. Triple-equals (===) is generally more intuitive and should be preferred unless you have a reason to use double-equals (==).
'foo' == 0 is true (!)
'000' == '0' is true (!)
'000' === '0' is false
To check if two scalars that are supposed to be numeric are equal, use ==, e.g. 5 == "5" is true.
To check if two variables are both of type 'string' and are the same sequence of characters, use ===, e.g. "1.e6" === "1.0e6" is false.
To check if two scalars that should be treated as strings are equal as strings, use strcmp(), e.g. strcmp(13,"13") is 0.
Comments and documentation
It is essential that your code be well documented so that other developers and bug fixers can easily navigate the logic of your code. New classes, methods, and member variables should include comments providing brief descriptions of their functionality (unless it is obvious), even if private. In addition, all new methods should document their parameters and return values.
Visibility
Make methods public/protected/private (think what makes sense). Don't just make everything public!
Global objects
Main page: Manual:RequestContext.php
Do not access the PHP superglobals $_GET, $_POST, etc, directly; use $request->get*( 'param' ) instead; there are various functions depending on what type of value you want. You can get a WebRequest from the nearest RequestContext, or if absolutely necessary $wgRequest. Equally, do not access $_SERVER directly; use $request->getIP() if you want to get the IP address of the current user.
Static methods and properties
Static methods and properties are useful for programmers because they act like globals without polluting the global namespace. However, they make subclassing and reuse more difficult for other developers. Generally, you should avoid introducing static functions and properties when you can, especially if the sole purpose is to just save typing.
For example, lots of developers would prefer to write something like:
Foo::bar();
This is because it is shorter and takes less keystrokes. However, by doing this you've made the Foo class much harder to subclass and reuse. Instead of introducing a static method, you could just type:
$f = new Foo();
$f->bar();
Remember, shorter does not always mean better, and you should take the time to design your classes in a way that makes them easy to reuse.
Classes
Encapsulate your code in an object-oriented class, or add functionality to existing classes; do not add new global functions or variables. Try to be mindful of the distinction between 'backend' classes, which represent entities in the database (eg User, Block, Revision, etc), and 'frontend' classes, which represent pages or interfaces visible to the user (SpecialPage, Article, ChangesList, etc. Even if your code is not obviously object-oriented, you can put it in a static class (eg IP or Html).
As a holdover from PHP 4's lack of private class members and methods, older code will be marked with comments such as /** @private */ to indicate the intention; respect this as if it were enforced by the interpreter.
Mark new code with proper visibility modifiers, including public if appropriate, but do not add visibility to existing code without first checking, testing and refactoring as required. It's generally a good idea to avoid visibility changes unless you're making changes to the function which would break old uses of it anyway.
Error handling
Don't suppress errors with PHP's @ operator, for any reason ever. It's broken when E_STRICT is enabled and it causes an unlogged, unexplained error if there is a fatal, which is hard to support.
The proper method of handling errors is to actually handle the errors. For example, if you are thinking of using an error suppression operator to suppress an invalid array index warning, you should instead perform an isset() check on the array index before trying to access it. When possible, always prevent PHP errors rather than catching and handling them afterward. It makes the code more understandable and avoids dealing with slow error suppression methods.
No comments:
Post a Comment