Nikolay Andonov

Hi, I'm Nikolay

Web Developer, Wannabe Doer

Unpopular PHP Features, Part 3

5th of October, 2020

Here is a list of PHP features which I use in my day-to-day life as programmer, but they weren't the first thing I learnt in the language. I'll admit they are not that unpopular compared to the ones I shared in my previous two articles, but after some thought, I decided they are worth their place in this series.

Generators

When we work with a huge amount of data we don't want to load it in-memory. Let's imagine we have a huge file to read. Using file_get_contents() will load it in-memory. Reading the file with fopen()/fgets() line by line and pushing to an array has the exact same effect. However, instead of pushing to an array, we can yield the current line and load only one line at a time in-memory.

I'll admit the first time I saw the yield statement I didn't know what was going on. Luckily for me, that happenned while I was pairing with a skilled collegue of mine, and I remember his explanation to this very day (even tho that's a story from 2016):

You know a function can return just once, right? Now imagine you can do that multiple times, and every time you go back in the function it will continue the execution from the exact place you returned the last time. That's exactly what the yield statement does.

While that may not be the best explanation from technical point of view, it was good enough for me to wrap my head around it, so I guess it would be good enough for someone else as well.

Laravel 6+ users can reduce their memory usage when dealing with huge amount of database records by using User::cursor() instead of User::all(). The first one will give an instance of Lazy Collections (meaning it's loading just one record in memory at a time) while the latter is the usual Laravel collection (meaning it loads all the records in memory). There is a trade-off here, tho, the processing time will be higher for the first example. So be careful when you reach out to this feature.

Generators are available since PHP 5.5.0. More on them, including examples, you can find in the official PHP docs. If you are a Laravel user, click the Lazy Collections link above and read what the great Joseph Silber had to share about them.

The BC Math Functions

Have you ever had to make math operations with float numbers? And have you heard that you can not trust them?

There is also bcadd() for adding, bccomp for comparing, bcdiv for dividing, bcpow for "powering", bcmod for getting modulus, and a few more you can find in the official PHP docs

The + operator for arrays

I was taught to use array_merge() when I want to merge arrays. However, I find myself reaching out for the + operator more often, because it doesn't allow overriding keys.

++ before the variable

Everyone knows what $usersCount++ does, right? Surprisingly, not many people are aware you can put the ++ before the variable, which makes the increment takes priority before other operations, which can save a line sometimes. The latter is actually the reason I use it every now and then, I love when I am reducing lines of code.

mb_* string functions

Have you ever used strlen() for a user input? Fe. to validate the max number of characters users can use for their username or something? Then I believe you have a bug to fix now if you have worlwide users. Luckily, it's as easy as prefixing your function with mb_.

It's not only the strlen() function. That's actually happenning for most of the PHP functions which manipulate strings. Even worse, the same issue is valid when we manipulate a character on given index. Ie $name = 'Jeff'; $name[1] = 'Д'; will give us b"JÐff" which I imagine is not what we aim to achieve. I am sharing this simply because I was recently bitten by this, even tho I knew about the binary-safe issues mentioned above.

Argument Unpacking

Since PHP 7.4 came out, I've seen a lot of examples out there for the spread operator. Fe. ['orange', ...$otherColors, 'blue'] But did you know we have the same syntax (ie ...) for accepting any number of arguments as they were passed as array? What's cooler is we can also do the other way around - pass an array to a function, prefixed with ..., and it will behave like we passed the values from the array as seperate arguments. I've seen code that combines these two in the same function, and it looks neat! The following is taken from the Laravel codebase (it's simplified for the sake of the example)

We have this since PHP 5.6. More info in the docs

The ArrayAccess interface

Let's say we have our own class, and we want to allow all instances of that class to be accessible as they were arrays, and not objects. Imagine we have an instance of a user $user = new User(). Calling $user['name'] without implementing the ArrayAccess interface will result in error. The only way to access data on the object is to use the regular syntax, ie $user->name.

Laravel users probably know they can do that on all their Eloquent models. Here's the Eloquent implementation of the interface. Note that it's not simplified at all, it's really that simple to implement this interface.

This feature is available since the release of PHP 5.

Instantiating and calling a method

The previous example of $user = new User(), followed by another statement of $name = $user->name leads us to another underrated feature. Which again I use just to save an extra line of code. When we instantiate an object just for the sake of accessing a single property/method on it, we can do that on the same statement. $name = (new User)->name. Pretty neat, and again something that wasn't obvious for me from the get-go.

Array destructuring

The list() language construct (yep, it seems like it's a function but it's not) allows us to destructure arrays. If you are not familiar with destructuring, take a look at the following example:

The example above will work for PHP 7.1+, tho. Before that we could use list() only for numerical arrays which starts with the index of 0.

That's all I got

I just lied. I had few more things I wanted to put on this list, but I feel like it's already way too big. So I ended up cutting few minor things, buuutt... that's life.

In case you enjoyed this article, and missed the previous two articles in the series, here you can find part 1 and part 2 (which covers PHP 7+ features only)