This guide defines a set of rules aimed to create consistent code across all PHP projects of Legal Things.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.
The term Project is used for deliverables that are typically served by a web server or run on the command line. The term Library is used for a collection of classes and/or functions which is consumed by projects or other libraries.
LegalThings follows the PSR-1 basic coding standard with an exception on Section 3 - Namespace and Class Names:
Projects SHOULD NOT use a vendor namespace.
Libraries MUST use the vendor namespace: "LegalThings".
Libraries must follow the PSR-4 autoloading standard.
LegalThings follows the PSR-2 coding style guide with a number of exceptions.
2.1. Exception on Section 2.3 - Lines
Lines MAY be longer than 80 characters; Lines SHOULD NOT be longer than 120 characters; lines longer than that SHOULD be split into multiple subsequent lines of no more than 120 characters each.
The keywords AND
and OR
SHOULD NOT be used. Instead use &&
and ||
.
PHP files SHOULD be 500 lines or less.
Functions and methods SHOULD be 30 lines or less.
The alternative syntax for control structures MUST NOT be used in files containing only PHP.
Directories MAY be omited if they're not used.
Cache, user generated content and external (composer and bower) libraries SHOULD be excluded from distribution.
A project SHOULD follow the following directory structure:
- bin - Executables and command line scripts
- cache - Cached files, may be deleted at any time
- config - Configuration files
- controllers - Controller classes
- dev - Development resources
- lib - Library classes and functions
- locale - Translation files
- models - Model classes
- static - User generated content (development environment only)
- tests - Unit and API tests
- vendor - Installed composer packages
- views - View templates
- www - Document root
- bower_components - Installed bower packages
- css - Stylesheets
- img - Images (except user generated content)
- js - JavaScript
On staging and production environments, user generated content MUST be stored on secure, persistent, redundant and backed-up storage (e.g. AWS S3 or Elastic file system).
A library SHOULD follow the following directory structure:
- bin - Executables and command line scripts
- dev - Development resources, eg a database dump
- locale - Translation files
- src - Library classes and functions
- tests - Unit and API tests
- vendor - Installed composer packages
Properties and methods SHOULD be public or protected, not private.
Classes SHOULD NOT have simple getter and setter functions as replacement for public properties.
Within the body of a function or method, there SHOULD be no more than 4 levels of nesting. With this many levels of nesting, introduce a new function rather than to use more nested blocks.
function foo() {
foreach (/* ... */) {
if (/* ... */) {
while (/* ... */) {
if (/* ... */) {
// No more nested blocks
}
}
}
}
}
Assertions and alternative flows SHOULD come before the normal flow to reduce nesting.
Examples of good flow:
function fizz($a) {
if (!$a) return;
foo();
bar();
}
function buzz($b) {
while ($b as $i) {
if (!$i) continue;
$i->foo();
$i->bar();
}
}
Examples of bad flow, with unnecessary nesting:
function fizz($a) {
if ($a) {
foo();
bar();
}
}
function fizz($a) {
if ($a) {
foo();
} else {
return;
}
bar();
}
function buzz($b) {
while ($b as $i) {
if ($i) {
$i->foo();
$i->bar();
}
}
}
Each project MUST include a README.md
document in the root folder.
The README document SHOULD include the title of and a short description the project.
The README document SHOULD include a list of prerequisites.
The README document SHOULD include installation instructions.
The README document SHOULD include API documentation or a link to the API documententation.
The README document MAY include additional information which can be useful for developers.
Each class MUST have a document blocks.
Each public property MUST have a document block with an @var
tag. Each protected of private property SHOULD have a document block with an @var
tag.
Each function and method MUST have a document block with @param
tags for all parameters and an @return
tag if a value is returned.
Variables document block SHOULD be as precise as possible. Examples:
@return string|boolean|array
is preferred to@var mixed
@var Foo|Bar
is preferred to@var object
@var Foo[]
is preferred to@var array
A document block for a method that implements the fluent interface pattern SHOULD state @return $this
.
Projects and libraries SHOULD include unit tests, runnable by codeception.
Each library class and function SHOULD be covered by unit tests, with a code coverage of 90% or more.
Each model class SHOULD be covered by unit tests, with a code coverage of 90% or more.
A controller class SHOULD NOT be covered by unit tests.
Projects with a web service API SHOULD include API tests, runnable by codeception.
Controller methods related to a web service SHOULD be covered by unit tests, with a code covereage of 90% or more.
Projects with a user interface SHOULD have a test plan for manual acceptance testing.
Controller methods not related to a web service MAY be covered by automated functional tests, runnable by codeception.