What’s New in PHP 8 - Part 3

Ronaldo B.July 27, 202214 min read

In this article

We have reached the third article about the new features of PHP 8, now already knowing the official logo of this version of the language. You can check the other two articles in this series at the links below:

What's New in PHP 8 - Part 1

What's New in PHP 8 - Part 2

In this article we will talk about 8 more new features of PHP 8. So let's go!

Named Arguments

When we work with functions or methods, we always hear about arguments or parameters. And we know that the order in which we provide these values can make all the difference in the proper functioning of the code.

The PHP language has always had arguments referenced by their position. But with version 8, that changed. Now we have named arguments. This means we can make it clear which argument the values refer to. Let's see an example of this.

Let's create a function that will return an array of the provided data:

function create_user($username = "admin", $password = "admin", $is_admin = true) {
	$data = [
		'username' => $username,
		'password' => $password,
		'admin' => $is_admin
	];
	return $data;
}

Note that this function has a default value for all arguments. Imagine we want to call this function, but providing only the $password argument. To do this, just pass the name of the argument without the $ sign, define a : (colon), and then provide its value:

print_r(create_user(password: '123456'));

This code will produce the following result:

Result of our function in the browser

Notice that the password information was recognized correctly, but the other two parameters received their default values. Through named arguments we can also provide arguments in any order we want; we no longer have to be chained to the order defined in the function. For example, if we want to provide the third argument and then the first, there is no problem:

print_r(create_user(is_admin: 0, username: 'support'));

The result of this code will be as follows:

Result of our function in the browser

The data is also recognized. Impressive, isn't it?

This same pattern can be used in native PHP functions. We can see an example of this with the array_fill() function, which is used to create a custom array with the values we set. It expects three parameters: 1) start_index, which represents the starting index of our array; 2) count, which represents the number of items that the array will have; and 3) value, which is the value of the items. If we want to use named arguments with this function, we can use the following code:

print_r(array_fill(value: 'Hcode', start_index: 0, count: 10));

The result will be as follows:

Array generated by the array_fill() function

Our array was created successfully ?.

Match Expression

The switch() statement is one of the most used control flow structures in any programming language, and PHP is no different. In version 8 of PHP, we will have a new feature that promises to simplify this structure, the match() expression. Its structure resembles switch(), but is a bit simpler. Let's see an example to compare their syntaxes.

Imagine we want to create a control flow that can identify a programmer's knowledge level or career, classifying them as “Junior”, “Mid-level” or “Senior” based on an identifier. We could do this with the following code:

$level_number = 3;
switch ($level_number) {
	case 1:
		$level = 'Senior';
		break;
	case 2:
		$level = 'Mid-level';
		break;
	case 3:
		$level = 'Junior';
		break;
}
echo $level;

The result would be as follows:

Result of our switch() in the browser

We see that the code worked correctly. We could write the same code using the match expression like this:

echo match($level_number) {
	1 => 'Senior',
	2 => 'Mid-level',
	3 => 'Junior'
};

The result would be the same, but note that we wrote much less this time. We called the echo constructor directly with match(), which is not possible with switch(). Moreover, we did not have to worry about the various breaks that are necessary in switch() to ensure that there will be no unwanted result.

The match() expression has another feature that can be seen as a good advantage. The switch() statement checks only the values that we are comparing. The match() expression checks both the value and the type of the variables. This ensures that the flow control will be even more precise. Let's see an example of this issue.

Imagine we want to check the value of the number 0. We will compare it both with its exact value and also with the string of this number. We will do this first with switch(), using this code:

switch (0) {
	case '0':
		$result = "This is the string zero";
		break;
	case 0:
		$result = "This is the number zero";
	break;
}

echo $result;

In your opinion, what will be the returned value? Will it be able to understand that we are actually looking for the number zero? When we access the browser, we see the following result:

Return of our switch() in the browser

The switch() identified the string of the number zero as the sought value, as it checks only the value. Now let's execute the same code using the match() expression:

echo match (0) {
	'0' => 'This is the string zero',
	0 => 'This is the number zero'
};

When we access the browser, the value returned now is the following:

String returned by the match() expression

Excellent, now we have indeed identified the number zero, because match() checks both the value and the type of the value being compared.

Another feature of the match expression is that it allows defining more than one case for the compared values, something we already know from switch(). Imagine, for example, that we want to check what the access level of a user is based on a number. We could do this with the following code:

$level_access = 2;
echo match($level_access) {
	1, 2 => 'Administrative Access',
	3, 4 => 'Public Access'
};

