1

Clean Code in PHP

 1 year ago
source link: https://devm.io/php/clean-code-php
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Do you want to create software that is easy to maintain and has as few bugs as possible? Or write code that others, but also you, can still understand after weeks or even months? Maybe clean code is something for you.

Most software developers, of course, want to write "good" or "clean" code. But it's not that trivial; otherwise, we wouldn't be discussing it. But where do we begin? And what, after all, is "clean" code?

What exactly is "clean code"?

The term "clean code" was popularised by Robert C. Martin, also known as Uncle Bob, and his standard work of the same name. [1] There is no truly uniform definition; in essence, it is code that is written simply and directly and can be read, understood, and modified without difficulty by other developers. Clean code is free of duplication, does not obscure the intentions of the authors, and is thoroughly covered by automated testing.

Over the years, many proven solutions and principles in the field of software development have emerged, on which clean code is based. These are not limited to a single programming language; many of the principles and approaches discussed later in this article also apply to most object-oriented languages.

To be clear, writing clean code is a time-consuming process. Unfortunately, we cannot teach you all the necessary skills in this article. Rather, we want to provide you with the resources you need to get started on this path, as well as pique your interest.

Naming

It is not always easy to name things correctly, that is, in a meaningful way. That is why naming is so important in clean code.

Although it should be common knowledge that variables are no longer abbreviated with a few letters, this practise persists. Count variables like $i and $j may still be borderline cases for simple loops, but using $row and $column instead, for example, to iterate over a CSV file, will help.

Names should be concise but meaningful. Placeholders like Manager or Processor, on the other hand, add no value, and humorous names or puns should be avoided. Cryptic and unpronounceable abbreviations cause more confusion than they solve. However, it is helpful to define fixed words for specific concepts. So, instead of using a combination of set, update, and put for updating values, stick to one word.

So don't be upset if you spend some time deciding on names for variables, classes, or methods. Take your time; it will be well worth it. Also, be open to change and listen to feedback from other developers.

Design principles

Clean code is based on several design principles that we should keep in mind when writing code. We will present a few basic principles in the following part, though you have probably encountered one or two of them elsewhere.

DRY

