You are on page 1of 14

PHP Coding Rule

For projects are written in PHP, we need to have contribution rules in development team. Beside
that the rules should be accepted widenly as an international standard to avoid controversy,
ambiguous and ensure a high level of technical interoperability.
In the limitation we will agree about some conventions are recognized by the community and
another specific rules.
Index
1. International Standard Convention
2. PHP Project Convention
2.1. Basic Rules and Standard
2.2. Naming Convention
2.2.1. Case Styles
2.3. Rules for break line
2.4. Rules for comment
2.5. Rules for logging
2.6. Rules for quantity (optional)
2.7. Rule for checking empty (optional)
2.8. Hard coding
2.9. Template
3. Traits
4. Best Practices
5. Check Style
6. Conclusion
1. International Standard Convention ↑
RFC7231 asserts about the semantics and content for Restful Web Service and related
technologies such as AJAX so HTTP methods (GET, HEAD, POST, PUT, PATCH, DELETE) will
be used in the suitable context.
RFC2616 asserts about HTTP status codes and its meaning for suitable case as it should be.
PSR-2 and PSR-4 are coding conventions for PHP Coding Standard which are approved
widenly from PHP Community (PHP Framework Interoperability Group) for several industrial
frameworks so PHP Developers must comply strictly in software development process.
Object Oriented Programming and related concepts of Object Oriented Programming must
be strictly apply to ensure about the abstraction , encapsulation , polymorphism and
inheritance at least. A professional developer should understand clearly and apply it
properly to ensure the structural, tightness, maintainable and adapt for enterprise
application.
Laravel Framework asserts that we should follows PSR-2 and PSR-4 so it ONLY contains
rules about PHPDoc. Anything relates to Laravel Framework which does not comply to RFC
or PSR-2/PSR-4 or OOP Concepts (if exist) will not be accepted.
2. PHP Project Convention ↑
2.1. Basic Rules and Standard ↑
These are the standards for writing code, there are a few simple rules as follows:
For file
The code must be written in <?php ?> Tag pairs and should use <?= ?> Short tags instead
of echo.
For PHP> = 5.4, use [] to declare array, instead of array ().
Code can only use UTF-8 without BOM (BOM - Byte Order Mark is the sequence of EF, BB,
BF at the beginning of the file, allowing the software to know this is a UTF-8 file).
Use the latest version of PHP if possible.
Each PHP file should only do 1 single task, avoid overlapping (called side effect).
For naming
Code must comply with PSR-1 & PSR-0.
Namespace must comply with the standard PSR "autoloading" (PSR-0, PSR-4).
The class name must be written according to the PascalCase rule (or another name
StudlyCaps).
The parameters must capitalize all letters, separated by underscores.
The method name is written according to the camelCase rule.
For functions
The closing and opening tags of a function {} must be separated on one line.
Before opening and closing the {} function, there must be no blank line.
If you must use abstract and final or static to declare the function, you must declare it in
order.
For variables and parameters
A single quote must be used to declare the string does not contain a variable, if the string
contains the character ' then use double quotes " to wrap it around (we are often
confused by this problem).
There must be a space before and after the operation, when cast, there must be a space
between the data type and the cast variable.
Use accents . to concatenate - notice before and after the period . must have spaces. If
the string is too long, split into multiple lines and the dot is placed before the line with the
equal sign.
The parameters passed to the function must have a space before the comma, you can split
into multiple lines but must be indented 1 unit.
The variable name is written as camelCase. For the property name inside the Model, it can
be written as snake_case to match the names of the columns in the Database tables.
Use the ' sign for a normal string. Use " only when PHP variables are internally
implemented.
There should be a space before and after operators like +, -,, /,.,>, <, ==
Variables should be declared at the beginning of the function or a scope block.
Reusable variables should not be declared in a loop scope block.
PHP is a loosely typed language, it allows variable declaration without specifying its
datatype. PHP provides various datatypes and the type conversion can be performed in
various methods. After each type casting, please specify the output and the type of the
variable using PHP comment line.
For statements, elements and arrays
For switch case statements, the case must be 4 spaces behind the switch, and the
commands in the case must be 4 spaces behind the case. There must be a break or return
keyword, in which case no one has to comment // no break
When declaring arrays, elements of the array can be separated into multiple lines. In doing
so, the following rules need to be followed:
The first word of the array must be on a new line.
Only one element per line is allowed, elements are allowed to indent once.
Commas need to be at the end of the last element.
The end of the array declaration (square brackets) must be placed on a new line.
For lines
On a line that does not exceed 120 characters, it is best to be less than or equal to 80
characters, there should be no trailing white space.
There must be a blank line after the namespace declaration and there must be a blank line
after the use declarations.
2.2. Naming Convention ↑
PascalCase for name of classes, functional directories,... E.g.: SendMailService,
HomeController, Controllers,...
camelCase for name of variables, methods, functions. E.g.: $userName, getUserName,
setGoodsPrice,...
snake_case for name of resources. E.g.: user_detail, order_list,...
UPPER_CASE for name of constants, parameters. E.g.: CATEGORY_CD_PAYMENT_TYPE ,
PROCESS_STATUS_DONE ,...

