PHP 8.4.2 Released!

下位互換性のない変更点

関数に渡す引数が少ない場合の挙動

これまでのバージョンでは、ユーザー定義の関数に渡す引数が足りない場合は warning が発生していました。PHP 7.1 以降では、warning ではなく Error 例外が発生するようになります。 この変更はユーザー定義の関数に対してだけのもので、 内部関数には影響を及ぼしません。

<?php
function test($param){}
test();

上の例の出力は、 たとえば以下のようになります。

Fatal error: Uncaught ArgumentCountError: Too few arguments to function test(), 0 passed in %s on line %d and exactly 1 expected in %s:%d

スコープを調べる関数の動的呼び出しの禁止

ある種の関数について、動的な呼び出し ($func()array_map('extract', ...) のような形式) が使えなくなりました。対象になるのは、別のスコープを調べたり変更したり、 あいまいな挙動になってしまったりするような関数です。 この変更の影響を受ける関数は、以下のとおりです。

<?php
(function () {
$func = 'func_num_args';
$func();
})();

上の例の出力は以下となります。

Warning: Cannot call func_num_args() dynamically in %s on line %d

クラス、インターフェイス、トレイトに使えない名前

これらのキーワードが、クラスやインターフェイスやトレイトの名前として使えなくなりました。

数値形式文字列の変換が科学記法に対応

数値形式の文字列の演算や型変換が、科学記法に対応するようになりました。 (int) によるキャストや、 intval() (基数が10の場合)、 settype()decbin()decoct()dechex() といった関数もその対象です。

mt_rand() のアルゴリズムの修正

mt_rand() のデフォルトが、修正版のメルセンヌ・ツイスタ アルゴリズムを使うようになりました。mt_rand() の結果に依存するコードを書いていた場合は、mt_srand() のオプションの第二引数に MT_RAND_PHP を指定すると、これまでの挙動 (間違った実装) を維持できます。

rand()srand() が、 それぞれ mt_rand()mt_srand() のエイリアスとなる

rand()srand() は、それぞれ mt_rand()mt_srand() のエイリアスになりました。つまり、 rand()shuffle()str_shuffle()array_rand() の出力がこれまでのバージョンとは変わるということです。

ASCII 制御文字 delete は識別子として使えない

ASCII 制御文字 delete (0x7F) は、 クォートしない限りは識別子として使えなくなりました。

error_logsyslog を指定した場合の変更

INI 項目 error_log の設定値を syslog にした場合に、PHP のエラーレベルが syslog のエラーレベルにマッピングされるようになりました。 これまでのバージョンではすべてのエラーが notice レベルで記録されていましたが、 この変更によって、今までよりも細やかな区別ができるようになります。

未完成のオブジェクトのデストラクタは呼び出されない

オブジェクトのコンストラクタの実行中に例外がスローされた場合に、 そのオブジェクトのデストラクタが呼ばれることはなくなりました。 以前のバージョンでは、場合によっては (例: そのオブジェクトが例外バックトレースなどで外部から参照される場合) デストラクタが呼ばれることもありました。

参照渡しの引数の call_user_func() での扱い

引数を参照渡しで受け取る関数を call_user_func() から呼んだときに、例外が発生するようになりました。 以前のバージョンでは、完全修飾形式の呼び出しであるか否かによってこの場合の挙動が異なっていました。

さらにこの場合、call_user_func()call_user_func_array() は関数呼び出しを中断しなくなりました。 "expected reference" という警告は出すものの、処理自体はそのまま続行します。

文字列における空のインデックス演算子はサポートしない

文字列に空のインデックス演算子を適用する (例: $str[] = $x) と、fatal エラーが発生します。これまでのバージョンではエラーにならず、 ただ配列に変換されるだけでした。

空文字列に対して、文字列インデックス経由で値を設定する操作

空文字列に対して、一文字単位で変更する操作が、 空でない文字列と同じように機能するようになりました。 つまり、範囲外のオフセットに対する書き込みがスペースで埋められ、 整数型でない値は整数に変換され、最初の文字だけが採用されるというものです。 これより前のバージョンでは、黙って空の配列として扱われていました。

<?php
$a
= '';
$a[10] = 'foo';
var_dump($a);
?>

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

array(1) {
  [10]=>
  string(3) "foo"
}

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

string(11) "          f"

削除された INI 項目

以下の INI 項目は、削除されました。

  • session.entropy_file
  • session.entropy_length
  • session.hash_function
  • session.hash_bits_per_character

参照による代入で自動的に作られる配列の要素の並び順の変更

参照による代入で配列の要素が自動的に作られる場合に、その並び順が変更されました。

