Variables
Meaningful
Use meaningful and pronounceable variable names
Bad:
$ymdstr = $moment->format('y-m-d');
Good:
$currentDate = $moment->format('y-m-d');
Vocabulary
Use the same vocabulary for the same type of variable
Bad:
getUserInfo();
getUserData();
getUserRecord();
getUserProfile();
Good:
getUser();
Searchable
We will read more code than we will ever write. It's important that the code we do write is readable and searchable. By not naming variables that end up being meaningful for understanding our program, we hurt our readers. Make your names searchable.
Bad:
// What the heck is 448 for?
$result = $serializer->serialize($data, 448);
Good:
$json = $serializer->serialize($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Bad:
class User
{
// What the heck is 7 for?
public $access = 7;
}
// What the heck is 4 for?
if ($user->access & 4) {
// ...
}
// What's going on here?
$user->access ^= 2;
Good:
class User
{
public const ACCESS_READ = 1;
public const ACCESS_CREATE = 2;
public const ACCESS_UPDATE = 4;
public const ACCESS_DELETE = 8;
// User as default can read, create and update something
public $access = self::ACCESS_READ | self::ACCESS_CREATE | self::ACCESS_UPDATE;
}
if ($user->access & User::ACCESS_UPDATE) {
// do edit ...
}
// Deny access rights to create something
$user->access ^= User::ACCESS_CREATE;
Explanatory
Use explanatory variables
Bad:
$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);
saveCityZipCode($matches[1], $matches[2]);
Not Bad:
It's better, but we are still heavily dependent on regex.
$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);
[, $city, $zipCode] = $matches;
saveCityZipCode($city, $zipCode);
Good:
$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);
saveCityZipCode($matches['city'], $matches['zipCode']);
Nesting
Avoid nesting too deeply and return early (part 1) Too many if-else statements can make your code hard to follow. Explicit is better than implicit.
Bad:
function isShopOpen($day): bool
{
if ($day) {
if (is_string($day)) {
$day = strtolower($day);
if ($day === 'friday') {
return true;
} elseif ($day === 'saturday') {
return true;
} elseif ($day === 'sunday') {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
Good:
function isShopOpen(string $day): bool
{
if (empty($day)) {
return false;
}
$openingDays = [
'friday', 'saturday', 'sunday'
];
return in_array(strtolower($day), $openingDays, true);
}
Bad:
function fibonacci(int $n)
{
if ($n < 50) {
if ($n !== 0) {
if ($n !== 1) {
return fibonacci($n - 1) + fibonacci($n - 2);
} else {
return 1;
}
} else {
return 0;
}
} else {
return 'Not supported';
}
}
Good:
function fibonacci(int $n): int
{
if ($n === 0 || $n === 1) {
return $n;
}
if ($n >= 50) {
throw new \Exception('Not supported');
}
return fibonacci($n - 1) + fibonacci($n - 2);
}
Mapping
Avoid Mental Mapping, don’t force the reader of your code to translate what the variable means. Explicit is better than implicit.
Bad:
$l = ['Austin', 'New York', 'San Francisco'];
for ($i = 0; $i < count($l); $i++) {
$li = $l[$i];
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
// Wait, what is `$li` for again?
dispatch($li);
}
Good:
$locations = ['Austin', 'New York', 'San Francisco'];
foreach ($locations as $location) {
doStuff();
doSomeOtherStuff();
// ...
// ...
// ...
dispatch($location);
}
Context
Don't add unneeded context, If your class/object name tells you something, don't repeat that in your variable name.
Bad:
class Car
{
public $carMake;
public $carModel;
public $carColor;
//...
}
Good:
class Car
{
public $make;
public $model;
public $color;
//...
}
Defaults
Use default arguments instead of short circuiting or conditionals
Bad:
This is not good because $breweryName can be NULL.
function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void
{
// ...
}
Not bad: This opinion is more understandable than the previous version, but it better controls the value of the variable.
function createMicrobrewery($name = null): void
{
$breweryName = $name ?: 'Hipster Brew Co.';
// ...
}
Good:
You can use type hinting and be sure that the $breweryName will not be NULL.
function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void
{
// ...
}
