PHP 8.1.28 Released!
リリース!
PHP8.1は、PHPのメジャーアップデートです。
Enum、読み取り専用プロパティ、callableの新シンタックス、Fiber、交差型、パフォーマンス向上など数々の新機能があります。

ENUM型 RFC ドキュメント

PHP < 8.1
class Status
{
const
DRAFT = 'draft';
const
PUBLISHED = 'published';
const
ARCHIVED = 'archived';
}
function
acceptStatus(string $status) {...}
PHP 8.1
enum Status
{
case
Draft;
case
Published;
case
Archived;
}
function
acceptStatus(Status $status) {...}

定数のかわりにENUMを使うことで、すっきりと書けるようになります。

読み取り専用プロパティ RFC ドキュメント

PHP < 8.1
class BlogData
{
private
Status $status;

public function
__construct(Status $status)
{
$this->status = $status;
}

public function
getStatus(): Status
{
return
$this->status;
}
}
PHP 8.1
class BlogData
{
public readonly
Status $status;

public function
__construct(Status $status)
{
$this->status = $status;
}
}

読み取り専用プロパティは、一度でも値を割り当てると、その後変更することはできません。
これはValue ObjectやData Transfer Objectを実現するのに最適です。

第一級callable RFC ドキュメント

PHP < 8.1
$foo = [$this, 'foo'];

$fn = Closure::fromCallable('strlen');
PHP 8.1
$foo = $this->foo(...);

$fn = strlen(...);

任意の関数へのリファレンスを取得できるようになりました。第一級callableと呼ばれます。

引数デフォルト値にNew RFC

PHP < 8.1
class Service
{
private
Logger $logger;

public function
__construct(
?
Logger $logger = null,
) {
$this->logger = $logger ?? new NullLogger();
}
}
PHP 8.1
class Service
{
private
Logger $logger;

public function
__construct(
Logger $logger = new NullLogger(),
) {
$this->logger = $logger;
}
}

引数デフォルト値、およびstatic変数、グローバル定数、アトリビュート引数にnewを書けるようになりました。

特にアトリビュートの入れ子において威力を発揮します。

PHP < 8.1
class User
{
/**
* @Assert\All({
* @Assert\NotNull,
* @Assert\Length(min=5)
* })
*/
public string $name = '';
}
PHP 8.1
class User
{
#[
\Assert\All(
new
\Assert\NotNull,
new
\Assert\Length(min: 5))
]
public
string $name = '';
}

交差型 RFC ドキュメント

PHP < 8.1
function count_and_iterate(Iterator $value) {
if (!(
$value instanceof Countable)) {
throw new
TypeError('value must be Countable');
}

foreach (
$value as $val) {
echo
$val;
}

count($value);
}
PHP 8.1
function count_and_iterate(Iterator&Countable $value) {
foreach (
$value as $val) {
echo
$val;
}

count($value);
}

交差型は、複数の型を全て満たすことを示す型です。

A&B|Cのように、交差型とUNION型を混在させることは今のところできません。

Never型 RFC ドキュメント

PHP < 8.1
function redirect(string $uri) {
header('Location: ' . $uri);
exit();
}

function
redirectToLoginPage() {
redirect('/login');
echo
'Hello'; // <- dead code
}
PHP 8.1
function redirect(string $uri): never {
header('Location: ' . $uri);
exit();
}

function
redirectToLoginPage(): never {
redirect('/login');
echo
'Hello'; // <- dead code detected by static analysis
}

値を返さないことを示すnever型が追加されました。die()exit()trigger_error()等、関数内でスクリプトが中断される場合に使います。

Finalクラス定数 RFC ドキュメント

PHP < 8.1
class Foo
{
public const
XX = "foo";
}

class
Bar extends Foo
{
public const
XX = "bar"; // No error
}
PHP 8.1
class Foo
{
final public const
XX = "foo";
}

class
Bar extends Foo
{
public const
XX = "bar"; // Fatal error
}

