This repository is deprecated since we follow PSR 1 and PSR 2 recommandations
Naming:
snake_case
id
.<referenced-table>_<referenced-column>
, example: user_id
._id
suffix for int columns
* Add _at
suffix for timestamp columns, example: created_at
_ext_id
suffix for external references columns, example: degree_ext_id
is_x TINYINT
No need of CONSTRAINT clause when defining a foreign key:
FOREIGN KEY user_id_fk (user_id) REFERENCES user (id) ON DELETE RESTRICT ON UPDATE CASCADE
To name an FK or an index (KEY), prefer this naming: <column-name>_[idx|fk]
.
Examples: user_id_fk
or col1_col2_idx
.
By default, always set FK with ON UPDATE CASCADE ON DELETE RESTRICT
.
Avoid DEFAULT
values, unless you have a good reason for it.
Don't forget UNSIGNED
types: user_id UNSIGNED INT
.
Stop specifying a never used display width with integers' declaration:
INT(1)
allows to store exactly the same integers as INT(11)
.
So prefer: user_id UNSIGNED INT
.
Add as many integrity constraints as you can: UNIQUE
, FK
, NOT NULL
…
About text columns:
CHAR(x)
for fixed-length strings, and VARCHAR(x)
for strings of length at most x
VARCHAR(255)
instead of any value < 255VARCHAR(255)
to VARCHAR()
because by default the latter is equivalent to VARCHAR(65535)
Use COMMENT on columns and keep them up to date.
Don't forget our 2 “system” columns managed by MySQL itself:
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW() ON UPDATE NOW(),
These 2 columns should never be used in writing by application code!
All keywords in CAPITALS.
Do not put backticks `
around a table or column name if not necessary, this complicates reading.
Always specify which type of join: LEFT JOIN
, INNER JOIN
, other?
Use table aliases as soon as there is more than one table in the query, and prefix each column name with them. Example:
SELECT U.id, D.name
FROM user U
INNER JOIN degree D ON D.id = U.degree_id
WHERE ...
Any SELECT must have a LIMIT
clause, with the possible exception of exports.
Because IF EXISTS
doesn't exist for many DDL statements
we need to encapsulate some SQL instructions in a stored procedure.
Systematically make sure to remove the possible existing in order to reconstruct and guarantee the expected result:
for example make a DROP INDEX
before the CREATE INDEX
because perhaps it does not target the same columns.
Approach adopted after vote:
DROP PROCEDURE IF EXISTS clean;
DELIMITER //
CREATE PROCEDURE clean()
BEGIN
SET @exists = (
SELECT count(*)
FROM information_schema.statistics
WHERE table_name = 'bounce' AND index_name = 'campaign_id' AND table_schema = database()
);
IF @exists > 0 THEN
DROP INDEX campaign_id ON bounces;
END IF;
END //
DELIMITER ;
CALL clean();
DROP PROCEDURE IF EXISTS clean;
-- True payload:
CREATE INDEX campaign_id ON bounce (campaign_id);
We follow the standards defined in the PSR-0, PSR-1 and PSR-2 documents.
composer.json
.composer.lock
must be committed.Alumnforce\PackageName
should be used as namespace.getPsrLogger()
, $mySqlQuery
.[]
notation for arrays.$a++
, $a--
, if (! $expr) {…}
, $foo = (int) $bar;
$a && $b
, $a . $b
new MyClass()
.@param int[] <description> <structure>
,
@param ThisClass[] <description> <structure>
.On-the-fly assignment must be avoided because not very readable:
if (($myId = $obj->getById())) {...}.
Write:
$myId = $obj->getById();
if ($myId !== null) {
// ...
}
Implicit if
must be avoided because not very readable:
Write:
if (<expression>) {
<statement>
}
Let: if (\,
if <expression>
is of boolean type, then simply write: if (<expression>) {…}
.
If <expression>
is not a boolean then be specific, e.g. if (preg_match(...) > 0) {...}
To avoid: switch (true) {...}
If case
expressions are not deductible from the same variable, then use if/elseif
.
Instead of:
if ($expression) {
return $foo;
}
// many lines...
return $bar;
Write:
if ($expression) {
return $foo;
} else {
// many lines...
return $bar;
}
Or better, only one return
if possible:
if ($expression) {
$value = $foo;
} else {
// many lines...
$value = $bar;
}
return $value;
For a given function, do not use more than one data type for return value.
Bad, because of the mixture between array
and int
:
/**
* @return array|int
*/
function (…) {
if (…) {
return [1, 2, 3];
} else {
return 5;
}
}
Rewrite as follows:
/**
* @return array
*/
function (…) {
if (…) {
return [1, 2, 3];
} else {
return [5];
}
}
string|null
case.null
, it's ok with MyClass|null
case.Redundant: if (! isset($params['foo']) || empty($params['foo'])) {…}
.
This is equivalent to: if (empty($params['foo'])) {…}
.
Not very readable: foreach ($items as $item) {…}
.
For example, improve it this way: foreach ($allItems as $item) {…}
.