下位互換性のない変更点

PHP コア

$GLOBALS へのアクセス制限

$GLOBALS 配列へのアクセスに対し、 多くの制限が適用されるようになりました。 $GLOBALS['var'] のような、 個別の配列要素に対する読み取りや書き込みは、 これまで通り動作します。 $GLOBALS 配列全体への読み取り専用のアクセスも、 引き続きサポートされます。 しかし、$GLOBALS 配列全体への書き込みは、 もはやサポートされなくなりました。 たとえば、array_pop($GLOBALS) のようなコードは、エラーが発生します。

継承したメソッド内で static 変数を使う

static 変数を使っているメソッドが継承された (但し、オーバーライドはされていない) 場合、継承されたメソッドは static 変数を親クラスのメソッドと共有するようになりました。

<?php
class A {
    public static function counter() {
        static $counter = 0;
        $counter++;
        return $counter;
    }
}
class B extends A {}
var_dump(A::counter()); // int(1)
var_dump(A::counter()); // int(2)
var_dump(B::counter()); // int(3), 以前のバージョンでは int(1)
var_dump(B::counter()); // int(4), 以前のバージョンでは int(2)
?>
これは、メソッド中の static 変数が、 static プロパティと同じ振る舞いをするようになったということです。

必須の引数の前に、デフォルト値を持つ引数を指定した場合

必須の引数の前に、 デフォルト値を持つ引数 を指定した場合、 デフォルト値を持つ引数は常に必須の引数として扱われるようになりました。 これは、 名前付き引数 を使って関数を呼び出した場合でも同様です。 PHP 8.0.0 以降、かつ 8.1.0 より前のバージョンでは、 以下のコードは推奨されない警告を発生させていましたが、 呼び出しは成功していました。 PHP 8.1.0 以降では、 ArgumentCountError がスローされるようになっています。 位置を指定して呼び出した場合でも、同じエラーがスローされます。

<?php
function makeyogurt($container = "bowl", $flavour)
{
    return "Making a $container of $flavour yogurt.\n";
}
try
{
    echo makeyogurt(flavour: "raspberry");
}
catch (Error $e)
{
    echo get_class($e), ' - ', $e->getMessage(), "\n";
}
?>

上の例の PHP 8.0 での出力は、このようになります。:

Deprecated: Required parameter container
 in example.php on line 3
Making a bowl of raspberry yogurt.

上の例の PHP 8.1 での出力は、このようになります。:

Deprecated: Optional parameter $container declared before required parameter
 $flavour is implicitly treated as a required parameter in example.php on line 3
ArgumentCountError - makeyogurt(): Argument #1 ($container) not passed

但し、必須の引数の前であっても、 Null を許容する型 を指定するために、 引数にデフォルト値 null を指定できることに注意して下さい。 その場合でも、その引数は必須であることには変わりありません。

内部クラスと戻り値の型の互換性

ほとんどの final でない内部メソッドは、 それをオーバライドする際、 互換性がある戻り値の型を宣言することが必須になりました。 そうしない場合、継承が有効かを検証する際に、 推奨されない警告が発生するようになります。 PHP のバージョン間の互換性を保ちたいがために、 戻り値の型を宣言できない場合、 アトリビュート ReturnTypeWillChange を追加することで警告を抑止できます。

新しいキーワード

readonly は予約されたキーワードになりました。しかし、まだ関数名としては使えます。

never が予約語になりました。 よって、クラスやインターフェイス、 トレイトの名前として使えなくなっています。 名前空間の中であっても同様です。

リソースからオブジェクトへの移行

いくつかの リソース が、object に移行しました。 is_resource 関数を使って戻り値をチェックしているコードは、 false を返すことをチェックするコードに置き換えるべきです。

  • FileInfo 関数は、 fileinfo リソース ではなく、 finfo オブジェクトを受け取り、 返すようになりました。

  • FTP 関数は、 ftp リソース ではなく、 FTP\Connection オブジェクトを受け取り、 返すようになりました。

  • IMAP 関数は、 imap リソース ではなく、 IMAP\Connection オブジェクトを受け取り、 返すようになりました。

  • LDAP 関数は、 ldap link リソース ではなく、 LDAP\Connection オブジェクトを受け取り、 返すようになりました。

  • LDAP 関数は、 ldap result リソース ではなく、 LDAP\Result オブジェクトを受け取り、 返すようになりました。

  • LDAP 関数は、 ldap result entry リソース ではなく、 LDAP\ResultEntry オブジェクトを受け取り、 返すようになりました。

  • PgSQL 関数は、 pgsql link リソース ではなく、 PgSql\Connection オブジェクトを受け取り、 返すようになりました。

  • PgSQL 関数は、 pgsql result リソース ではなく、 PgSql\Result オブジェクトを受け取り、 返すようになりました。

  • PgSQL 関数は、 pgsql large object リソース ではなく、 PgSql\Lob オブジェクトを受け取り、 返すようになりました。

  • PSpell 関数は、 pspell リソース ではなく、 PSpell\Dictionary オブジェクトを受け取り、 返すようになりました。

  • PSpell 関数は、 pspell config リソース ではなく、 PSpell\Config オブジェクトを受け取り、 返すようになりました。