Plural for functional directories.


Fuction name shoud start with "verb" as get, set, check, update,... E.g.: getUserName,...
Names must be meaningful, not abbreviated style names. E.g.: abc1, do1, fExport,...
Avoid naming too general, obscure. E.g.: get, doIt, makeIt,...
Abstract classes MUST be prefixed by Abstract: e.g. Psr\Foo\AbstractBar .
Traits MUST be suffixed by Trait: e.g. Psr\Foo\BarTrait .
2.2.1. Case Styles ↑
Case Styles is the most popular ways to combine words into a single string by removing spaces
between words
camelCase

Example: someVar , someClass , somePackage.xyz


PascalCase

Example: SomeVar , SomeClass , SomePackage.xyz


snake_case or under_scores

Example: some_var , some_class , some_package.xyz


2.3. Rules for break line ↑
If there is a "," sign, then the line after the "," sign.
Break line in front of the +,- operator.
If there are many nested levels, then go down to each level.
A new line breaks is started in the same column as the command at the same level above.
2.4. Rules for comment ↑
Limit comments to explain code, improve your code instead.
Only use comments when writing documentation for libraries, information attached to the
class ...
2.5. Rules for logging ↑
Store logs into files and/or database for reviewing.
For high levels of logs ( emergency , alert , critical , error ), they should be forwarded
to administrator via notification hooks (e.g.: Slack or email).
Bases on project definition, some error messages are not log level error , in this case, they
should be saved log as notice or info .
2.6. Rules for quantity (optional) ↑
The number of lines of code in the function / class, the number of functions in the class, the
number of classes in the package must be kept at a certain limit, and should be kept as little as
possible.
The function should not exceed 30 lines.
Class should not exceed 500 lines. (Clean Code).
A function cannot exceed 5 parameters. (should hold <= 3).
A function can only do 1 job, in case of necessity, can allow 2 jobs, but the function name
must say this clearly. E.g.: exportUserData, exportOrderDataAndUpdateStatus,...
When declaring a variable, one line contains only one variable.
Use 4 spaces (spaces) to indent, absolutely do not use tabs (you can declare in a
programming tool so when pressing the tab it is equivalent to indenting 4 spaces).
A line should not be longer than 120 characters. It is best to be less than or equal to 80
characters, there should be no trailing white space.
Nested statements up to 4 levels.
2.7. Rule for checking empty (optional) ↑
Determine whether a variable is considered to be empty. A variable is considered empty if it does
not exist or if its value equals FALSE . empty() does not generate a warning if the variable does
not exist.
No warning is generated if the variable does not exist. That means empty() is essentially
the concise equivalent to !isset($var) || $var == false .
Syntax: bool empty ( $var )
This function accepts a single parameter as shown in above syntax and described below.
$var : Variable to check whether it is empty or not.

Note:
Below version of PHP 5.5, empty() only supports variables, anything other will result in a
parse error. The following statement will not work empty(trim($var)) . Instead, use
trim($name) == false .
Return Value:
It returns FALSE when $var exists and has a non-empty, non-zero value. Otherwise it
returns TRUE .
These values are considered to be as an empty value:
"" (an empty string)
0 (0 as an integer)
0.0 (0 as a float)
"0" (0 as a string)
NULL
FALSE
array() (an empty array)

isset() vs empty() vs is_null()


