WHat's new in PHP 8.1

MergePHP December 2021

Hunter Skrasek

Thanks to release managers Joe Watkins, Ben Ramsey, and Patrick Allert

 

Also, 8.1.1RC1 dropped December 3rd, for folks who don't believe in .0 releases

What we'll cover

  • Where to get it now
  • What's new
  • What's deprecated/removed
  • How to find out more information

How do I get it?

enum Status // singleton; Status::Active === Status::Active
{
    case Active;
    case Expired;
    case Cancelled;
    case Pending;

    public function isActive(): bool {} // can be static

    // Look ma, no constants!
}

Enums - Backed

enum Status: string // can be int
{ // can implement JsonSerializeable
    case Active = 'active';
    case Expired = 'expired';
    case Cancelled = 'cancelled';
    case Pending = 'pending';
} // can't be used as array keys...for now


json_serialize(Status::Active); // 'active'
Status::Active->value; // 'active'
Status::from('active'); // Status::Active
Status::tryFrom('activv'); // null; would throw on ::from

Enums - Yes, interfaces work with them

interface HasColor {
    public function getColor(): Color;
}

enum Status implements HasColor
{
    // cases go brr

    public function getColor(): Color {}

    // Can also include traits, but no properties
}
class ValueObject
{
    public function __construct(
        public readonly string $value
    ) {}
}


$foo = new ValueObject('foo');
echo $foo->value; // foo
$foo->value = 'bar'; // throws
$foo = $this->foo(...); // instead of [$this, 'foo'];

$fn = strlen(...);
// instead of Closure::fromCallable('strlen');

New in initializers (allows nested atTributes)

Old:

class Service {
    public function __construct(protected Logger = null) {
        $this->logger ??= new Logger();
    }
}

New:

class Service {
    public function __construct(
        protected Logger = new Logger()
    ) {}
}
function process(
    HasId&HasName $item
): Result&ArrayAccess {
    // do stuff
}

 

You could extend interfaces and then implement the extended interfaces, but this lets you get the same effect without touching the implementation classes at all.

function throwThings(): never
{
    throw new \RuntimeException('things');
} // Different from void return type since it never returns

 

This helps with static analysis, for detecting dead code. The "never" type also applies to functions that die or trigger errors 100% of the time.

class Base
{
    public const NAME = 'Base';
    final public const STATUS_ACTIVE = 'active';
    // lets your constants actually be constant
}


class Extended extends Base
{
    public const NAME = 'Extended'; // works
    public const STATUS_ACTIVE = 'passive'; // fails
}
016 === 16; // false

016 === 14; // true

0o16 === 14; // true

0x16 === 22; // true
$fiber = new Fiber(function (): void {
    $valueAfterResuming = Fiber::suspend('after suspending');
    // … 
});
 
$valueAfterSuspending = $fiber->start();
 
$fiber->resume('after resuming');

 

You'll use these in an event loop, e.g. React/AMPHP. This is not parallel processing

$array1 = ["a" => 1];

$array2 = ["b" => 2];

$array = ["a" => 0, ...$array1, ...$array2];

var_dump($array); // ["a" => 1, "b" => 2]

 

This follows array_merge semantics

Performance Improvements

  • ​JIT for Arm64 (new Macs, AWS Graviton2)
  • Some other JIT improvements
  • Inheritence cache (vs. re-linking classes in each request)
  • Fast class name resolution
  • Misc. performance improvements
    • Timelib + ext/date
    • SPL file system iterator
    • Serialize/deserialize
    • get_declared_classes(), explode(), strtr(), strnatcmp(), dechex()
  • 23% Symfony demo speedup, 3.5% WordPress speedup

...and more!

Deprecation + BC Break Time

Type breaks

Type breaks 2: Resources that are now objects

  • file_info(): finfo
  • IMAP resources -> IMAP\Connection
  • FTP resources -> FTP\Connection
  • GD font identifiers -> GdFont
  • LDAP resources -> LDAP\{Connection, Result, ResultEntry}
  • Postgres resources -> PgSql\{Connection, Result, Lob}
  • Pspell -> Pspell\{Dictionary, Config}

Other database changes

Other functionality changes

  • ' now gets encoded as ' in escaping functions
  • $GLOBALS is now less flexible
    • Can't write to it as a whole
    • Reading from it as a whole is read-only
    • Reading from/writing to array values inside $GLOBALS still works

Further Reading

Thanks! Questions?

What's New in PHP 8.1 - MergePHP December 2021

By Ian Littman

What's New in PHP 8.1 - MergePHP December 2021

  • 671