What’s Changed in PHP 8.2
PHP 8.2 will be released on November 24, 2022, and at the top level, there's nothing that's going to blow your socks off, but this is a good thing. PHP is at a point where it's stabilizing, so we shouldn't expect huge changes all the time, especially because it's a minor release.
There are some helpful items in this release, including small improvements to the core of the language, and some cleanup that's going to be a little painful now and maybe more painful later. Again it's a point release, so don't expect it to be a painful upgrade but there are breaking changes.
Warning
This article was written while the 8.2 release was at release candidate 2. Because we are using a pre-release release, things might change between now and the release. It's also still not ready for production so we do not recommend installing this anyone's production environment.
At my day job we've been bitten by letting point releases go for too long in the past, so it's important you do get it installed, but don't rush into the update.
I prefer to set up a branch to test our product using automated tests and then we fix those issues immediately. Then sometime after the 8.2.1 release, we'll start pushing it out to our testing environments and then production shortly after that.
New Features
My favorite part of the new versions is the new features. There's always something that makes me excited to see how the language is evolving.
Readonly Classes
My favorite new feature is the readonly
class support that is being added. PHP 8.1 added readonly
properties and 8.2 adds support to make the whole class read-only. This is useful for immutable classes like Value Objects.
readonly class Age
{
public int $age;
public function __construct(int $age)
{
$this->age = $age;
}
}
It's almost the same as marking all the properties as readonly
but prevents us from accidentally creating dynamic properties.
$age = new Age(42);
// Fatal error: Uncaught Error: Cannot modify readonly property Age::$age
$age->age = 43;
Disjunctive Normal Form Types
Another new feature we get is Disjunctive Normal Form(DNF) types. Now, this is a computer science term that means it allows us to combine union and intersection types, these were introduced in PHP 8.0 and 8.1 respectively. DNFs must be grouped by parentheses. These will be very helpful for helper functions where we need to use them with multiple classes.
For example, you might have to generate a hash. For our example below, we need a class that implements both the hasName
interface and the hasId
interface or is null
. In this case (HasName&HasId)|null
is the disjunctive normal form of our variable constraints.
function generateHash((HasName&HasId)|null $item):string
{
if ($item === null) {
return '';
}
return sha1($post->getName() . $item->getId());
}
Constants in Traits
We can now use constants inside of traits. However, we can't access the constant through the name of the trait. We can access it using self::NAME
or a class that uses the trait.
trait Uuid {
const COLUMN_NAME = 'uuid';
}
class User {
use Uuid;
public function getColumnName(): string
{
return self::COLUMN_NAME;
}
}
$user = new User();
echo $user->getColumnName(), PHP_EOL;
// or
echo User::COLUMN_NAME, PHP_EOL
Redacted Parameters in Backtraces
Another new feature is redacted parameters in backtraces. The backtrace shows us what functions have been called and with what parameters. This can be a pain when passwords, encryption keys, or AWS keys are included and displayed to our end users or sent to third parties.
function testMe(string $secure): void
{
debug_print_backtrace();
}
testMe("AWS-key-don't-let-anyone-know");
- *Output: **
#0 /home/user/scripts/code.php(21): testMe('AWS-key-don't-l...')
We can now mark specific parameters as sensitive using the #[\\SensitiveParameter]
attribute. This is useful for anyone who works with sensitive information and needs to send the data to third parties.
function testMe(#[\\SensitiveParameter] string $secure): void
{
debug_print_backtrace();
}
testMe("AWS-key-don't-let-anyone-know");
Output:
#0 /home/user/scripts/code.php(21): testMe(Object(SensitiveParameterValue))
I use observability solutions and need to scrub the sensitive data for them, so I'm looking forward to this. Ultimately, I do trust those solutions, but why take a risk?
Fetch Properties of Enums in Const Expressions
We're also now able to fetch properties of enums in constant expressions. Again, I love enums and a gap in the implementation of enums in PHP 8.1 prevented us from using an enum value in constant expressions. We can now use the object operator (->
) or the null safe operator (?->
) to access the value.
enum PublishedState:string {
case Draft = "Draft";
case ReadyForReview = "Ready For Review";
case Scheduled = "Scheduled";
case Published = "Published";
const TRANSITIONS = [
self::Draft->value => self::ReadyForReview,
];
}
null, true, and false Stand Alone Types
Null, true and false has been added as standalone types in this version. This helps add these types to return values in our functions.
function testFunction(bool $condition): true|null
{
if ($condition) {
return true;
}
return null;
}
Deprecated Functions/Features
I'm not going to cover all of the deprecated functions and features because it's not super entertaining and instead focus on the ones that seem the most painful.
Deprecate Dynamic Properties
I love this. Before 8.2, we can set properties that don't exist inside of a class. This is called a dynamic property. It's helpful in a lot of ways, except for those of us who can't spell or type very well.
Dynamic properties are going to be deprecated in 8.2. This will cause a deprecation warning to be raised. Eventually, it's going to throw an exception when 9.0 comes out. I welcome this and wish we could throw an exception now as I have shot myself in the foot repeatedly.
class Age
{
public int $age;
public function __construct(int $age)
{
$this->age = $age;
}
}
$age = new Age(42);
// Deprecated: Creation of dynamic property Age::$aeg is deprecated
$age->aeg = 43;
Deprecated utf8_encode and utf8_decode
The RFC argues that these functions have inaccurate names. It sounds like it does more, but it only converts between ISO-8859-1 and UTF-8. Check out the RFC for a full explanation. If you're using these, you should switch to mb_convert_encoding()
.
Deprecate ${}
string interpolation
PHP allows us to embed variables inside of strings so they will be automatically concatenated with the string. This change deprecates using the method ${}
.
$user = "Scott";
// Deprecated: Using ${var} in strings is deprecated, use {$var}
echo “Hello, ${user}!";
I didn't even know this was possible until it was deprecated. We can still use the ${}
method, which everyone seems to be using.
$user = "Scott";
echo “Hello, {$user}!”;
Breaking changes
Again, I'm not going to cover all of them because it's not entertaining and instead focus on the ones that seem the most painful.
DateTime Return Types
There is a return type change for the DateTime::createFromImmutable()
and DateTimeImmutable::createFromMutable()
functions. Before 8.2 these returned the name of the class (DateTime
or DateTimeImmutable
respectively), but now they return static
. This improves code completion for classes extending the DateTime
classes, but it's a potentially breaking change if you're extending these two classes.
// PHP < 8.1
DateTime::createFromImmutable(): DateTime
DateTimeImmutable::createFromMutable(): DateTimeImmutable
// PHP 8.2
DateTime::createFromImmutable(): static
DateTimeImmutable::createFromMutable(): static
Locale-insensitive strtolower() and strtoupper()
strtolower()
and strtoupper()
are now no longer locale-specific. The example from the RFC is that a user selecting Turkish when installing Linux would find that applications calling toupper("i")
would obtain İ. Instead we should be using mb_strtolower() or mb_strtoupper().
Conclusion
We hope you'll enjoy the new features coming in PHP 8.2! What are you most excited about? Let us know in the comments.
The post What’s Changed in PHP 8.2 appeared first on php[architect].