isset — Determine if a variable is set and is not NULL
It returns true only when the variable is not null.
empty — Determine whether a variable is empty
It will return true if the variable is an empty string, false, array(), NULL, "0", 0, and an
unset variable.
is_null — Finds whether a variable is NULL
It returns true only when the variable is null . is_null() is opposite of isset() ,
except for one difference that isset() can be applied to unknown variables, but
is_null() only to declared variables.

is_null can be applied to undeclared variables, but a Notice is issued.

The table below is an easy reference for what these functions will return for different values. The
blank spaces means the function returns bool(false) .
Value of variable ($var) isset($var) empty($var) is_null($var)
"" (an empty string) bool(true) bool(true)

" " (space) bool(true)

FALSE bool(true) bool(true)

TRUE bool(true)

array() (an empty array) bool(true) bool(true)

NULL bool(true) bool(true)

"0" (0 as a string) bool(true) bool(true)


Value of variable ($var) isset($var) empty($var) is_null($var)
0 (0 as an integer) bool(true) bool(true)

0.0 (0 as a float) bool(true) bool(true)

var $var; (a variable declared, but


without a value) bool(true) bool(true)

NULL byte ("\ 0") bool(true)

2.8. Hard coding ↑


Constant string, table name, column name must be replaced by constant or translation (for
html or json) to avoid hard coding issue.
For examples:
const TEMPLATE_ID = 3;
const CREATED_AT = 'CreatedAt';

2.9. Template ↑
Copyright header
<?php
/**
* --------------------------------------------------------------------
* Copyright (c) 2019 Project X. All rights reserved.
* --------------------------------------------------------------------
* NOTICE: All information contained herein is, and remains
* the property of Vitalify Asia Co., Ltd and its suppliers,
* if any. The intellectual and technical concepts contained
* herein are proprietary to Vitalify Asia Co., Ltd
* and its suppliers and may be covered by Vietnamese Law,
* patents in process, and are protected by trade secret or copyright law.
* Dissemination of this information or reproduction of this material
* is strictly forbidden unless prior written permission is obtained
* from Vitalify Asia Co., Ltd.
* --------------------------------------------------------------------
* Author 1: Author One <author.one@@vitalify.asia>
* Author 2: Author Two <author.two@@vitalify.asia>
* --------------------------------------------------------------------

Class description
namespace App\Core\Controller;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

/**
* Abstract Controller
* This controller is an example about abstract class
*
* @category \App\Core
* @package \App\Core\Controller
* @author Author One <author.one@vitalify.asia>
* @author Author Two <author.two@vitalify.asia>
* @copyright 2019 Vitalify Asia Vietnam
*/
abstract class Controller extends BaseController
{
/**
* By default this controller uses a trait to
* provide this functionality without requiring any additional code.
*/
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
}

Encapsulation in OOP
/**
* User hashed password
*
* @var string password
*/
private $password;

/**
* Set password for user
* Raw password will be hashed by bcrypt algorithm before saving to database
*
* @param string $email
* @return User
*/
public function setPassword(string $rawPassword): User
{
$this->password = Hash::make($rawPassword);
return $this;
}

/**
* Get user password in bcrypt format
*
* @return string
*/
public function getPassword(): string
{
return $this->password;
}

3. Traits ↑
As of PHP 5.4.0, PHP implements a method of code reuse called Traits.
Traits are a mechanism for code reuse in single inheritance languages such as PHP. A Trait is
intended to reduce some limitations of single inheritance by enabling a developer to reuse
sets of methods freely in several independent classes living in different class hierarchies.
The semantics of the combination of Traits and classes is defined in a way which reduces
complexity, and avoids the typical problems associated with multiple inheritance and Mixins.
A Trait is similar to a class, but only intended to group functionality in a fine-grained and
consistent way. It is not possible to instantiate a Trait on its own. It is an addition to traditional
inheritance and enables horizontal composition of behavior; that is, the application of class
members without requiring inheritance.
Precedence
An inherited member from a base class is overridden by a member inserted by a Trait.
The precedence order is that members from the current class override Trait methods, which
in turn override inherited methods.
Multiple Traits
Multiple Traits can be inserted into a class by listing them in the use statement, separated by
commas.
Example for Multiple Traits Usage
<?php
trait HelloTrait {
public function sayHello() {
echo 'Hello ';
}
}