<?php
$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

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

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

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

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

同値な要素の並び順

内部的なソートアルゴリズムが改良されたことに伴って、 比較したときに等しいとみなされる要素の並び順が以前とは変わるかもしれません。

注意:

同値な要素の並び順に依存するコードは書かないようにしましょう。 その並び順がいつまでも同じであるとは限りません。

E_RECOVERABLE エラーのエラーメッセージ

E_RECOVERABLE エラーのエラーメッセージが、 "Catchable fatal error" から "Recoverable fatal error" に変更されました。

unserialize() 関数の $options パラメータ

unserialize() 関数の $options パラメータの allowed_classes 要素が、 型を厳密に解釈するようになりました。 つまり、array または bool 以外のあらゆる値が与えられても、 unserialize() は false を返し、 E_WARNING レベルの警告が発生します。

DateTime クラスのコンストラクタに、マイクロ秒も組み込まれる

DateTimeDateTimeImmutable は、現在時刻、明示的な時刻、 または相対時刻を示す文字列 (例: "first day of next month") から構築されると、 マイクロ秒を適切に含めるようになりました。 これは、新しく生成されたふたつのインスタンスが、true ではなくて false を返しやすくなったということです。

<?php
new DateTime() == new DateTime();
?>

致命的なエラーが Error 例外に変換される

Date 拡張モジュールでは、 DateTime または DatePeriod クラス のシリアライズデータが不正だったり、 シリアライズしたデータからタイムゾーンを初期化するのに失敗した場合、 致命的なエラーにならず、 __wakeup()__set_state() メソッドから Error 例外をスローするようになりました。

DBA 拡張モジュールでは、 (dba_insert() のように) データを変更する関数は、キーが正確にふたつの要素を含んでいない場合に キャッチ可能な fatal error ではなく、 Error 例外をスローするようになりました。

DOM 拡張モジュールでは、 不正なスキーマ や RelaxNG検証コンテキスト は 致命的なエラーにならず、 Error 例外をスローするようになりました。 同じように、適切な基底クラスを継承しないノードクラスを登録しようとしたり、 不正なプロパティを読み出そうとしたり、 読み込み専用のプロパティに書き込もうとしたりしても、 同様に Error 例外をスローようになりました。

IMAP 拡張モジュールでは、 16385 バイト以上の email アドレスは、 致命的なエラーにならず、 Error 例外をスローするようになりました。

Intl 拡張モジュールでは、 Collator クラスを継承したクラスで、 親メソッドを呼ぶ前に親のコンストラクタを呼ぶのに失敗すると、 回復可能な fatal error にはならず、 Error 例外をスローするようになりました。 同様に、Transliterator を clone すると、 内部の transliterator の複製に失敗した時に 致命的なエラーにならず、 Error 例外をスローするようになりました。

LDAP 拡張モジュールでは、 ldap_batch_modify() 関数に不明な変更タイプを渡すと、 致命的なエラーにならず、 Error 例外をスローするようになりました。

mbstring 拡張モジュールでは、 mb_ereg() 関数と mb_eregi() 関数が、 'e' オプションを使い、かつ 不正な PHP の式が渡された場合に ParseError 例外をスローするようになりました。

Mcrypt 拡張モジュールでは、 mcrypt_encrypt()mcrypt_decrypt() 関数が mcrypt を初期化できなかった場合に 致命的なエラーにならず、 Error 例外をスローするようになりました。

mysqli 拡張モジュールでは、 不正なプロパティを読み出そうとしたり、 読み取り専用のプロパティに書き込もうとしたりすると、 致命的なエラーにならず、 Error 例外をスローするようになりました。

Reflection 拡張モジュールでは、 リフレクションオブジェクトを取得できなかったり、 オブジェクトのプロパティを取得できなかったりすると、 致命的なエラーにならず、 Error 例外をスローするようになりました。

Session 拡張モジュールでは、 セッションIDに文字列を返さないカスタムのセッションハンドラは、 セッションIDを生成しなければならない関数を呼んだ際に 致命的なエラーにならず、 Error 例外をスローするようになりました。

SimpleXML 拡張モジュールでは、 名前が付いていない、または 重複した属性を作ろうとすると、 致命的なエラーにならず、 Error 例外をスローするようになりました。

SPL 拡張モジュールでは、 SplDirectory オブジェクトを clone しようとすると、 致命的なエラーにならず、 Error 例外をスローするようになりました。 同じように、オブジェクトを繰り返している時に ArrayIterator::append() を呼び出すと、 Error 例外をスローするようになりました。

