Coding standards are guidelines about programming style and practices developers should follow when writing code. They usually cover indentation, white space, comments, naming conventions, etc. Moreover, coding standards are very important for producing consistent, readable and maintainable code, especially if you are part of a team. Remember the countless argues about tabs vs spaces? Well, that’s history if you and your team agree to use a standard.
The PHP-FIG has defined the PSR-1 and PSR-2 coding style guides. A few more like Symfony, Zend, Squiz also exist, so you can choose whatever suits you better and start reading the specification. Fortunately, you don’t have to remember all those rules, since there are tools, like the PHP-CS-Fixer, that can validate and fix your code. Even better, you can create a pre-commit hook that does it automatically, before you commit your changes to your repository.
PHP Coding Standards Fixer
The PHP-CS-Fixer has been written by Fabien Potencier, the creator of the Symfony framework, and Dariusz Rumiński. It’s open source and released under the MIT license. You can download it from cs.sensiolabs.org or install it via Composer, Homebrew.
Requirements
PHP 5.6.0 or greater
Installation
Global (Composer)
composer global require friendsofphp/php-cs-fixer
Global (Homebrew)
brew install homebrew/php/php-cs-fixer
In the vendor directory (Composer)
composer require — dev friendsofphp/php-cs-fixer
Basic Commands
If you used the installation in the vendor directory, the path to the fixer is ./vendor/friendsofphp/php-cs-fixer/php-cs-fixer. If you chose the global installation, running php-cs-fixer should be enough. To run the fixer without writing php
at the beginning of the command, set its execute permissions with chmod +x path/to/php-cs-fixer.
General help: php-cs-fixer help
Help for a given command: php-cs-fixer help <command>
Help for a given ruleset (e.g. Symfony): php-cs-fixer describe @Symfony
Help for a given rule (e.g. yoda_style): php-cs-fixer describe yoda_style
Use the PSR-2 rules and output the changes, without applying them: php-cs-fixer fix path/to/dir_or_file — rules=@PSR2 — dry-run — diff — using-cache=no
Use the Symfony rules and output the changes, without applying them: php-cs-fixer fix path/to/dir_or_file — rules=@Symfony — dry-run — diff — using-cache=no
Usage Example
Let’s start with fixing the very simple class Str. Below you can see the project’s structure
├── composer.json
├── composer.lock
├── src
│ └── Str.php
└── vendor
├── autoload.php
├── bin
├── composer
├── doctrine
├── friendsofphp
├── gecko-packages
├── paragonie
├── php-cs-fixer
└── symfony
and its code, before the fixes
<?php
namespace App;
class Str {
private $str;
public function __construct(string $str) {
$this->str = $str;
}
public function concat($str) {
return new static($this->str . ' ' . $str);
}
public function __toString() {
return $this->str;
}
}
Step-by-step Fixes
Step 1: Test what the tool can fix by applying the PSR-2 and the Symfony standards. The —-dry-run
flag will run the fixer without making changes to your files. The —-diff
flag will be used to let the fixer output all the changes it makes.
php-cs-fixer fix src — rules=@PSR2,@Symfony — dry-run — diff — verbose — using-cache=no
Loaded config default.
F
Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error
1) src//Str.php (blank_line_after_opening_tag, class_definition,
no_whitespace_in_blank_line, blank_line_after_namespace, braces)
---------- begin diff ----------
--- Original
+++ New
@@ @@
-<?php namespace App;
-class Str {
- private $str;
-
- public function __construct(string $str) {
- $this->str = $str;
- }
+<?php
- public function concat($str) {
- return new static($this->str . ' ' . $str);
- }
+namespace App;
- public function __toString() {
- return $this->str;
- }
+class Str
+{
+ private $str;
+
+ public function __construct(string $str)
+ {
+ $this->str = $str;
+ }
+
+ public function concat($str)
+ {
+ return new static($this->str . ' ' . $str);
+ }
+
+ public function __toString()
+ {
+ return $this->str;
+ }
}
----------- end diff -----------
Checked all files in 0.073 seconds, 10.000 MB memory used
Let’s decode the output:
F
Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error
1) src//Str.php (blank_line_after_opening_tag, class_definition,
no_whitespace_in_blank_line, blank_line_after_namespace, braces)
The F means that the tool can fix the code. The rules it will use are the following: blank_line_after_opening_tag
, class_definition
, no_whitespace_in_blank_line
, blank_line_after_namespace
, braces
.
You can skip any rule by adding a dash before its name. For example, to skip the braces
rule, write the following command:
./vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix src — rules=@PSR2,@Symfony,-braces — dry-run — diff — verbose — using-cache=no
Step 2: Remove the —-dry-run
flag and let the tool do its job.
./vendor/friendsofphp/php-cs-fixer/php-cs-fixer fix src rules=@PSR2,@Symfony —-verbose —-using-cache=no
Loaded config default.
F
Legend: ?-unknown, I-invalid file syntax, file ignored, S-Skipped, .-no changes, F-fixed, E-error
1) php-cs-fixer-project/src//Str.php (blank_line_after_opening_tag,
class_definition, no_whitespace_in_blank_line, blank_line_after_namespace, braces)
Fixed all files in 0.084 seconds, 10.000 MB memory used
…and Voilà!
<?php
namespace App;
class Str
{
private $str;
public function __construct(string $str)
{
$this->str = $str;
}
public function concat($str)
{
return new static($this->str . ' ' . $str);
}
public function __toString()
{
return $this->str;
}
}
Not bad, right? But, how can you share the same rules with the rest of your team? It’s pretty simple. Create a config file named .php_cs
in your project’s root directory, put the rules in it and execute the php-cs-fixer using the —-config=.php_cs
option, like the following example. php-cs-fixer fix —-config=.php_cs
Here is a config you can use. It requires the --allow-risky=yes
option for applying some rules, so feel free to adapt it to your needs.
<?php
$finder = PhpCsFixer\Finder::create()
->exclude('vendor')
->in(__DIR__);
return PhpCsFixer\Config::create()
->setRules([
'@Symfony' => true,
'array_syntax' => ['syntax' => 'short'],
'align_multiline_comment' => [
'comment_type' => 'all_multiline',
],
'cast_spaces' => ['space' => 'none'],
'concat_space' => ['spacing' => 'one'],
'is_null' => ['use_yoda_style' => false],
'no_useless_return' => true,
'not_operator_with_space' => false,
'ordered_class_elements' => true,
'ordered_imports' => true,
'yoda_style' => [
'equal' => false,
'identical' => false,
'less_and_greater' => false
],
'full_opening_tag' => false,
'php_unit_construct' => true,
'php_unit_strict' => true,
'phpdoc_order' => true,
])
->setUsingCache(false)
->setFinder($finder);
Wrap Up
- Use a coding style guide, especially when you are member of a team
- Use PHP-CS-Fixer to fix your code automatically