Note that in this situation we defined that both value 1 and 2 can represent “Administrative Access”. Thus, when accessing the browser, the returned result will be as follows:

Return of our match() expression

The code worked correctly! And finally, we can talk about the default case, or default. It is also present in the match() expression and can be defined as follows:

echo match($level_access) {
	1, 2 => 'Administrative Access',
	3, 4 => 'Public Access',
	default => 'Public Access'
};

Now, if we define that access is 0, for example, the code will not break; the result will be as follows:

Default return of the match() expression

Something interesting we can note regarding default in match() is that, unlike switch(), it cannot be defined along with other values. In other words, the code below would not work:

echo match($level_access) {
	1, 2 => 'Administrative Access',
	3, 4, default => 'Public Access' // This part would return an error
};

Have you managed to think of situations where you could use this new PHP resource? All the issues we've discussed above help us know when we can use the match expression to simplify our code. This is certainly a very interesting novelty, isn't it?

Native Attributes in PHP

Using attributes is a habit that can help us make our code well explained. This can also help us when we need to create some type of documentation for our systems. PHP did not have any native tool that allowed us to develop these annotations. Therefore, it is very common to use third-party tools, like PHPDoc. Using this documentation generator, we could document a method using the syntax below:

class Clients {
	/**
	* @Route("/clients", methods={"POST"})
	*/
	public function create($data) {}
}

However, starting from version 8, PHP will have attribute annotations natively. Thus, we could define the same annotations as PHPDoc using the code below:

class Clients {
	#[Route("/clients", methods: ["POST"])]
	public function create($data) {}
}

If you have a friend who usually uses PHPDoc and will like this novelty of PHP 8, do not forget to share this article with him ?.

Functions str_starts_with() and str_ends_with()

PHP 8 will also introduce new functions to its resource set. Two very interesting functions are str_starts_with() and str_ends_with(). As the names show, their purpose is to check, respectively, whether a string starts and ends with a letter or set of letters. Let's see an example of each of them.

The str_starts_with() function expects two parameters: 1) a string and 2) the set of characters we are looking for at its beginning. Imagine we are working on a registration system and need to ensure that no user can register an email with the name “hcode”, as this will be a reserved identifier for a specific number of users. We could use the new str_starts_with() function for that, using the following code:

$email = '[email protected]';
if (str_starts_with($email, 'hco')) {
	echo 'This is a reserved email';
}

Thus, if someone tries to register an email that starts with “hco”, they will see the following message:

Message returned by our email check

Previously we would have needed to define the calls to the substr() and strpos() functions to perform the same check. But with the new PHP 8 feature, it has become much simpler, don't you agree?

The str_ends_with() function also expects two parameters: 1) a string and 2) the set of characters we are looking for at its end. To talk about this, let's think about the following situation: imagine we want to create a function that checks if a word is plural or singular. Generally speaking, what parameter do we take into account to find out if a word is plural? Plural words usually have an “s” at the end. We could create a ternary if() that would check this condition using the new function. The code would look like this:

echo (str_ends_with($name, 's')) ? 'This word is plural' : 'This word is singular';

Thus, if we define the $name variable as “Computer”, we will see the following result:

Return of a variable in singular

But, if we define that it will have the value “Computers”, the result will be different:

Return of a variable in plural

Of course there are exceptions to this rule regarding knowing whether a word is plural or singular. But in this example, we can see that this function can easily identify the last characters of a string and can help us a lot in other situations during development.

Function str_contains()

Another function arriving with PHP 8 is the str_contains() function. Its purpose is to check whether a string contains a certain letter or word in its structure. It expects two parameters: 1) a string and 2) the word we are looking for in it. Let's create an example. Imagine we defined a sentence within a variable:

$phrase = 'The PHP language is sensational!!!';

We want to check if this phrase contains the word “PHP”. If so, we wish to print a message on the screen. To do that, we could use the following ternary if():

if (str_contains($phrase, 'PHP')) echo 'PHP was found';

When we access the browser, we would see the following result:

Return of our str_contains() function

Note that the function was able to identify the word in the phrase and returned a boolean true.

This new function has a small detail: if we perform a search for an empty string, it will always return true. That is, the code below would always be true:

if (str_contains($phrase, '')) echo 'PHP was found';

Function fdiv()

Another function is fdiv(). It is used to perform a division between two numbers and always returns the result of the equation in floating-point notation. This function expects two parameters: 1) the dividend and 2) the divisor of the equation. See below the call of this function:

