As you might or might not be aware of, most projects define or adopt a certain style of coding. This means that you need to be able to write your code following a set of rules.
These rules might include where to place the curly braces while declaring a new class or how many characters you are allowed to place on one line.
Combined these rules are usually part of the “coding conventions”.
For more information on exactly what coding conventions are you can look at the Wikipedia page: https://en.wikipedia.org/wiki/Coding_conventions.
Scuti has adopted a code style that already existed instead of writing our own, this standard is widely used and accepted.
The standard we use is called PSR-2.
The organization that writes/develops standards for use in the PHP language is called FIG. FIG stands for “Framework Interop Group” and its members consist out of developers of the major frameworks (that choose to be part of the group).
Their goal is to develop recommendations on how to do certain things. These recommendations are called PSR which stands for “PHP Standards Recommendations”.
More information can be found here: http://www.php-fig.org/psr/.
The PSR that is most important for this course is PSR-2.
The recommendations of PSR-2 extend and expand on the recommendations of PSR-1.
Before the PSR-2 was accepted there already was a convention to follow. The recommendations of this standard are as follows:
The only tags we are allowed to use according to the standard are the long tags:
<?php ?>
And the short-echo tags:
<?= ?>
Other variations are not allowed and must never be used.
You may or may not be aware of the fact that character encodings exist and that different operating systems, may by default use different character encodings.
Windows for example uses the Windows-1252 encoding by default, while Linux uses UTF-8.
For more information about character encodings, please look here: https://en.wikipedia.org/wiki/Character_encoding.
The recommendations state that the only encoding that should be used is UTF-8 and no BOM (Byte Order Mark) should be used.
Usually your IDE (Integrated Development Environment) will have some sort of setting or preference you can configure for the character set to be used. For PHPStorm this can found in the bottom bar all the way to the right:
So if PHPStorm does not show UTF-8 on your machine, please configure it to use the UTF-8 character encoding. (It goes without saying that this should also be done in other IDEs).
The standard states:
“The phrase "side effects" means execution of logic not directly related to declaring classes, functions, constants, etc., merely from including the file.
"Side effects" include but are not limited to: generating output, explicit use of require or include, connecting to external services, modifying ini settings, emitting errors or exceptions, modifying global or static variables, reading from or writing to a file, and so on.”
So basically “side effects” are lines of code that get executed without calling a function or method.
For example:
<?php
// side effect: change ini settings
ini_set('error_reporting', E_ALL);
// side effect: loads a file
include "file.php";
// side effect: generates output
echo "<html>\n";
// declaration
function foo()
{
// function body
}
In the code snippet above we can see that there are 3 lines that will get executed on loading the file. These are the so-called side effects.
Another example the PSR standard shows us is the following:
<?php
// declaration
function foo()
{
// function body
}
// conditional declaration is *not* a side effect
if (! function_exists('bar')) {
function bar()
{
// function body
}
}
This snippet has no side-effects.
According to the standard it is important that no file includes both code with side-effects and code without side-effects (like the first example).
So it is okay to have a file with just side-effects and to have a file without side-effects, but not a file containing both!
Following the recommendations an “autoloading” PSR should be used. Currently this can be either PSR-0 or PSR-4.
Autoloading means that there is some code registered somewhere (usually the framework provides this for you), that allows PHP to find the file that contains the class you want to use.
We use PSR-4 for our projects. PSR-0 is deprecated.
PSR-4 Requires us to place each class in a separate file. It also has to be in a namespace of at least one level.
For more information about namespaces, please look here: http://php.net/manual/en/language.namespaces.php.
Another requirement is that the class names are declared in “StudlyCaps”.
A string is written in StudlyCaps when it starts with an uppercase letter and words are separated by having the new word start with an uppercase letter as well.
For example: “BananaTreeLeaveTea”.
But not: “bananaTreeLeaveTea” or “Banana_Tree_Leave_Tea”.
Class names in this case are the names of classes, interfaces and traits.
Constants should be written in all uppercase letters, separated with underscores.
For example:
<?php
namespace Vendor\Model;
class Foo
{
const VERSION = '1.0';
const DATE_APPROVED = '2012-06-01';
}
The PSR-1 standard intentionally does not have any recommendations about the format of property names.
The important part is that the same case is used consistently throughout a reasonable scope.
A scope could be a namespace, class or project.
We should try to use “camelCase” as much as possible keeping the above in mind.
Regarding the naming convention of methods the standard is strict. All methods must have a name in “camelCase()”.
So far we have discussed the rules of PSR-1. These rules are very important not only by themselves, but also because the rules are part of PSR-2.
As said before PSR-2 extends and expands on the rules of PSR-1. Basically making it more specific.
The first rule of PSR-2 is that all code must follow the rules of PSR-1.
There are recommendations regarding files and their format:
You may or may not be aware of this, but different computer systems use different characters to indicate the end of a line in a text file. These are invisible characters so generally you will never see them. However we have a way to insert them in a string by escaping them with a backslash. Windows uses “\r\n” by default. Mac uses (or used) “\r” by default. Unix uses “\n” by default.
The recommendation states that lines must not be longer than 120 characters and should not be longer than 80 characters.
If a line is longer than 80 characters it is usually possible to split it up in multiple statements and spread it out over multiple lines. If this is not possible, it is okay to leave the line as it is (as long as it is not longer than 120 characters).
Also there should be no trailing whitespace.
This means there should be no spaces or tabs or other whitespace characters after the characters on the line that are code.
It is advisable to enable the display of whitespace characters in your IDE or editor, so that you will notice that it’s there.
Another rule is that you may use empty lines to improve readability and indicate blocks of related code.
Make sure there is only 1 statement per line. So we should never have something like this:
$line = ‘somestring’; $line .= ‘s’;
After a semicolon (“;”) there should be a line ending character.
For indentation 4 spaces should be used. Tabs are not allowed to be used as indentation.
All keywords should be written in lowercase. Keywords include “new”, “if”, “for”, etc…
A full list of keywords can be found here: http://php.net/manual/en/reserved.keywords.php.
The values “true”, “false” and “null” should also be written in lowercase.
After a “namespace” declaration there should always follow an empty line.
All “use” statements should go below the namespace (and empty line) declaration.
There should be only one “use” statement on each line.
There must be 1 empty line after the block of “use” statements.
For example:
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
// ... additional PHP code ...
When declaring a class, interface or trait there are certain rules we should follow.
The general rule is that the curly brace “{“ should go one a new line after the class declaration. The other curly brace “}” should also have its own line.
Extends and Implements
The “extends” and “implements” keywords should go on the same line as the class declaration.
If the line becomes too long, because there are a lot of interfaces to implements, each interface name can go on a new line.
For example:
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements
\ArrayAccess,
\Countable,
\Serializable
{
// constants, properties, methods
}
Properties
Properties should always be declared with a visibility keyword.
Usage of the “var” keyword is not allowed, so we should always use “private”, “protected” or “public”.
Another recommendation is that there should be only one property declared on one line.
Property names should not be prefixed with an underscore “_” to indicate their visibility.
An example of how not to declare properties:
<?php
namespace App\NotSoCleanCode;
class SomeClass
{
// Incorrect: $name does not have a visibility
$name;
// Incorrect: $description is declared with the “var” keyword
var $description;
// Incorrect: $_extra is prefixed with an underscore
private $_extra;
// Incorrect: only one property should be declared on this line
private $street, $houseNumber, $city;
}
In the above example you can see that all properties are declared incorrectly.
Now for an example where the properties are declared correctly:
<?php
namespace App\CleanCode;
class SomeClass
{
private $name;
private $description = ‘’;
private $extra;
protected $street;
protected $houseNumber;
public $city = null;
}
Methods
All method declarations must contain the desired visibility of the method.
Method names must NOT be prefixed with an underscore and there must NOT be a space after the method name.
The curly braces (“{“ and “}”) have to be on their own lines and there must not be a space after the opening parenthesis “(“ and no space before the closing parenthesis “)”.
An example of what a method declaration should look like following the rules above:
<?php
namespace App\CleanCode;
class SomeClass
{
public function doSomething($parameter)
{
// Code that does something
}
}
Method Arguments
For method arguments there are several recommendations to follow.
The first one states that there must not be a space character before a comma “,” and there must be a space character after a comma.
Another recommendation is that arguments with a default value must be declared last.
For example:
<?php
namespace App\CleanCode;
class SomeClass
{
public function __construct($name, $description, $extra = null)
{
// Code that does something
}
}
When the arguments cause the line to become too long, you may spread the arguments over multiple lines. If you do the following rules apply:
For example:
<?php
namespace App\CleanCode;
class SomeClass
{
public function __construct(
$name,
$description,
$extra = null
) {
// Code that does something
}
}
abstract, final and static
When using the abstract and final keywords, they must come before the visibility. The static keyword must always come after the visibility.
For example:
<?php
namespace App\CleanCode;
abstract class SomeClass
{
abstract public function getName();
final protected function doSomething()
{
// More code that does something
}
public static function transformMatrix($matrix)
{
// Transforms some kind of matrix
}
}
Method and Function Calls
For single line method or function calls, the recommendations revolve around the use of space characters.
There must not be any space between the method or function name and the opening parenthesis “(“.
Also there must not be any space after the opening parenthesis and before the closing parenthesis.
For the arguments the same rules as for their declaration apply. So no space before a comma and 1 space after a comma.
For example:
<?php
$unixTime = mktime(13, 37);
You may also spread the arguments over multiple lines. In this case the same rules apply as for spreading the arguments of the method declaration over multiple lines.
For example:
<?php
$unixTime = mktime(
13,
37,
0,
12,
21
);
Control structures are subject to the recommendations as well. There are some general guidelines that apply to all of the structures and some specific ones.
if, elseif and else
For this kind of control structure a few rules apply:
For example:
<?php
if ($someCondition) {
// if body
} elseif ($someOtherCondition) {
// elseif body
} else {
// else body
}
switch and case
As with all control structures there must be a space between the keyword (switch) and the opening parenthesis “(“. There must be no space after the opening parenthesis and no space before the closing parenthesis.
A switch has a slightly different format than the other control structures and as such it has some recommendations for that.
After the opening brace of the switch statement the “case” or “default” keyword is expected followed by the value and a colon. These lines are indented once.
On a new line after the “case” the body of the case can be inserted. This should be indented twice.
Case bodies are generally terminated with either a “break” or “return”. If a case body is not empty and it is not terminated with a break or return, a comment should be present to indicate that it is intentional.
For example:
<?php
switch ($expr) {
case 0:
echo 'First case, with a break';
break;
case 1:
echo 'Second case, which falls through';
// no break
case 2:
case 3:
case 4:
echo 'Third case, return instead of break';
return;
default:
echo 'Default case';
break;
}
Please notice that even though default is the last case it is still terminated with the break keyword.
while and do..while
There are no special recommendations with regards to the while and do while control structures. Instead here are examples of what they are supposed to look like.
<?php
while ($someCondition) {
// Do something interesting
}
do {
// Do something interesting, but check the condition afterwards
} while ($someCondition);
for
Other than providing an example, there are no special recommendations with regards to “for” control structures.
<?php
for ($i = 0; $i < 10; $i++) {
// Do something 10 times
}
foreach
For foreach control structures there are also no special recommendations. A foreach should look something like:
<?php
foreach ($iterable as $key => $value) {
// Do something for all items
}
try and catch
There are no specific recommendations for try..catch statements. A try..catch block should something like:
<?php
try {
// Execute code that might throw an exception
} catch (SomeException $e) {
// Catch exceptions of type SomeException
} catch (SomeOtherException $e) {
// Catch exceptions of type SomeOtherException
} finally {
// Execute whether an exception was thrown or not
}
Closures
When it comes to closures, basically the same recommendations apply as for normal functions or methods. There are some additional recommendations, this is because closures support an extra keyword: “use” which is followed by a list of 1 or more variables.
The recommendations for closures:
For example:
<?php
$closureWithArgs = function ($arg1, $arg2) {
// Closure body
};
$closureArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
// Closure body
};
This is the relatively simple notation of closures. When the argument and variable lists get a little longer they will have to be spread over multiple lines (otherwise the line would become too long).
Some examples:
<?php
$noArgsManyVars = function () use (
$var1,
$var2,
$var3,
$var4,
$var5
) {
// body
};
$manyArgsNoVars = function (
$arg1,
$arg2,
$arg3,
$arg4,
$arg5
) {
// body
};
$someArgsManyVars = function ($arg1, $arg2) use (
$var1,
$var2,
$var3,
$var4,
$var5
) {
// body
};
$manyArgsSomeVars = function (
$arg1,
$arg2,
$arg3,
$arg4,
$arg5
) use ($var1, $var2) {
// body
};
$manyArgsManyVars = function (
$arg1,
$arg2,
$arg3,
$arg4,
$arg5
) use (
$var1,
$var2,
$var3,
$var4,
$var5
) {
// body
};
When declaring the closure as an argument, the same rules apply:
<?php
$someObject->callMe(
1,
function () use ($var1) {
// body
},
null
);
We all make mistakes, that unfortunately can’t be helped. Fortunately there is a tool available that can help us check if our code adheres to the code style of choice (PSR-2).
This tool is developed by Squizlabs and its name is PHP_Codesniffer. You can find the source of the tool here if you’re interested: https://github.com/squizlabs/PHP_CodeSniffer.
It can be installed through composer by using the following command:
$ composer require squizlabs/php_codesniffer --dev
This will add the style checker to the composer.json file of the project in the require-dev section.
By default a symlink to the executable will be placed in “vendor/bin” and the name will be “phpcs”.
To run it, use the following command (from the root directory of your project):
$ vendor/bin/phpcs --standard=PSR2 path/to/the/php/files
If your code does not contain any violations the tool will not display any output. If it does it will show you the line numbers and the violations on that line.
Before committing you should always run the tool to prevent committing code with code style violations.