PHP 8 tricks that will help you write cleaner code
A compilation of some tricks that we can use in PHP to write better code
Today I wanted to create an article with a collection of tricks that will help us write cleaner PHP code. I wanted to prepare an article of this type because many times every day forces us to go much faster than we should causing us to not delve into the language or be aware of the latest developments that appear in each version.
So let’s see them. I hope you find them useful for your projects.
1. Null coalescing operator
For me this operator is one of the most useful. Its appearance took place with the output of PHP 7.0 and will allow us to save some code in this type of checks:
$someArray = ['one' => 'foo', 'two' => 'bar'];$one = isset($someArray['one'] ? $someArray['one'] : 'empty';
// 'foo'$three = isset($someArray['three'] ? $someArray['three] : 'empty';
// 'empty'
Since it will allow us to simplify them as follows:
$someArray = ['one' => 'foo', 'two' => 'bar'];$one = $someArray['one'] ?? 'empty';
// 'foo'$three = $someArray['three] ?? 'empty';
// 'empty'
That is, thanks to the operator? (called “null coalescing operator”) we can save the isset check every time we want to check if a key is in an array. Very very useful and much cleaner.
2. Invokable classes
This is one of the concepts that are often unknown when working with classes in PHP and that however are beginning to become popular thanks to frameworks such as Symfony that use them repeatedly in certain situations.
What is an invokable class? Well, as its name implies, it is a class that we can invoke as if it were a function.
This is possible thanks to the magical __invoke
method of PHP that we can declare within our class:
class A {
public function __invoke() {
print_r('Hello world!);
}
}$a = new A();
($a)(); // 'Hello World'class B {
public function __invoke(int $a): int {
return $a * 2;
}
}$b = new B();
($b)(5); // 10
As you can see, by adding the invoke
method within our class we can use an instance of it as if it were a function. To do this, simply enclose it in parentheses and PHP will interpret it for us to call the __invoke
method of the object.
What is its usefulness? For example, to define Event Listeners
o Message Handlers
that only need to have the public method in charge of processing the event or message implemented.
Thanks to the possibility of declaring invoked classes it is not necessary to call a method of the particular class.
3. Traits
About PHP “traits” I already prepared an article at the time explaining what they are and how to use them to create reusable code between our classes:
However, I have thought it convenient to mention them in this article because of the possibility they give us when grouping common code of different classes and isolating it into a component.
For example, suppose we have a few classes that have the property createdAt
:
// A.php<?phpclass A {private $createdAt;public function getCreatedAt(): \DateTimeInterface {
return $this->createdAt;
}public function setCreatedAt(\DateTimeInterface $createdAt): self {
$this->createdAt = $createdAt;
return $this;
} // getters and setters and rest of properties
}// B.phpclass B {private $createdAt; public function getCreatedAt(): \DateTimeInterface {
return $this->createdAt;
} public function setCreatedAt(\DateTimeInterface $createdAt): self {
$this->createdAt = $createdAt;
return $this;
} // getters and setters and rest of properties
}
This code, being common to them, can be grouped into a Trait so that every time we want to implement this functionality it is not necessary to copy and paste:
// Timestampable.phptrait Timestampable {private $createdAt; public function getCreatedAt(): \DateTimeInterface {
return $this->createdAt;
} public function setCreatedAt(\DateTimeInterface $createdAt): self {
$this->createdAt = $createdAt;
return $this;
}}// A.php<?phpclass A { use Timestampable; // getters and setters and rest of properties
}// B.phpclass B { use Timestampable; // getters and setters and rest of properties
}
In this way, we will have the functionality grouped by being able to access the createdAt
variable as if it had been declared in the normal way within our class.
$a = new A();
$a->getCreatedAt();
4. array_map, array_filter, array_reduce
Now that it is so fashionable to use the declarative programming style (especially in Javascript) it is worth remembering the possibility we have of using these functions to iterate over the arrays.
array_map
allows us to iterate over each of the elements of an array to operate on them and generate a new array:
// imperative$myArray = [1, 2, 3];
$multipliedArray = [];
foreach ($myArray as $item) {
$multipliedArray[] = $item * 2;
}// declarative$multipliedArray = array_map(
function(int $item) { return $item * 2; },
$myArray
);
array_filter
allows us to filter the elements of an array based on a condition:
// imperative$myArray = [1, 2, 3];
$filteredArray = [];
foreach ($myArray as $item) {
if ($item % 2 === 0) {
$filteredArray[] = $item;
}
}// declarative$filteredArray = array_filter(
$myArray,
function(int $item) { return $item % 2 === 0; }
);
array_reduce
allows us to reduce an array to a value by accumulating the result in a variable. For example, it serves to add the elements of an array:
// imperative$myArray = [1, 2, 3];
$total = 0;
foreach ($myArray as $item) {
$total += $item;
}// declarative$total = array_reduce(
$myArray,
function(int $ac, int $item) { return $ac + $item; },
0
);
5. Destructuring arrays
This is one of the features that I like most about PHP (probably because I am very used to Javascript) and probably more unknown: the possibility of extracting elements from an array without having to access them through their key or position.
For example:
$people = [
[1, 'Tom'],
[2, 'Fred'],
];
// Estilo de []
[$firstPerson, $secondPerson] = $people;[$id, $name] = $firstPerson;
This can also be used within foreach
loops such as:
foreach ($people as [$id, $name]) {
// do something
}
This provides us with a very clean way to access the arrays without having to explicitly resort to their position.
6. Arrow functions
Linking with the use of the array_map
, array_reduce
andarray_filter
functions with the arrival of PHP 7.4 (which will be released onNovember 28, 2019) we will have an important novelty: to be able to use “arrow functions”.
In this way the functional programming style is reinforced while we slightly lighten the code of certain expressions:
$numbers = [1, 2, 3];
$multipliedNumbers = array_map(fn($x) => $x * 2, $numbers);
In this way, we can write functions of a single line when we need to declare anonymous or callables making it much easier to read the code.
I think this type of thing is where you can see the effort that the PHP team is doing to update the language in order to evolve its syntax and give us better tools to develop.
Is PHP dead? No I don’t think so.
7. Invoke methods and functions using variables
Another possible big unknown and that however can give us great versatility to our code: the possibility of invoking a function or method by means of a variable that contains a string with the name of the function or method to invoke.
For example:
class A {
public function someMethod() {
echo 'hello world';
}
}$a = new A();
$method = 'someMethod';
$a->$someMethod(); // hello world
This is usually useful to define for example callbacks so that we can tell the function to call the callback which method of our object to use.
class Invoker {
public function executeMethod($object, string $method) {
$object->$method();
}
}class A {
public function doSomething() {
echo 'hello world';
}
}$a = new A();
$invoker = new Invoker();
$invoker->executeMethod($a, 'doSomething');
8. Finally statement
The finally
statement allows us to execute code at the end of a try/catch
statement so that we can carry out a task regardless of the execution flow that has been followed.
For example, we can use it to close a file using fclose
once we have finished writing to it or if for some reason an exception occurred during the execution of the code inside try
:
$file = fopen('log.txt', 'a');
try {
fwrite($file, 'Throwing exception..');
throw new \Exception();
} catch (\Exception $e) {
echo 'Threw a RangeException: ' . $e->getMessage();
} finally {
// Always make sure that we close the file
echo 'Reached the finally block';
fwrite($file, 'Reached the finally block');
fclose($file);
}
Conclusions
I hope that these eight tips for writing cleaner code in PHP have been interesting and that they help you to continue improving as developers.
I also leave a couple of articles where I talk about the news of PHP 7.3 and PHP 7.4 in case you want to keep up to date with the new tools we have:
Do you want to read more articles like this?
If you liked this article I encourage you to subscribe to the newsletter that I send every Sunday with similar publications to this and more recommended content: 👇👇👇