standard 拡張モジュールでは、 assert()関数 の 最初のパラメーターに string 型の引数が与えられた場合、 かつ PHP のコードが不正だった場合に キャッチ可能な致命的なエラーではなく、 ParseError 例外をスローするようになりました。 同じように、 クラススコープの外側から forward_static_call() を呼び出すと、 Error 例外をスローするようになりました。

Tidy 拡張モジュールでは、 tidyNode を手動で作ろうとすると、 致命的なエラーにならず、 Error 例外をスローするようになりました。

WDDX 拡張モジュールでは、 シリアライズする時に循環参照が存在すると、 致命的なエラーにならず、 Error 例外をスローするようになりました。

XML-RPC 拡張モジュールでは、 シリアライズする時に循環参照が存在すると、 致命的なエラーにならず、 Error 例外をスローするようになりました。

Zip 拡張モジュールでは、 glob サポートが利用できない場合、 ZipArchive::addGlob() メソッドは 致命的なエラーにならず、 Error 例外をスローするようになりました。

字句的に束縛される変数は、名前を再利用できない

use 経由で クロージャ に束縛された変数名には、スーパーグローバル$this またはあらゆるパラメータ と同じ名前が使えなくなりました。 たとえば、次のような関数定義はすべて致命的なエラーが発生します。

<?php
$f
= function () use ($_SERVER) {};
$f = function () use ($this) {};
$f = function ($param) use ($param) {};

long2ip() のパラメータタイプの変更

long2ip() 関数は、 引数に string ではなく int を期待するようになりました。

JSON のエンコードとデコード

serialize_precision ini 設定が、 float 型の値をエンコードするときに、 シリアル化の精度を制御するようになりました。

空のキーをデコードすると、 プロパティ名が _empty_ ではなく、空のプロパティ名になります。

<?php
var_dump
(json_decode(json_encode(['' => 1])));

上の例の出力は、 たとえば以下のようになります。

object(stdClass)#1 (1) {
  [""]=>
  int(1)
}

json_encode() 関数に JSON_UNESCAPED_UNICODE フラグを渡すと、 U+2028 および U+2029 がエスケープされるようになりました。

mb_ereg() および mb_eregi() 関数の引数のセマンティクスの変更

mb_ereg() 関数 と mb_eregi() 関数 の第3引数 (regs) は、 マッチするものがなかった場合、空の配列が設定されるようになりました。 これより前のバージョンでは、このパラメータは変更されませんでした。

sslv2 ストリームのサポートの削除

sslv2 ストリーム が OpenSSL から削除されました。

戻り値の型が決まっている関数で "return;" と書いてもコンパイルエラーになる

戻り値の型を宣言している関数内で、引数がないreturn文を使うと、 (戻り値の型を void と宣言していない場合) E_COMPILE_ERROR が発生するようになりました。 これは、そのreturn文に到達しない場合であっても同じです。

add a note

User Contributed Notes 5 notes

up
46
love at sickpeople dot se
8 years ago
For anyone migrating from 5.x to 7.1:

About "Array ordering when elements are automatically created during by reference assignments has changed" on this page

(http://php.net/manual/en/migration71.incompatible.php#migration71.incompatible.array-order)

The behaviour of 7.1 is THE SAME as of PHP 5. It is only 7.0 that differs.

See https://3v4l.org/frbUc

<?php

$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
up
34
kees at twekaers dot net
7 years ago
The backwards incompatible change 'The empty index operator is not supported for strings anymore' has a lot more implications than just a fatal error on the following code

<?php
$a
= "";
$a[] = "hello world";
var_dump($a);
?>

This will give a fatal error in 7.1 but will work as expected in 7.0 or below and give you: (no notice, no warning)

array(1) {
[0]=>
string(11) "hello world"
}

However, the following is also changed:

<?php
$a
= "";
$a[0] = "hello world";
var_dump($a);
// 7.1: string(1) "h"
// pre-7.1: array(1) { [0]=> string(11) "hello world" }

$a = "";
$a[5] = "hello world";
var_dump($a);
// 7.1: string(6) " h"
// pre-7.1: array(1) { [0]=> string(11) "hello world" }

?>
up
17
m dot r dot sopacua at gmail dot com
7 years ago
"OMFG! Why was session.hash_function removed?!? Dude!"

https://wiki.php.net/rfc/session-id-without-hashing

There. Saved ya a search.
up
2
mikem at gmail dot com
7 years ago
ArgumentCountError - this modification is the main reason to avoid this version on older projects.
up
0
david at artefactual dot com
5 years ago
Regarding the ArgumentCountError, PHP 7.1+ does still support user functions with a variable number of arguments, using the "func(...$args) {}" syntax, see: https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list
To Top