echo fdiv(450, 15);

This code returns the following result in the browser:

Return of our defined equation in code

The result was as expected. But, as we mentioned above, this function returns the value as a floating-point, or decimal. Thus, if we perform the division of two decimals, the returned value will be exact. See for example the code below:

echo fdiv(4.5, 2.8);

It will return the following result:

Result of dividing two decimals

We see that the decimal result is correct. This would not happen with other functions, such as intdiv(), which would round that result to 2.

After analyzing these characteristics, we might think: “This function is very interesting. However, I can do these same operations using the slash (/). What differential can this function offer me?”

At this moment, we can analyze a peculiarity of this new function, which can be used to handle one of the most classic programming errors: trying to divide a number by zero. If we try to do this with PHP, an error will be returned, stopping the execution of the code. However, if we perform this division using the fdiv() function, we will have a different result. See the code below:

echo fdiv(450, 0);

Normally, we would see an error returned as a result of your call, but when we access the browser, we come across this result:

Return with the new fdiv() function

We were returned the string “INF”. This return could also be “-INF” (if we perform the division with negative numbers) or “NAN” (if we divide the number 0 by 0). This concept is very similar to what we see in JavaScript, which natively returns the string “Infinity” when we try to divide a number by zero. It is now possible to achieve a similar result with PHP 8, but only if we use the fdiv() function. The zero division error remains the same if we perform this operation without the function.

Function get_debug_type()

The next function we will see is get_debug_type(). We can say that it is an alternative to the gettype() function, widely used to identify the data type of a variable. This new function aims to return data types in a way that we are more accustomed to seeing in other programming languages or even in documentation. Let's see some examples of this.

Imagine we want to check the data type of a variable that contains an integer. We will call both functions in our code:

$year = 2020;
var_dump(gettype($year)); // Conventional way
echo "<br/>";
var_dump(get_debug_type($year)); // New way

When we access the browser, we see the following result:

Return of the integer value via the new function

Note that the gettype() function returned “integer”. In contrast, the new get_debug_type() function returned “int”, an identifier we are more used to.

Another example is in the case of decimal numbers. Let's see how these functions treat this type of data through the code below:

$price = 999.90;
var_dump(gettype($price));
echo "<br/>";
var_dump(get_debug_type($price));

When we access the browser, we see the following result:

Return of the float value via the new function

We see that the gettype() function returned “double”. We can understand this type of data, but we might be more accustomed to the type “float”. If that is the case, we can use the get_debug_type() function.

See below how these functions treat a boolean value:

$is_admin = true;
var_dump(gettype($is_admin));
echo "<br/>";
var_dump(get_debug_type($is_admin));

This is the result we see when we access the browser:

Return of the bool value via the new function

In this example, we see that the get_debug_type() function returns the value “bool”, which is also very common.

So far the examples we have seen have subtly varied the types of data returned. However, when we see how these functions deal with objects, we can notice a big difference. Let's see this difference by creating a class called “Product” and checking the data type of the variable that will contain the new instance of it:

class Product {  }
$notebook = new Product();
var_dump(gettype($notebook));
echo "<br/>";
var_dump(get_debug_type($notebook));

When we access the browser, we see the following result:

Return of the class type via the new function

 Note that the gettype() function returned only “object” as the type of the variable, in a rather generic manner. However, the get_debug_type() function returned the name of the class that the object instantiated, in this case, “Product”. Pretty interesting, don’t you think? This new function really brought some interesting resources to PHP and it may be that we encounter situations during development where we can use these two functions together.

Function get_resource_id()

The function get_resource_id() is another function that comes as a novelty in version 8 of PHP. It comes with the specific goal of helping us identify the ID of a resource defined in our code. For example, imagine that we create a new variable of the resource type by reading a file:

$file = fopen('./users.xml', "r");

This resource has an ID within our page. Previously, to identify this ID, we needed to convert the resource variable to an integer:

var_dump((int)$file);

This code would return the resource ID, which could be any number:

Returned resource ID

Now, if we want to identify this information, we can use this new function:

var_dump(get_resource_id($file));

The result will be the same:

Returned resource ID

Conclusion

In this article, we learned about 8 more new features of PHP 8. We are now looking forward to seeing the amazing applications we can develop with this new version of PHP. If you liked the content of this article, please share it with others. This helps us continue producing content about programming here on our Blog.

Until the next article :)

Keep learning with Hcode

Sign up for the course platform and follow the next blog guides.