Longhorn PHP 2023 - Call for Papers
リリース!
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