MySQLi

mysqli_fetch_fieldsmysqli_fetch_field_direct は、 max_length を指定すると 常に 0 を返すようになりました。 この情報は、結果セットを繰り返し処理する際に計算できますし、 長さの最大値をとります。 PHP でも以前のバージョンから、 内部的にこれと同じ処理が行われてきました。

MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH オプションは、もはや意味をなさなくなりました。

MYSQLI_STORE_RESULT_COPY_DATA オプションは、もはや意味をなさなくなりました。 mysqli::store_resultmode 引数にどんな値を渡しても、 同様に意味がなくなっています。

mysqli::connect は、 成功時に null ではなく、true を返すようになりました。

デフォルトのエラー処理モードが、 "silent" から "exceptions" に変更されました。 この変更の意味の詳細と、 どのようにこの属性を明示的に設定するかについては、 MySQLi のエラー報告モード のページを参照ください。 以前のバージョンの振る舞いは、 mysqli_report(MYSQLI_REPORT_OFF); を使うことで再現できます。

mysqli_stmt::execute を継承したクラスは、 追加でオプションの引数を指定しなければいけません。

MySQLnd

INI ディレクティブ mysqlnd.fetch_data_copy が削除されました。 このディレクティブによって、 ユーザーの目に見える形で、振る舞いが変更されるべきではないからです。

OpenSSL

EC キーの秘密鍵は、他のキーと同じように PKCS#8 フォーマットでエクスポートされるようになりました。

openssl_pkcs7_encryptopenssl_cms_encrypt は、 デフォルト値が RC2-40 から AES-128-CBC に変更されました。 RC2-40 暗号はセキュアではないと見なされており、 OpenSSL 3 からはデフォルトで有効ではなくなっています。

PHP Data Objects(PDO)

PDO::ATTR_STRINGIFY_FETCHES は、bool 型の値を "0""1" に変換するようになりました。 以前のバージョンでは、bool は文字列に変換されていませんでした。

PDOStatement::bindColumnPDO::PARAM_LOB を指定してコールした場合、 かつ、PDO::ATTR_STRINGIFY_FETCHES が有効になっていない場合は、 常にストリームに結果をバインドするようになりました。 以前のバージョンでは、 使っているデータベースドライバやバインドが行われるタイミングによって、 文字列にバインドされることもあれば、 ストリームにバインドされることもありました。

MySQL ドライバ

結果セットの整数と浮動小数点の値は、 エミュレートされたプリペアドステートメントを使った場合、 文字列ではなく、 ネイティブの PHP の型を使って返されるようになりました。 これは、ネイティブのプリペアドステートメントの振る舞いと一致します。 以前のバージョンの振る舞いは、 PDO::ATTR_STRINGIFY_FETCHES オプションを有効にすることで再現できます。

SQLite ドライバ

結果セットの整数と浮動小数点の値は、 ネイティブの PHP の型を使って返されるようになりました。 以前のバージョンの振る舞いは、 PDO::ATTR_STRINGIFY_FETCHES オプションを有効にすることで再現できます。

Phar

ArrayAccess インターフェイスに準拠するため、 Phar::offsetUnset と、 PharData::offsetUnsetbool を返さなくなりました。

標準ライブラリ

version_compare は、 ドキュメントに書かれていない演算子の省略形を受け入れなくなりました。

htmlspecialchars, htmlentities, htmlspecialchars_decode, html_entity_decode, get_html_translation_table のデフォルト値が、 ENT_COMPAT から ENT_QUOTES | ENT_SUBSTITUTE に変更されました。 これは、'&#039; にエスケープされるようになるということです。 以前のバージョンでは、' に対してはエスケープは行われていませんでした。 さらに、不正な UTF-8 文字列は、空文字列を返すのではなく、 Unicode 置換文字に置きかえられるようになっています。

debug_zval_dump は、 値の前に & を付加する代わりに、 自身のリファレンスカウントだけでなく、 リファレンスラッパーのリファレンスカウントも表示するようになりました。 これは、PHP 7.0 以降のリファレンスの表現をより正確にモデル化したものです。

debug_zval_dump は、 インターン化された文字列や、 変更できない配列については、 ダミーのリファレンスカウントではなく、 interned と表示するようになりました。

Standard PHP Library (SPL)

SplFixedArray は、 array のように JSON にエンコードできるようになりました。