Good content takes time and effort to come up with.

Please consider supporting us by just disabling your AD BLOCKER and reloading this page again.







Write Clean Code In PHP | StackCoder


Writing Clean Code In PHP


09th August 2020 8 mins read
Share On     Share On WhatsApp     Share On LinkedIn


In this article, let's learn how to write clean code in PHP. These tips help you to write readable, reusable & refactorable code in PHP.


Comment Your Code


Comment comment comment your code. This doesn't mean that you start commenting everywhere in your code and create shit load of unwanted comments. If you do so then your failing to express the code you had written to other developers.


Comment whenever it's necessary, when you have some complicated code or expression so that developers and you at later point will understand what you were trying to achieve.


Bad

/** Get the user details */
public function getUser(int $id)
{
  /** Fetch the user details by id */
  $user = User::where('id', $id)->first();

  /** Calling function to calculate user's current month salary */
  $this->currentMonthSalary($user);
}

/** Calculating the current month salary of user */
private function currentMonthSalary(User $user)
{
  /** Salary = (Total Days - Leave Days) * PerDay Salary */
  // ...
}


Better


public function getUser(int $id)
{
  $user = User::where('id', $id)->first();

  $this->currentMonthSalary($user);
}

private function currentMonthSalary(User $user)
{
  /** Salary = (Total Days - Leave Days) * PerDay Salary */
  // ...
}

Use Proper Opening And Closing Tags <?php ?>


Sometimes developers try to take shortcuts when declaring PHP like the following, so that you don't have to think on enabling short tags syntax in php.ini files.


Bad

<?
  echo "Hello world";
?>
 
<?="Hello world"; ?>
 
<% echo "Hello world"; %>


Good

<?php 
  echo 'Hello world';
?>

Use Meaningful & Pronounceable Variable Names


Bad

$ymdstr = date('d-M-Y', strtotime($customer->created_at));


Good

$customerRegisteredDate = date('d-M-Y', strtotime($customer->created_at));

Use Proper & Meaningful Method Names


Bad

public function user($email)
{
    // ...
}


Good

public function getUserDetailsByEmail($email)
{
    // ...
}

Use The Same Vocabulary For Same Type Of Variable


Bad

getUserInfo();
getUserData();
getUserRecord();
getUserProfile();


Good

getUser();

Readable & Searchable Code


Try to use CONSTANTS or Functions for more readable & searchable code. This helps you very much in a longer run


Bad

// What the heck is 1 & 2 for?
if ($user->gender == 1) {
    // ...
}

if ($user->gender == 2) {
    // ...
}


Good

public const MALE = 1;
public const FEMALE = 2;

if ($user->gender == MALE) {
    // ...
}

if ($user->gender == FEMALE) {
    // ...
}

Avoid Deep Nesting & Return Early


Avoid deep nesting as much as possible and use early returns.


Bad

function isShopOpen($day)
{
    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;
    }
}


Not Bad

function isShopOpen($day)
{
    if (empty($day)) {
        return false;
    }
    
    $openDays = ['friday', 'saturday', 'sunday'];
    return in_array(strtolower($day), $openDays) ? true : false;
}


Good

function isShopOpen($day)
{
    if (empty($day)) {
        return false;
    }


    return in_array(strtolower($day), ['friday', 'saturday', 'sunday']) ? true : false;
}

Early False/Negation Returns


Try checking for false conditions or negation conditions first so that the valid code remains at the bottom of the functions, this will help in readability and maintainability of the code


Bad

function isShopOpen($day)
{
    if (!empty($day)) {
        return in_array(strtolower($day), ['friday', 'saturday', 'sunday']) ? true : false;
    }
    return false;
}


Good

function isShopOpen($day)
{
    if (empty($day)) {
        return false;
    }
    return in_array(strtolower($day), ['friday', 'saturday', 'sunday']) ? true : false;
}

Avoid Mental Mapping


Don’t force the reader of your code to translate what the variable means.


Bad

$l = ['Austin', 'New York', 'San Francisco'];

for ($i = 0; $i < count($l); $i++) {
    $li = $l[$i];

    doSomething();
    // ...

    dispatch($li);
}


Good

$locations = ['Austin', 'New York', 'San Francisco'];

foreach ($locations as $location) {
    doSomething();
    // ...

    dispatch($location);
}

Avoid Useless Variables As Much As Possible


Basically if you use the variable more than 2 times in a code then keep that variable else directly use it inside the code. This improves the readability and makes your code very cleaner.


Bad

public function create()
{
    $zones = Zone::get();

    $data = [
        'zones' => $zones,
    ];

    return view('customer.create', [
        'data' => $data
    ]);
} 


Good

public function create()
{
    return view('customer.create', [
        'zones' => Zone::get()
    ]);
} 

Don't Use Abbreviations


Abbreviations are nothing but your butler words or short words which you basically use in message texting.


Bad

$ord = Order::create($data);
// ...
$ord->notify();


Good

$order = Order::create($data);
// ...
$order->createNotification();

Don't Add Un-Needed 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;
    // ...
}

Use Type Hinting For Method Parameters


Basically the parameter that you use with the methods will be interpreted differently by different users.


So, if you use Type Hinting then it will help the users reading your code, even your IDE will type hint the code and try to auto complete, and PHP will throw proper errors and warnings on the same.


Bad

Here we don't know whether the parameter $user is an integer, array, object or any other type

public function show($user)
{
  //
}


Good

public function show(User $user)
{
    // ...
}


public function schoolFunction(array $guests)
{
    // ...
}

Use Default Arguments Instead Of Short-Circuiting Or Conditionals


Not Good

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
{
    // ...
}