trait WorldTrait {
public function sayWorld() {
echo 'World';
}
}
class MyHelloWorld {
use HelloTrait, WorldTrait;
public function sayExclamationMark() {
echo '!';
}
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
$o->sayExclamationMark();
?>

The above example will output:


Hello World!

Conflict Resolution
If two Traits insert a method with the same name, a fatal error is produced, if the conflict is
not explicitly resolved.
To resolve naming conflicts between Traits used in the same class, the insteadof operator
needs to be used to choose exactly one of the conflicting methods.
Since this only allows one to exclude methods, the as operator can be used to add an alias to
one of the methods. Note the as operator does not rename the method and it does not
affect any other method either.
Example for Conflict Resolution
In this example, Talker uses the traits AndyTrait and BobTrait . Since AndyTrait
and BobTrait have conflicting methods, it defines to use the variant of smallTalk from
trait BobTrait , and the variant of bigTalk from trait AndyTrait .
The Aliased_Talker makes use of the as operator to be able to use BobTrait's bigTalk
implementation under an additional alias talk.
<?php
trait AndyTrait {
public function smallTalk() {
echo 'andy';
}
public function bigTalk() {
echo 'Andy';
}
}
trait BobTrait {
public function smallTalk() {
echo 'bob';
}
public function bigTalk() {
echo 'Bob';
}
}

class Talker {
use AndyTrait, BobTrait {
BobTrait::smallTalk insteadof AndyTrait;
AndyTrait::bigTalk insteadof BobTrait;
}
}

class Aliased_Talker {
use AndyTrait, BobTrait {
BobTrait::smallTalk insteadof AndyTrait;
AndyTrait::bigTalk insteadof BobTrait;
BobTrait::bigTalk as talk;
}
}
?>

Changing Method Visibility


Using the as syntax, one can also adjust the visibility of the method in the exhibiting class.
Traits Composed from Traits
Just as classes can make use of traits, so can other traits. By using one or more traits in a
trait definition, it can be composed partially or entirely of the members defined in those
other traits.
Abstract Trait Members
Traits support the use of abstract methods in order to impose requirements upon the
exhibiting class.
Caution: A concrete class fulfills this requirement by defining a concrete method with the
same name; its signature may be different.
Static Trait Members
Traits can define both static members and static methods.
Properties
Traits can also define properties.
If a trait defines a property then a class can not define a property with the same name unless
it is compatible (same visibility and initial value), otherwise a fatal error is issued. Before PHP
7.0.0, defining a property in the class with the same visibility and initial value as in the trait,
raised an E_STRICT notice.
4. Best Practices ↑
Some features in PHP are highly NOT recommend in developing business feature because of
explicitly and hard to maintain for enterprise application. In case of using, please make your
comment clearly so that other guys can follow it easier.
Magic method in assignment
Wrong
$a->thisPropertyDoesNotExist = 0;

Right
Declare property $thisPropertyDoesNotExist before using it

Eval function
Wrong
eval("$a + $b");

Right
// This is an explaination about why we must use eval in here
// If you can not explain please DO NOT use
eval("$a + $b");

Variable as a part of another variable or property name


Wrong
echo $$a;
echo $this->$abc;
Right
// This is an explaination about why we must use dynamic variable name
// If you can not explain please DO NOT use
echo $$a;

// This is an explaination about why we must use dynamic property name


// If you can not explain please DO NOT use
echo $this->$abc;

Ternary operator
Wrong
$example = trim($this->doSomething()) ? $this->doSomething() : "";

Right
// ONLY use ternary in return statement of simple statement
$isSomethingNotEmpty = ! empty(trim($this->doSomething()));
return $isSomethingNotEmpty ? $this->doSomething() : "";

Nested if else - complex conditions


Wrong
if ($a) {
if ($b) {
}
} elseif ($c) {
} else {
}

Right (Early RETURN)


if (($a) && ($b)) {
return;
}

if ($c) {
return;
}

return;
Else keyword has no effect to return statement
Wrong
if ($a) {
return true;
} else {
return false;
}

Right (No need ELSE because of RETURN)


if ($a) {
return true;
}

return false;

Because the cost for human readable and maintainace is expensive so please DO NOT abuse if
you can do in a better way.
5. Check Style ↑
It is required for all PHP project, base on defined project convention.
Use checkstyle.xml to check code convention before commit code.
6. Conclusion ↑
All developers should follow this agreement about best practices
to ensure about unique coding style and maintainability.

You might also like