Finalクラス定数は、子クラスで上書きされないことが保証されるクラス定数です。

8進数表記 RFC ドキュメント

PHP < 8.1
016 === 16; // false because `016` is octal for `14` and it's confusing
016 === 14; // true
PHP 8.1
0o16 === 16; // false — not confusing with explicit notation
0o16 === 14; // true

8進数を0oのプレフィックスで書くことができるようになりました。

Fiber RFC ドキュメント

PHP < 8.1
$httpClient->request('https://example.com/')
->
then(function (Response $response) {
return
$response->getBody()->buffer();
})
->
then(function (string $responseBody) {
print
json_decode($responseBody)['code'];
});
PHP 8.1
$response = $httpClient->request('https://example.com/');
print
json_decode($response->getBody()->buffer())['code'];

Fiberは同時実行を実現する軽量な機能です。ジェネレータのような、スタックのどこからでも一時停止や再開が可能なコードを作ることができます。ただしFiber自体は必要最低限の機能しか持っていないため、非同期処理を実現するためにはイベントループ等の実装が必要です。

ユーザがFiberを直接使用することはほとんどなく、ライブラリを経由して利用することが推奨されます。

文字列キー配列のアンパック RFC ドキュメント

PHP < 8.1
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];

$result = array_merge(['a' => 0], $arrayA, $arrayB);

// ['a' => 1, 'b' => 2]
PHP 8.1
$arrayA = ['a' => 1];
$arrayB = ['b' => 2];

$result = ['a' => 0, ...$arrayA, ...$arrayB];

// ['a' => 1, 'b' => 2]

これまでPHPは、スプレッド演算子による配列展開は数値キーしか対応していませんでした。PHP8.1では文字列キーの配列についてもアンパックに対応します。

パフォーマンス向上

Symfonyデモ リクエスト時間
秒間250リクエストを25回連続実行

PHP8.0に対して:

  • Symfonyデモでは23.0%の高速化を達成。
  • WordPressでは3.5%の高速化を達成。

PHP8.1でのパフォーマンス向上技術:

  • ARM64 (AArch64)へのJITバックエンド対応。
  • リクエスト毎にクラスを再リンクせず、キャッシュを継続する。
  • クラス名の解決の高速化。
  • timelibおよびext/dateの高速化。
  • SPLイテレータの改良。
  • serialize/unserializeの最適化。
  • いくつかの内部関数(get_declared_classes()・explode()・strtr()・strnatcmp()・dechex()等)の最適化。
  • JITの改善。

新しいクラス・インターフェイス・関数

  • #[ReturnTypeWillChange]アトリビュート。
  • fsyncfdatasync関数。
  • array_is_list関数。
  • SodiumがXChaCha20暗号化に対応。

互換性のない変更点

  • nullableでない内部関数にnullを渡すことを非推奨化。
  • ビルトインクラスの返り値の型判定が厳格になりました。
  • Serializableインターフェイスを非推奨化。
  • HTMLエンコード関数は、デフォルトでシングルクォートもエスケープするようになりました。
  • $GLOBALSの扱いが他のグローバル変数と同じようになりました。
  • MySQLiのエラーモードのデフォルトが例外になりました。
  • floatからintへ暗黙の型変換を非推奨化。
  • file_infoが返す型はリソースからfinfoオブジェクトになりました。
  • imap関数が返す型はリソースからIMAP\Connectionオブジェクトになりました。
  • FTP関数が返す型はリソースからFTP\Connectionオブジェクトになりました。
  • GDのフォント関数が返す型はリソースからGdFontオブジェクトになりました。
  • LDAP関数が返す型はリソースからLDAP\ConnectionLDAP\ResultLDAP\ResultEntryオブジェクトになりました。
  • PostgreSQL関数が返す型はリソースからPgSql\ConnectionPgSql\ResultPgSql\Lobオブジェクトになりました。
  • Pspell関数が返す型はリソースからPSpell\DictionaryPSpell\Configオブジェクトになりました。
To Top