Use Ternary Operator ( ?: )


Bad

if ($today == 'sunday') {
    return true;
} else {
    return false;
}


Good

return ($today == 'sunday') ? true : false;

Null Coalescing Operator ( ?? )


Null Coalescing operator checks if the variable or the condition was empty or not.


Bad


if (!empty($user)) {
  return $user;
}

return false;


Good

return $user ?? false;

Comparison (===, !==)


Bad

The simple comparison will convert the string in an integer.


$a = '42';
$b = 42;

if ($a != $b) {
    // The expression will always pass
}

The comparison $a != $b returns FALSE but in fact it's TRUE! The string 42 is different than the integer 42.


Good

The identical comparison will compare type and value.


$a = '42';
$b = 42;

if ($a !== $b) {
    // The expression is verified
}

The comparison $a !== $b returns TRUE.


Encapsulate Conditionals


Writing conditions is not bad but if you encapsulate into methods/functions then it will help better readability and maintain code in future.


Bad

if ($article->status === 'published') {
    // ...
}


Good

if ($article->isPublished()) {
    // ...
}

Remove Dead Code

Dead code is just as bad as duplicate code. There's no reason to keep it in your codebase. If it's not being called, get rid of it! It will still be safe in your version history if you still need it.


Bad

function oldGetUser()
{
    // ...
}

function getUser()
{
    // ...
}

$request = getUser();


Good

function getUser()
{
    // ...
}

$request = getUser();

PDO Over mysqli or mysql functions


Problem


Ya I know its very hard to come out of mysql or mysqli function for database connections in PHP. But you will end up facing the following problems.


  1. SQL Injection. If you need to avoid then you have to use mysql escaping and other stuff.
  2. If you change from one database to another you will end up writing other database drive SQL queries


Solution


Where as if you use PDO then there are many advantages like


  1. Protection against SQL Injection.
  2. PDO acts as a DBAL or similar to your ORM layer, which means tomorrow if you change the database to another supported database driver then no need to rewrite any queries nor use any other complicated stuff for code migration.

Use Composer For Dependency Management


If you are still downloading the libraries and manually adding them or if your still using PEAR then better check composer.


Composer is a PHP Dependency manger. This will automatically add, update, remove the libraries for your project with just a simple commands.


If you would like to learn more on composer then please check the following articles


What Is Composer? How Does It Work? Useful Composer Commands And Usage

Composer Install v/s Composer Update

composer.json v/s composer.lock


Template Engines Over HTML & PHP Scrambled View Pages


Problem


If you use plain HTML/PHP view pages then you might face the following problems


  1. Lot of opening and closing PHP tags.
  2. Escaping (browser safe display) the HTML/PHP output must be handled manually.
  3. Session management might be trickier.
  4. View pages templating might end up complicated or not that optimized.
  5. Form old data for failed validation must be handled manually.


Solution


Start using templating engines like smarty, twig, mustache, dwoo


  1. Very clean syntax usage.
  2. Built-in auto escaping (browser safe display) the HTML/PHP output.
  3. Tries to separate logic and view page, but again it depends on us how do we implement it.
  4. Session management are simpler for usage.
  5. View pages templating are dam super cool with inheritance and other super cool stuff.
  6. Some template engines caches your pages which will ultimate result in fast rendering.
  7. Form old data for failed validation handling is built-in.

Run The Scripts With Time Limit


Bad


Sometimes you might be prompted to run you scripts with unlimited time. But that totally bad idea to change in php.ini file


Good


If you really want to run specific scripts without any time limit then you can only use the time limit on top of that script file or method like the following


ini_set('max_execution_time', '300'); //300 seconds = 5 minutes
ini_set('max_execution_time', '0'); // for infinite time of execution 

Always Validate Incoming Data


Never trust your users, always validate any form you have in your website.


Basically 2 types of validation


1. Client side validation - done on the HTML part with Javascript or Javascript libraries like jQuery validate.

2. Server Side validation - Even if you omit the client side validation never ever skip your server side validation. Here you will validate on the server side ie. PHP side.


Cache Database Queries


Bad


  1. Never fetch all the records at a stretch from database. 
  2. If the records are huge then it may slow down your application and sometime may crash you website page.


Good


  1. Limit your records while fetching database records.
  2. Cache more frequently used query using REDIS, MEMCACHE or any other caches.


Eg: listing pages, same query frequently used


Turn On Error Reporting Only During Development


Turn on error reporting during development and turn off when you deploy the project to production so that your users don't see weird error on their browsers.


If you are using plain PHP then you may configure you init.php like the following


if(!defined('ENVIRONMENT')){
    define('ENVIRONMENT', 'DEVELOPMENT');
}

if (defined('ENVIRONMENT'))
{
    switch (ENVIRONMENT)
    {
        case 'DEVELOPMENT':
            $base_url = 'http://localhost/product/';
            ini_set('display_errors', 1);
            ini_set('display_startup_errors', 1);
            error_reporting(E_ALL|E_STRICT);
            break;


        case 'PRODUCTION':
            $base_url = 'Production URL'; /* https://google.com */
            error_reporting(0);
            /* Mechanism to log errors */
            break;


        default:
            exit('The application environment is not set correctly.');
    }
}

Conclusion


Most of the code has been adopted from Clean Code PHP & few of my experiences.


Will keep updating the article meanwhile don't forget to checkout my other articles. Hope this article helped you. Please share it with your friends.




Author Image
AUTHOR

Channaveer Hakari

I am a full-stack developer working at WifiDabba India Pvt Ltd. I started this blog so that I can share my knowledge and enhance my skills with constant learning.

Never stop learning. If you stop learning, you stop growing