If you have been our customer for a while, you know that we always strive to provide fast, secure, and contemporary services. That implies keeping both the hardware and software we use and offer to our customers as up-to-date as possible. One piece of software had been missing from our hosting services for a few months, but we are happy to say that has been remedied. PHP 8.3 is now available for all our hosting services. It was initially released in November of 2023. Since then, we have eagerly awaited CloudLinux to make it available for their operating systems. They recently released it, thus PHP 8.3 is now available for all our customers!
While the name might lead you to believe it is a minor release, some of its changes are not minor at all. Several significant changes could impact the way you write code for the better. Such improvements are never minor or insignificant. Without further ado, here are all the changes, additions, and enhancements that PHP 8.3 brings.
Typed Class Constants
Ever since PHP 7.3 the ability to declare class properties has been available to the public. However, it had one major drawback: class constants could never declare a type. That was not an issue with global constants, but it could lead to confusion and even bugs regarding class constants. After years of development, though, PHP 8.3 allows us to assign a type to a class constant. Fitting that this changes comes precisely one major release after the community identified the issue.
Assigning a type, or typing – not to be confused with writing on a keyboard, should make it easier for PHP developers to find consistency when working with class constants. Typing will apply to all class constants, including interface, trait, and enum. What this will do for class constants is ensure that child classes that override such class constants or assign new values to them also don’t change the type of the constant on a whim. When a class constant is declared with a type, PHP will now enforce the type on the declaration itself and all consequent subclasses. Previously, changing the type of constant would make it incompatible with the declaration, leading to a fatal error.
Here is a very basic example that will show the functionality we have explained more clearly. We are using an interface constant.
// Legal: interface FastCometTest { // Both the declared type and value are strings const string VERSION = "PHP 8.3"; }
And an example where the code will not work.
// Illegal: interface FastCometTest { // The type and value are mismatched in this declaration const float VERSION = "PHP 8.3"; }
Keep in mind that the actual value of the typed class constant is revealed only when working with classes derived from the base declaration. That is why we mentioned this update will help with child classes occasionally changing the type of the constant. Here is an example that demonstrates what we described.
class FastCometTest { const string VERSION = "PHP 8.2"; } class MyConstTest extends FastCometTest { // Legal: //It’s fine to alter the value of VERSION here const string VERSION = "PHP 8.3"; // Illegal: // Since the type was specified in the base class, it must also be declared const VERSION = "PHP 8.3"; // Illegal: // The type that was declared in the base class can’t be altered despite the new type and its // value being compatible const float VERSION = 8.3; }
As you can see from the explanations within the code itself, subclasses must now follow specific rules. Finally, when working with multiple class types, it is possible to narrow the class type when working with multiple ones. Such a variation is safe as long as it is compatible with the main type. Here is an example.
class FastCometTest{ const string|float VERSION = "PHP 8.2"; } class MyConstTest extends FastCometTest{ // Legal: // Narrowing the type declaration to string or float is fine here const string VERSION = "PHP 8.3"; const float VERSION = 8.3; // Legal: // Value is compatible with float despite being an int const float VERSION = 8; // Illegal: // In the example below, the type options can’t be widened to include int const string|float|int VERSION = 8; }
As you can see from the example, as long as at least one of the types aligns with the main class constraint type, the code will work fine.
New Function: json_validate()
When working with any code, it is vital to make sure it is syntactically sound before trying to execute it, integrate it with other scripts, pass it as an argument to a function, or do anything else in general. That is why having the correct tools to check the syntax for you is essential, especially if you are learning to write code or are unfamiliar with what you are putting together.
Fortunately, a new function in PHP 8.3 allows you to validate a JSON payload without using a well-known workaround. Previously, developers used the json_decode() function to check for errors. The function turned the JSON data into associative arrays and objects. That process itself could be taxing on a system’s memory. It was a suboptimal solution.
The new json_validate() function in PHP 8.3 is a much more elegant way to check your JSON code for errors. It uses less memory than json_decode(), and since it is a dedicated function, it also does not require any roundabout coding. Of course, that is not to say that the json_decode() function is now useless. You can still use it to check the validity of the code if you intend to use the arrays and objects it creates. If you are just checking, though, using json_validate() is far more efficient. Below is a quick example of the new function.
if (json_validate($checkJSON)) { // Perform intended task with $checkJSON }
Finally, the new function is capable of accepting $flags, but for now, there is only one that will work with it: JSON_INVALID_UTF8_IGNORE. The developers of PHP may add more in future versions. You can add the flag to the function like any other.
if (json_validate($checkJSON , flags: JSON_INVALID_UTF8_IGNORE)) { // Perform intended task with $checkJSON }
The json_validate() function is terrific if you only want to check your JSON payload instead of using the more memory-intensive json_decode().
New Methods
Next up in the list of additions that come with PHP 8.3 are three new methods: getBytesFromString(), getFloat(), and nextFloat(). The Randomizer class can use these methods to generate specific random outputs. getBytesFromString() will create a random alphanumeric string out of pre-approved characters. Developers, on the other hand, can use getFloat() and nextFloat() to generate random float values. Let’s start with some random strings!
getBytesFromString()
While this new method is straightforward, the functionality is undeniably useful. Pass it a string of characters as the source material, specify how many you want the code to use, and it will spit out a random arrangement of those characters. The method selects bytes at random until it has reached the quota. Here is a quick example.
$rando = new RandomRandomizer(); $alpha = 'ABCDEFGHJKMNPQRSTVWXYZ'; $rando->getBytesFromString($alpha, 9); // "MGQFHWXYJ" $rando->getBytesFromString($alpha, 11); // "PLKVNRSEUIO" $rando->getBytesFromString($alpha, 4); // "DAZB"
As you can see, we invoke the Randomizer class, provide it with the string of characters we want it to use, and then execute. We request six characters each time, and we get six random ones. Here is a different example with numbers.
$rando = new RandomRandomizer(); $nums = '1234567890'; $rando->getBytesFromString($nums, 9); // "725193804" $rando->getBytesFromString($nums, 11); // "62815730943" $rando->getBytesFromString($nums, 4); // "5281"
As you can see from this example, we don’t have to stay within the number of characters when deciding how many to request from the method. The string has only six, but we requested ten, and it provided them. Finally, you can use letters and numbers and weigh the outcome using a weighted string. The example below shows the method will select the more common symbols more often.
$rando = new RandomRandomizer();
$weighted = 'AAA1234567BBC';
$rando->getBytesFromString($weighted, 6); // "37AAB1"
$rando->getBytesFromString($weighted, 12); // "47A1CAB5AB76"
If you ever needed random strings of characters generated, the new getBytesFromString() method is precisely what you need.
getFloat() and nextFloat()
Further expanding on the Randomizer class, the getFloat() and nextFloat() can create random float values out of a given range. We will focus on the former more because the latter has a singular purpose, which we will explain at the end of this section. They both work similarly, though.
The getFloat() method takes a minimum and a maximum value and then returns a random float value from those two. Here is an example below that will illustrate that perfectly.
$rando = new RandomRandomizer();
// This will generate a float value between a minimum
// value of 0 and a maximum value of 9
$rando->getFloat(0,9); // 5.3945744610617
We gave the method a range between 0 and 9, and it generated a random value for us. Simple, straightforward. Using one of these four parameters, you can further control what the model produces as a value.
- IntervalBoundary::ClosedOpen – The minimum value may be returned, but not the maximum;
- IntervalBoundary::ClosedClosed – Both the minimum and maximum values may be returned;
- IntervalBoundary::OpenClosed – The minimum value may not be returned, but the maximum value may be;
- IntervalBoundary::OpenOpen – Neither the minimum nor the maximum values may be returned.
As you can see, each parameter will change how the method works. If you do not use these parameters, the default is IntervalBoundary::ClosedOpen. The method will generate a value that can include the minimum value but not the maximum. The PHP documentation has an excellent example that we will show you here as well.
<?php
$randomizer = new RandomRandomizer();
// For the latitude, the value may be both -90 and 90.
// For the longitude, the value may be 180, but not -180 because
// -180 and 180 refer to the same longitude.
printf(
"Lat: %+.6f Lng: %+.6f",
$randomizer->getFloat(-90, 90, RandomIntervalBoundary::ClosedClosed),
$randomizer->getFloat(-180, 180, RandomIntervalBoundary::OpenClosed),
);
?>
As you can see from the comments in the code itself, the method can produce a latitude value that can be either the minimum or maximum value. The longitude can, on the other hand, not produce the minimum value.
Finally, the nextFloat() method is very similar to getFloat(). Still, it can only produce a random float between 0 and less than 1. It has a more niche use, but it is straightforward to implement.
$rando = new RandomRandomizer();
$rando->nextFloat(); // 0.7984651324934
Dynamic Fetching for Class Constants and Enum Members
If you have been programming with PHP for a while you would be familiar with how convoluted fetching class constants and Enum members with variable names can be. You might have had to use something like the constant() function to achieve that. Perhaps something like this.
class FastComet {
public const THE_CONST = 9;
}
enum FastEnum: int {
case InitialMember = 9;
case SecondaryMember = 10;
}
$constantName = 'THE_CONST';
$memberName = 'InitialMember';
echo constant('FastComet::' . $constantName);
echo constant('FastEnum::' . $memberName)->value;
Doesn’t exactly accomplish the fetching in the most elegant way, does it? Fortunately, PHP 8.3 introduces dynamic fetching for class constants and Enum members, so you no longer have to do that. More specifically, it introduces dynamic fetching constants that look something like this.
$constantName = 'THE_CONST';
$memberName = 'InitialMember';
echo FatComet::{$constantName};
echo FastEnum::{$memberName}->value;
New Attribute: #[Override]
The #[Override] attribute debuted in PHP 8.3, and it can save developers a lot of time troubleshooting and headaches. After adding the attribute to a class method, PHP will ensure that the class method in question overrides or implements a parent or interface method.
When creating or implementing interfaces in PHP, developers can specify the exact functionality of that interface’s methods. However, when creating a separate instance of a class – like a subclass – it is possible to override the parent method using the same name and a compatible signature in the child class. That usually works, but developers must be vigilant to ensure that there are no typos. That the subclass has not accidentally created a brand-new method.
Now, developers can use the #[Override] attribute to specify that the method in question will have some lineage within the code. As we mentioned above, the method must be in some way connected to a parent. That should make things much more easy to read and understand as well. Here is a quick example of how a piece of code with this attribute would look like.
class FastComet {
protected function ovrTest(): void {}
}
// Since ovrTest() can be found in the parent class, this will work
class CloudHosting extends FastComet {
#[Override]
public function ovrTest(): void {}
}
// On the other hand, this will fail because ovrBest()
// (a typo) is not in the parent class
class SharedHosting extends FastComet {
#[Override]
public function ovrBest(): void {}
}
Smaller Additions and Deprecations
Those are not the only changes that come with PHP 8.3, though. We will sum up several more minor additions and improvements here. If you want to know more about the details, please follow the links to their articles.
- zend.max_allowed_stack_size – A new INI setting that allows for setting the maximum stack size;
- ZipArchive::getArchiveFlag() – A class method for ZIP archives;
- str_increment(), str_decrement(), and stream_context_set_options() – Three new string functions;
- socket_atmark() – New socket function;
- posix_sysconf(), posix_pathconf(), posix_fpathconf(), and posix_eaccess() – Four new POSIX functions;
- mb_str_pad() – New multibyte string function;
These are the most important smaller additions. Please refer to their complete documentation for a full breakdown of everything else that PHP 8.3 introduced.
Finally, as with any update, PHP 8.3 introduces some deprecations, which you should know.
- The U_MULTIPLE_DECIMAL_SEPERATORS constant is deprecated in favor of U_MULTIPLE_DECIMAL_SEPARATORS;
- The 3MT_RAND_PHP Mt19937 variant is deprecated;
- ReflectionClass::getStaticProperties() is no longer nullable;
- INI settings assert.active, assert.bail, assert.callback, assert.exception, and assert.warning are deprecated;
- Calling get_class() and get_parent_class() without arguments have been deprecated.
Conclusion
These are all the significant changes the 8.3 update for PHP brings. It is already available on all our servers and hosting plans. If you need help changing the PHP version for your plan, server, or website, we have a fantastic tutorial for that. Alternatively, you can contact us via ticket or live chat, and our 24/7, always-human Technical Support team will be happy to assist you!