DRY (Don't Repeat Yourself) is possibly the oldest programming principle. Even in the early days of software development, it felt necessary to outsource repetitive code into subroutines, primarily to save precious memory. As programmes grew, it became clear that redundant code should be avoided to ensure maintainability.

However, the opposite of DRY is all too common: copy-and-paste programming. A piece of code is quickly duplicated, and evil takes its course. Bug fixes or other changes must be made in multiple locations if they can be found at all. Each copy is then altered slightly to perfect the chaos. Resist the temptation to allow code duplication. It will undoubtedly come back to haunt you one day.

KISS

KISS (Keep It Simple, Stupid) reminds us to look for the simplest solution to a problem. I wonder who hasn’t felt this way: we're proud of our abilities and want to flaunt them. Then, at the next available opportunity, we overshoot and write a fantastic algorithm for which there is already a thoroughly tested function in the SPL library (Standard PHP Library) that comes with PHP by default. A quick internet search on the issue in question would have saved us a lot of time. Clean code is as simple as possible. Although adventurous one-liners demonstrate how well we can juggle ternary operators, they are much more difficult to read and maintain than a well-readable if statement over several lines, as shown in Listing 1.

Listing 1

// nested ternary operators
$number > 0 ? 'Positive' : ($number < 0 ? 'Negative' : 'Zero');
 
// If-Anweisung
if ($number > 0) {
	echo 'Positive';
} elseif ($number < 0) {
	echo 'Negative';
} else {
	echo 'Zero';
}

It doesn’t help anyone if the bug is not found quickly the next time it fails on the production system because it has been successfully hidden in our code art. In any case, our colleagues will not thank us for it.

YAGNI

YAGNI (You Ain't Gonna Need It) is a continuation of KISS: don't programme anything you don't need right now. The code remains leaner, making it easier to maintain.

Because there are more requirements than you expected, the probability is that you will have to discard the code or radically change it. In the worst-case scenario, the unnecessary code remains in your software. After a while, nobody understands why it was written in the first place. And reading. understanding, testing, and making changes to the source code costs time.

This is not to say that we should not plan ahead of time. If it is clear that a feature we are currently working on will be made multilingually translatable in the next sprint, it can't hurt to keep this in mind and take sensible precautions.

YAGNI, like KISS, is meant to encourage us to simplify by always questioning our decisions. Is a composer package really required for a single function? Is it really necessary to programme a process, or are there ready-made solutions on the market?

SOLID

Of course, SOLID cannot be left out of this list. SOLID is an acronym for a set of five principles that are commonly used in object-oriented programming and are thus ideal for PHP. Let's look at each principle in more detail below.

Single Responsibility Principle (SRP): The SRP states that a module (typically a class) should only change for one reason. This does not, however, imply that each class should have only one responsibility, as is commonly assumed [2]. Rather, it means that the module should be accountable to only one actor.

For example, if a module contains two functions, one of which is used by actor 1 and the other by actor 2, these two functions should not be in the same class. If changes are later required for one actor, the behaviour of the other function may be affected (and thus indirectly affect the other actor).

Open Closed Principle (OCP): The behaviour of a class should be extensible without requiring modification. We can accomplish this primarily through polymorphism, which is the use of a single interface for multiple manifestations of an object.

To be prepared for different use cases, we define an interface for the method rather than inflating the code with multiple if-else constructs. This interface is then implemented by different classes, which implement this method in a variety of ways, depending on the use case.

A common example is a function called readFile() that is supposed to read data from both CSV and Excel files. Rather than combining these two tasks in a single class, we define an interface for readFile(), which is then implemented by two classes: one for CSV files and one for Excel files.

Liskov Substitution Principle (LSP): Behind the complicated name lies the simple principle that subtypes must behave like their base type. They may only extend, but not change, the functionality of the base type. These may be obvious properties like Return Types, which an inherited class should not change. When we use Return Types, we force the inherited class to behave like the base class, at least in terms of return values, as shown in Listing 2.

Listing 2

class BaseClass
{
	public function getValue()
	{
    	return 1;
	}
}
 
// Verletzung des LSP, da der return  // type sich ändert
class SubClass extends BaseClass
{
	public function getValue()
	{
    	return 'result: ' . $this->getValue();
  }
}

Without Return Types, the above example would be valid PHP code. If Return Types were used, the LSP violation would result in an error, as shown in Listing 3.

Listing 3

class BaseClass
{
	public function getValue(): int
	{
    	return 1;
	}
}
 
// Causes PHP error, because  // return type does not match the // of BaseClass
class SubClass extends BaseClass
{
   public function getValue(): string
	{
    	return 'result: ' . $this->getValue();
	}
}

However, less obvious behaviour, such as throwing exceptions in certain circumstances, should be consistent with the base type. If the behaviour here is inconsistent, bugs are pre-programmed, which are frequently difficult to find.

Interface Segregation Principle (ISP): The Interface Segregation Principle states that a client should only rely on the specifics of a service that it requires. For example, a class that implements an interface should only implement the methods that are truly required for the use case.

Instead of providing a comprehensive interface that is ready for any eventuality and contains a correspondingly large number of methods, it is preferable to implement several, specialised interfaces that focus on a single aspect. The advantage of this is that the class has fewer dependencies, reducing so-called coupling. Since PHP allows classes to implement multiple interfaces, this principle is simple to put into practise.

Dependency Inversion Principle (DIP): To create a system that is easy to maintain and resilient, we must consider which code parts may be particularly affected by changes. The file system is an example: rather than always writing to a local drive, we should extract that part and move it to a low-level class. For example, if we want to store our files in a cloud bucket because our application is no longer running on a single server but in the cloud (which happens quite often), we simply swap out the low-level class without modifying the high-level class.

We implement an interface for file system accesses and thus reverse the dependency so that the high-level class is not required to be aware of the implementation details of the dependency. The high-level class is only aware of one interface,...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK