2021/11/26にPHP8.1.0がリリースされました。
大きな新機能については、PHP8.0以降公開されるようになったランディングページで見ることができます。
ここでは、概要ではなくUPGRADINGに載っている変更点を全部見て回ることにします。
Backward Incompatible Changes
下位互換性のない変更点。
PHPコア
Access to the $GLOBALS array is now subject to a number of restrictions
$GLOBALS
の内部処理を変更します。
$a = 1;
$globals = $GLOBALS; // 値をコピー
$globals['a'] = 2;
var_dump($a);
// PHP8.1
int(1)
// PHP8.0
int(2)
$GLOBALS
は値をコピーしただけのはずなのにリファレンスになったりといった特殊な仕様がありました。
このせいで内部構造が複雑になり、パフォーマンスも劣化していました。
PHP8.1では、$GLOBALS
を普通の変数と同じように扱うようにします。
Passing null to a non-nullable argument of a built-in function is deprecated
内部関数へのnullの引き渡しに関するルール変更です。
strlen(null);
// PHP8.1
Deprecated: strlen(): Passing null to parameter #1 ($string) of type string is deprecated
// PHP8.0
エラー出ない
strlenの引数はstring
ですが、これまではnullを渡しても何もエラーが出ませんでした。
PHPは元々型に緩かったという経緯もあり、内部関数への引数には甘めの判定をしていました。
それを徐々に厳しくしていく変更です。
PHP9ではユーザ定義関数と同様、TypeErrorになる予定です。
inherited method will now share static variables with the parent method.
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) PHP8.0までint(1)
var_dump(B::counter()); // int(4) PHP8.0までint(1)
何故かこれまで、静的変数は継承したときに別の変数になっていたのですが、今後は同じになります。
変更後はクラス変数と同じ挙動です。
Most non-final internal methods now require overriding methods to declare a compatible return type
ビルトインクラスの返り値の型の厳格化です。
class MyDateTime extends DateTime{
public function modify(string $modifier):int{
return 1;
}
}
$dt = new MyDateTime();
$dt->modify('modifier');
// PHP8.1
Deprecated: Return type of MyDateTime::modify(string $modifier): int should either be compatible with DateTime::modify(string $modifier): DateTime|false
// PHP8.0
エラー出ない
DateTime::modify()
の返り値はDateTime|false
ですが、extends時に別の型を指定しても動作していました。
これが禁止されます。
ユーザ定義クラスでは最初からFatal Errorですが、ビルトインクラスは互換性のため特別に緩くしてありました。
今後は徐々にユーザ定義クラスと揃えていくということです。
互換性などの問題で今後も異なる返り値を使い続けたい場合は、アトリビュート#[ReturnTypeWillChange]
で黙らせることができます。
Fileinfo
The fileinfo functions now accept and return, respectively, finfo objects instead of resources
finfo_openなどの関数は、これまでリソースを返していたのがfinfoオブジェクトを返すようになりました。
var_dump(finfo_open(FILEINFO_NONE));
// PHP8.1
object(finfo)#1 (0) {}
// PHP8.0
resource(4) of type (file_info)
他のFileinfo関数はこれまでと同じ書き方で透過的に動作します。
is_resourceでチェックしている場合は修正が必要です。
FTP
The FTP functions now accept and return, respectively, FTP\Connection objects instead of resources
ftp_connectなどの関数は、これまでリソースを返していたのがFTP\Connection
オブジェクトを返すようになりました。
他のFTP関数はこれまでと同じ書き方で透過的に動作します。
IMAP
The IMAP functions now accept and return, respectively, IMAP\Connection objects instead of resources
imap_openなどの関数は、これまでリソースを返していたのがIMAP\Connection
オブジェクトを返すようになりました。
他のIMAP関数はこれまでと同じ書き方で透過的に動作します。
LDAP
The LDAP functions now accept and return, respectively, LDAP\Connection objects instead of "ldap link" resources
ldap_connectなどの関数は、これまでリソースを返していたのがLDAP\Connection
オブジェクトを返すようになりました。
他のLDAP関数はこれまでと同じ書き方で透過的に動作します。
The LDAP functions now accept and return, respectively, LDAP\Result objects instead of "ldap result" resources
ldap_listなどの関数は、これまでリソースを返していたのがLDAP\Result
オブジェクトを返すようになりました。
他のLDAP関数はこれまでと同じ書き方で透過的に動作します。
The LDAP functions now accept and return, respectively, LDAP\ResultEntry objects instead of "ldap result entry" resources
ldap_first_entryなどの関数は、これまでリソースを返していたのがLDAP\ResultEntry
オブジェクトを返すようになりました。
他のLDAP関数はこれまでと同じ書き方で透過的に動作します。
MySQLi
mysqli_fetch_fields() and mysqli_fetch_field_direct() will now always return zero for max_length.
mysqli_fetch_fieldsおよびmysqli_fetch_field_directの返り値のうち、max_length
は常に0になります。
そもそも結果セットにおけるフィールドの最大幅
って何だ。
The MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH option no longer has an effect.
定数MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTHは何の意味も持たなくなりました。
The MYSQLI_STORE_RESULT_COPY_DATA option no longer has an effect.
定数MYSQLI_STORE_RESULT_COPY_DATAは何の意味も持たなくなりました。
The default error handling mode has been changed from "silent" to "exceptions".
mysqliのエラーモードのデフォルトがExceptionになりました。
Classes extending mysqli_stmt::execute() will be required to specify the additional parameter now.
mysqli_stmt::executeに実行時引数引き渡しができるようになりました。
// mysqli 事前渡し
$stmt = $mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)');
$stmt->bind_param('ss', $id, $name);
$stmt->execute();
// mysqli 実行時渡し
$stmt = $mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)');
$stmt->execute([$id, $name]);
PDOStatement::execute()と同じ使い方ができるようになります。
mysqli::connect() will now return true instead of null on success.
mysqli::connect()は成功時にtrueを返すようになりました。
これまでは何故かnullでした。
MySQLnd
The mysqlnd.fetch_data_copy ini setting has been removed.
ini設定mysqlnd.fetch_data_copyが削除されました。
ただしユーザから見える挙動に変化はありません。
OpenSSL
EC private keys will now be exported in PKCS#8 format
ECの秘密鍵が、他の鍵と同じくPKCS#8形式でエクスポートされるようになりました。
openssl_pkcs7_encrypt() and openssl_cms_encrypt() will now default to using AES-128-CBC
openssl_pkcs7_encryptとopenssl_cms_encryptの暗号化アルゴリズムのデフォルト値がAES-128-CBCになりました。
これまではRC2-40でしたが、これは脆弱なのでOpenSSL3.0ではデフォルトでは無効化されています。
PDO
PDO::ATTR_STRINGIFY_FETCHES now also stringifies values of type bool to "0" or "1".
PDOの設定PDO::ATTR_STRINGIFY_FETCHESは、bool値を"0"か"1"にするようになりました。
これまではbool値は変換しませんでした。
Calling bindColumn() with PDO::PARAM_LOB will now consistently bind a stream result
PDOStatement::bindColumn()の引数に型PDO::PARAM_LOBを渡すと、データが必ずストリームに入ってくるようになりました。
これまではデータベースドライバ等によってストリームだったり文字列だったりすることがありました。
PDO MySQL
Integers and floats in result sets will now be returned using native PHP types when using emulated prepared statements.
プリペアドステートメントを使った場合、返ってきたint型・float型の結果はPHPのint型・float型になりました。
これまではMySQL側の型に関わらず返り値は常に文字列型でした。
PDO SQLite
Integers and floats in results sets will now be returned using native PHP types.
返ってきたint型・float型の結果はPHPのint型・float型になりました。
PgSQL
The PgSQL functions now accept and return, respectively, \PgSql\Connection objects instead of "pgsql link" resources.
pg_connectなどの関数は、これまでリソースを返していたのがPgSql\Connection
オブジェクトを返すようになりました。
The PgSQL functions now accept and return, respectively, \PgSql\Result objects instead of "pgsql result" resources.
pg_queryなどの関数は、これまでリソースを返していたのがPgSql\Result
オブジェクトを返すようになりました。
The PgSQL functions now accept and return, respectively, \PgSql\Lob objects instead of "pgsql large object" resources.
pg_lo_openなどの関数は、これまでリソースを返していたのがPgSql\Lob
オブジェクトを返すようになりました。
Phar
To comply with the ArrayAccess interface, Phar::offsetUnset() and PharData::offsetUnset() no longer return a boolean.
Phar::offsetUnset()およびPharData::offsetUnset()は、これまでtrue/falseを返していたのが値を返さなくなりました。
オーバーライドしているhttps://www.php.net/manual/ja/class.arrayaccess.phpに揃えたものです。
$p = new Phar('./my.phar');
var_dump($p->offsetUnset('a'));
// PHP8.1
NULL
// PHP8.0
true
PSpell
The PSpell functions now accept and return, respectively, PSpell\Dictionary objects instead of "pspell" resources.
pspell_newなどの関数は、これまでリソースを返していたのがPSpell\Dictionary
オブジェクトを返すようになりました。
The PSpell functions now accept and return, respectively, PSpell\Config objects instead of "pspell config" resources.
pspell_new_configなどの関数は、これまでリソースを返していたのがPSpell\Config
オブジェクトを返すようになりました。
Standard
version_compare() no longer accepts undocumented operator abbreviations.
version_compare関数は、これまで第三引数の比較演算子に非公式な引数!
、l
・g
などを受け付けていたのですが、これが禁止されました。
これはドキュメント化されておらず、ユーザノートにも記載はなく、そもそも知ってる人が何人いたのだろうというレベルの謎機能です。
var_dump(version_compare(PHP_VERSION, '8.1.0rc5', 'l'));
// PHP8.1
PHP Fatal error: Uncaught ValueError: version_compare(): Argument #3 ($operator) must be a valid comparison operator
// PHP8.0
true
今後はl
ではなくlt
もしくは<
と記載しなければなりません。
しかし、これが実際に影響する人は存在するのでしょうか。
htmlspecialchars(), htmlentities(), htmlspecialchars_decode(), html_entity_decode() and get_html_translation_table() now use ENT_QUOTES | ENT_SUBSTITUTE rather than ENT_COMPAT by default.
htmlspecialchars()をはじめとした各関数の、変換フラグのデフォルト値がENT_QUOTES | ENT_SUBSTITUTE
になりました。
これまでのデフォルト値はENT_COMPAT
であり、シングルクォートは変換されませんでした。
var_dump(htmlspecialchars('a"b\'c'));
// PHP8.1
a"b'c
// PHP8.0
a"b'c
これまでの初期値がおかしかった案件。
debug_zval_dump() will now print reference wrappers with their refcount, instead of only prepending a "&" to the value.
debug_zval_dump()は、参照値に参照カウントを表示するようになりました。
<?php
$r = 1;
$a = [&$r];
debug_zval_dump($a);
// PHP8.1
array(1) refcount(2){
[0]=>
reference refcount(2) {
int(1)
}
}
// PHP8.0
array(1) refcount(2){
[0]=>
&int(1)
}
細かすぎてわからない変更。
debug_zval_dump() will now print "interned" instead of a dummy refcount of one for interned strings and immutable arrays.
debug_zval_dump()は、参照カウントが不要なところではinterned
を表示するようになりました。
$a = "string";
debug_zval_dump($a);
// PHP8.1
string(6) "string" interned
// PHP8.0
string(6) "string" refcount(1)
これまで表示されていたのが謎です。
SPL
SplFixedArray will now be JSON encoded like an array.
SplFixedArrayのJSONエンコード方式が配列と同じになりました。
var_dump(json_encode([1, 2]));
var_dump(json_encode(SplFixedArray::fromArray([1, 2])));
// PHP8.1
"[1]", "[1]"
// PHP8.0
"[1]", "{"0":1}"
これまで異なっていたのが謎。
New Features
新機能。
Core
It is now possible to specify octal integer by using the explicit "0o"/"0O" prefix
8進数を接頭辞0o
で表現できるようになりました。
var_dump(0o10);
// PHP8.1
int(8)
// PHP8.0
Parse error: syntax error, unexpected identifier "o10"
これまで8進数だけ010
という謎形式だったものを2進数・16進数と合わせたものです。
既存の形式も当面の間は有効であり、非推奨になる予定はありません。
Added support for array unpacking with strings keys
文字列キーの配列をアンパックできるようになります。
var_dump([...['a'=>1], ...['a'=>2]]);
// PHP8.1
['a'=>2]
// PHP8.0
Fatal error: Cannot unpack array with string keys
Added support for enumerations.
列挙型が追加されました。
enum Suit : string{
case Hearts = 'H';
case Diamonds = 'D';
case Clubs = 'C';
case Spades = 'S';
}
var_dump(Suit::Diamonds, Suit::Diamonds->name, Suit::Diamonds->value); // enum(Suit::Diamonds), "Diamonds", "D"
個別にメソッドを実装したりも可能で、様々な遊び甲斐がありそうな機能です。
Added support for never return type
never型が追加されました。
function foo():never{
exit;
}
常にexitしたり常に例外を吐くような、呼び出し元に帰らない型です。
Added support for fibers.
Fiberが追加されました。
PHPのユーザサイドで非同期処理を書けるようになる画期的な機能です。
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('fiber');
echo "レジュームした。$value: ", $value, "\n";
});
$value = $fiber->start();
echo "一時停止した。$value: ", $value, "\n";
$fiber->resume('test');
とはいえPHPでの実装は最低限必要な機能に抑えられているため、実際に使いこなすにはライブラリの登場を待ったほうがいいかもしれません。
It is now possible to use "new ClassName()" expressions as parameter default values
引数デフォルト値でnewできるようになります。
class Test {
public function __construct(
private Logger $logger = new NullLogger,
) {}
}
これまではいったんnullなどで受け取ってから、nullであればnewするといった一手間が必要でした。
また、これはRFCには全く書かれていないのですが、defineにオブジェクトを渡せるようになりました。
define('HOGE', new stdClass());
// PHP8.1
エラー出ない
// PHP8.0
PHP Fatal error: Uncaught TypeError: define(): Argument #2 ($value) cannot be an object, stdClass given
全く関係なさそうな話なのに唐突にここに書かれているのは、処理を共通で使っているから副作用でそうなったとかそんなかんじなのですかね。
Closures for callables can now be created using the syntax myFunc(...)
,
// 同じ
myFunc(...);
Closure::fromCallable('myFunc');
前者と後者は全く同じ意味になります。
...
は省略ではなくこのままの文字です。
File uploads now provide an additional full_path key
ファイルのアップロード時に、$_FILES['full_path']
が追加されました。
webkitdirectoryでディレクトリごとアップロードした際に、ディレクトリを取り出せるようにするものです。
It is now allowed to specify named arguments after an argument unpack
引数アンパックの後ろに名前付き引数を追加することができるようになりました。
foo(...[1], named: "str");
function foo(...$args){
var_dump($args); // [1, "named"=>"str"]
}
これまでは引数アンパックと名前付き引数を組み合わせることはできませんでした。
逆のfoo(named: $arg, ...$args);
はPHP8.1でもエラーになります。
Added support for intersection types.
交差型が追加されました。
function foo(Traversable&Countable $arg){ }
foo(new ArrayIterator()); // エラー出ない
foo(new DirectoryIterator('.')); // Fatal error: Uncaught TypeError: foo(): Argument #1 ($arg) must be of type Traversable&Countable, DirectoryIterator given
型のANDです。
Traversable&Countable
であれば、TraversableかつCountableの型しか受け付けません。
Added support for the final modifier for class constants.
finalクラス定数が追加されました。
class FOO{
final public const HOGE = 1;
}
class BAR extends FOO{
public const HOGE = 2;
}
// Fatal error: BAR::HOGE cannot override final constant FOO::HOGE
final
のついたクラス定数は上書きできなくなります。
Added support for readonly properties.
readonlyアクセス修飾子が追加されました。
class Test {
public readonly string $name;
public function setName(string $name) {
$this->name = $name;
}
}
$t = new Test();
$t->setName('a'); // OK
$t->setName('b'); // Fatal error: Uncaught Error: Cannot modify readonly property Test::$name
$t = new Test();
$t->name = 'a'; // Fatal error: Uncaught Error: Cannot initialize readonly property Test::$name from global scope
内部からは一回だけ書き込み可能ですが、一度書き込んだら上書きはできません。
外部からは一切書き込み不可能です。
極めてよくある『読まれてもいいけど書き込ませたくない』という要望へのソリューションです。
Curl
Added CURLOPT_DOH_URL option.
定数CURLOPT_DOH_URLが追加されました。
libcurlのラッパーです。
DNS over HTTPSに対応したDNSサーバのURLを指定します。
これで何がうれしいかというと、DNSの中間者攻撃を防ぐことができます。
Added certificate blob options when for libcurl >= 7.71.0
定数CURLOPT_ISSUERCERT_BLOB・CURLOPT_PROXY_ISSUERCERT・CURLOPT_PROXY_ISSUERCERT_BLOB・CURLOPT_PROXY_SSLCERT_BLOB・CURLOPT_PROXY_SSLKEY_BLOB・CURLOPT_SSLCERT_BLOB・CURLOPT_SSLKEY_BLOBが追加されました。
これらもlibcurlに追加された定数のラッパーです。
Added CURLStringFile, which can be used to post a file from a string rather than a file
ファイルのアップロード用にCURLStringFileクラスが追加されました。
既存のCURLFileはファイルの実体を指定する必要があって面倒だったのですが、CURLStringFileは文字列を直接ファイルとしてアップロードできます。
$file = new CURLStringFile($data, 'filename.txt', 'text/plain');
curl_setopt($curl, CURLOPT_POSTFIELDS, ['file' => $file]);
中身が$data
のファイルが、filename.txt
という名前でアップロードされます。
FPM
Added openmetrics status format.
openmetricsフォーマットが追加されました。
PrometheusがFPMの情報を取得するのに使えるらしいですが、なんのことだかよくわからない。
Added new pool option for the dynamic process manager called pm.max_spawn_rate.
プールオプションpm.max_spawn_rateが追加されました。
Apacheのpreforkみたいな話ですかね?
そもそもFPMってなんなんだ。
GD
Avif support is now available through the imagecreatefromavif() and imageavif() functions
関数imagecreatefromavif()およびimageavif()が追加されました。
Avifフォーマットが使えるようになります。
WebPより低容量高画質だそうです。
正直いまだにpng使ってる。
hash
The following functions have changed signatures, to support an optional $options
argument
3関数hash、hash_file、hash_initに第四引数array $options=[]
が追加されました。
アルゴリズムに特有のオプションを渡せるようになります。
Added MurmurHash3 with streaming support.
ハッシュアルゴリズムMurmurHash3が追加されました。
$h = hash("murmur3f", 'hoge', options: ["seed" => 42]);
var_dump($h); // "231990405db0441823f7f90ce310315d"
実装されたのはmurmur3a
・murmur3c
・murmur3f
の3種類です。
MurmurHash3は引数にシード値を渡せるため、第四引数$options
が必要となりました。
Added xxHash.
ハッシュアルゴリズムxxHashが追加されました。
$h = hash("xxh128", 'hoge', options: ["secret"=>"secret値は136バイト以上の長さが必要".str_repeat('a',100)]);
var_dump($h); // "d5ace21ffc307b3ae0737e70c0e7525e"
実装されたのはxxh32
・xxh64
・xxh3
・xxh128
の4種類です。
引数にシード値もしくはシークレット文字列を渡すことができます。
MySQLi
mysqli.local_infile_directory ini setting has been added
ini設定mysqli.local_infile_directoryが追加されました。
マニュアルにはLOCAL DATA
って書いてあるのですがそんなSQLは無いので、おそらくLOAD DATA LOCALのことだと思います。
LOAD DATA LOCAL
で読み込み可能なディレクトリを制限します。
Binding in execute has been added to mysqli prepared statements.
mysqli_stmt::executeが実行時バインドできるようになりました。
// 何故か今までできなかった
$stmt = $mysqli->prepare('INSERT INTO users(id, name) VALUES(?,?)');
$stmt->execute([$id, $name]);
// PDOは今までもできた
$stmt = $pdo->prepare('INSERT INTO users(id, name) VALUES(?,?)');
$stmt->execute([$id, $name]);
PDOと動作を合わせたものとなります。
A new method has been added to mysqli_result called mysqli_fetch_column().
メソッドmysqli_fetch_columnが追加されました。
PDOStatement::fetchColumnに相当するものです。
正直使いどころがわからない。
PDO MySQL
The PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORY attribute has been added
定数PDO::MYSQL_ATTR_LOCAL_INFILE_DIRECTORYが追加されました。
mysqli.local_infile_directory
と同じものです。
PDO SQLite
SQLite's "file:" DSN syntax is now supported
DSN構文file
がサポートされました。
new PDO('sqlite:file:path/to/sqlite.db?mode=ro')
元々はsqlite:path/to/sqlite.db?mode=ro
ってかんじで指定していたはずなので、ファイルを明記できるようになった?
Posix
POSIX_RLIMIT_KQUEUES and POSIX_RLIMIT_NPTS.
POSIX定数POSIX_RLIMIT_KQUEUES、POSIX_RLIMIT_NPTSが追加されました。
FreeBSDでのみ定義されます。
Standard
fputcsv() now accepts a new "eol" argument
fputcsv()に第6引数string $eol = "\n"
が追加されました。
行末の改行を変更できます。
引数が多すぎるのでarray $options
にしてほしい。
SPL
SplFileObject::fputcsv() now accepts a new "eol" argument
SplFileObject::fputcsv()に第5引数string $eol = "\n"
が追加されました。
関数fputcsv()
と全く同じ変更です。
Changes in SAPI modules
CLI
コマンドラインの変更点。
Using -a without the readline extension will now result in an error.
readline拡張機能が有効でないときは、PHPの対話シェル-a
がエラーになるようになりました。
これまでは-a
を無視して通常モードのPHPが起動していました。
Remote functionality from phpdbg has been removed
phpdbgのリモート機能が削除されました。
とあるのですがなんのことだかわかりません。
-a
とかがなくなったってことでいいのかな。
Deprecated Functionality
非推奨になった機能・関数など。
Core
. Implementing the Serializable interface without also implementing __serialize() and __unserialize() has been deprecated.
Serializable
が非推奨になりました。
class HOGE implements Serializable{
public function serialize(){
return serialize($this->data);
}
public function unserialize($data){
$this->data = unserialize($data);
}
}
// PHP8.1
Deprecated: HOGE implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition
// PHP8.0
エラー出ない
PHP7.4でマジックメソッド__serialize/__unserialize
が実装されたため、今後はそちらが推奨されます。
Implicit conversion of floats to integers that result in loss of precision is deprecated.
float
からint
への暗黙の型変換が非推奨になりました。
function toInt(int ...$arg){ }
toInt(1.5);
// PHP8.1
Deprecated: Implicit conversion from float 1.5 to int loses precision
// PHP8.0
エラー出ない
1.5から1へと情報が抜け落ちてしまうためです。
int
からfloat
等への暗黙の型変換は、情報が抜け落ちないため今後もエラーは出ません。
また、明示的な変換については今後も問題なく可能です。
Calling a static method or accessing a static property directly on a trait is deprecated.
traitのstaticプロパティへの直接アクセスが非推奨になりました。
trait T{
public static $foo = 1;
}
var_dump(T::$foo);
// PHP8.1
Deprecated: Accessing static trait property T::$foo is deprecated
// PHP8.0
エラー出ない
Returning a non-array from __sleep will raise a warning
マジックメソッド__sleepが配列以外を返すとE_WARININGが発生するようになりました。
class A{
public function __sleep(){
return 1;
}
}
$a = new A;
serialize($a);
// PHP8.1
Warning: serialize(): A::__sleep() should return an array
// PHP8.0
Warning: serialize(): A::__sleep() should return an array
って書いてあるんだけど、実際はPHP8.0でもエラー出ます。
よくわからない。
Returning by reference from a void function is deprecated.
返り値がvoidのメソッド・関数をリファレンスで書くことが非推奨になりました。
function &ref():void{ }
// PHP8.1
Deprecated: Returning by reference from a void function is deprecated
// PHP8.0
エラー出ない
意味がない文法のため禁止されます。
Automatic conversion of "false" into an empty array on write operands is deprecated.
falseから配列の自動生成が非推奨になりました。
$a = false;
$a[] = 1;
// PHP8.1
Deprecated: Automatic conversion of false to array is deprecated
// PHP8.0
エラー出ない
元々voidやundefinedなど存在しないところからは生成可能、intやstring、true等の通常型からは生成不可能でした。
falseはtrueと揃えるべきだろうということで合わせたものとなります。
Ctype
Passing a non-string value to ctype_*() functions is deprecated.
ctype関数の引数の型において、string型以外は非推奨になりました。
var_dump(ctype_digit(128));
// PHP8.1
Deprecated: ctype_digit(): Argument of type int will be interpreted as string in the future
// PHP8.0
false
元々-128から255までのint型をASCII値として扱うというとんでもない罠仕様があったため、これを防ぐついでに意味のない入力を禁止します。
Date
The date_sunrise() and date_sunset() functions have been deprecated
date_sunriseとdate_sunsetが非推奨になりました。
date_sun_infoが完全上位互換なのでそちらを使いましょう。
The strftime() and gmstrftime() functions have been deprecated
strftimeとgmstrftimeが非推奨になりました。
これらはプラットフォームによって出力がかわってしまうためです。
影響を受けないDateTime::format()などを使いましょう。
Filter
The FILTER_SANITIZE_STRING and FILTER_SANITIZE_STRIPPED filters have been deprecated.
定数FILTER_SANITIZE_STRING・FILTER_SANITIZE_STRIPPEDが非推奨になりました。
一見strip_tagsと同じように見えて異なる動作であり、何に対するサニタイズなのかも明白にされておらずわかりにくいため削除されます。
The filter.default ini setting is deprecated.
ini設定filter.default
が非推奨になりました。
これは$_REQUEST
等の入力値をフィルタリングする機能です。
マジッククォート以上に強力な機能であり、存在そのものが危険であるため封印されます。
GD
The $num_points parameter of image(open|filled)polygon has been deprecated.
imagepolygonなどの引数$num_points
が非推奨になりました。
そもそもPHPで絵なんて描かないからわからぬ。
Hash
The mhash*() functions are deprecated.
mhashをはじめとしたmhash*関数が非推奨になりました。
かわりにhash*関数を使いましょう。
IMAP
The NIL constant has been deprecated.
NILといえばNULLと同じと思われがちですが、PHPではNILの値は0
です。
Intl
Calling IntlCalendar::roll() with bool argument is deprecated.
IntlCalendar::roll()の第二引数$value
の型boolが非推奨になりました。
trueは1、falseは-1と、他の関数ではありえない使われ方をしていました。
Calling mb_check_encoding() without an argument is deprecated.
引数なしのmb_check_encoding()が非推奨になりました。
実はまともに実装されていませんでした。
MySQLi
The mysqli_driver::$driver_version property has been deprecated.
mysqli_driver::$driver_versionプロパティが非推奨になりました。
このプロパティは10年以上更新されておらず実質的に意味がありません。
かわりにPHP_VERSION_IDが推奨されています。
Calling mysqli::get_client_info in OO style or passing $mysqli argument to mysqli_get_client_info() function has been deprecated.
mysqli::get_client_infoの引数が非推奨になりました。
引数なしのmysqli_get_client_info()
はクライアントのバージョンを返します。
The mysqli::init() method has been deprecated.
これは生成メソッドなのに何故かクラスメソッドではなくインスタンスメソッドであり、使い道がわからない代物でした。
OCI8
The INI directive oci8.old_oci_close_semantics has been deprecated.
ini設定oci8.old_oci_close_semanticsが非推奨になりました。
この設定はだいぶ昔に後方互換性だけのために導入されたものなので、そろそろ不要です。
ODBC
odbc_result_all() has been deprecated.
関数odbc_result_all()が非推奨になりました。
取得した結果をいきなりHTMLテーブルに入れて表示する、しかもHTMLエスケープしない、という意味のわからない関数です。
PDO
The PDO::FETCH_SERIALIZE mode has been deprecated.
定数PDO::FETCH_SERIALIZEが非推奨になりました。
これは内部的にSerializableインターフェイスを使っていたため、Serializableと共にこちらも非推奨になります。
しかしそれ以前に、実はそもそも動いていなかったとかなんとかいう話があるっぽいですが。
PgSQL
Not passing the connection argument to PgSQL functions and using the default connection is deprecated.
pg_query()など一部のPgSQL関数を、引数$connection
を渡さずに呼び出すことが非推奨になりました。
コネクションを渡しましょう。
SOAP
The ssl_method option for the SoapClient constructor has been deprecated
SoapClient::__construct()のオプションssl_method
が非推奨になりました。
かわりにcontext
オプションを使いましょう。
Standard
Calling key(), current(), next(), prev(), reset(), or end() on objects is deprecated.
オブジェクトに対する配列ポインタ操作関数の使用が非推奨になりました。
詳しくは配列ポインタ操作関数はIteratorを無視するに書きましたが、かなり不安な挙動であるため禁止されます。
The strptime() function has been deprecated.
この関数はプラットフォームやロケールに影響を受けてしまうためです。
影響を受けないDateTime::createFromFormat()などを使いましょう。
The auto_detect_line_endings ini setting has been deprecated.
ini設定oci8.old_oci_close_semanticsが非推奨になりました。
古いMacと互換するためだけの機能なので、もはや不要です。
The FILE_BINARY and FILE_TEXT constants are deprecated.
定数FILE_BINARYとFILE_TEXTが非推奨になりました。
これらは定義されていただけで、何の効果もありませんでした。
Changed Functions
動作に変更のあった関数。
Core
Properties order used in foreach, var_dump(), serialize(), object comparison etc. was changed.
各関数やループにおいて、オブジェクトのプロパティ出力の順序が規定・文書化されました。
親クラス→子クラスの順番です。
これまでは順序が規定されておらず、実装に依存する状態でした。
Filter
The FILTER_FLAG_ALLOW_OCTAL flag of the FILTER_VALIDATE_INT filter now accept octal string with the leading octal prefix ("0o"/"0O")
フィルタフラグFILTER_FLAG_ALLOW_OCTALが、"0o123"のような値を受け入れるようになりました。
8進数表記として"0o123"ができるようになったので、そのための変更です。
GMP
All GMP function now accept octal string with the leading octal prefix ("0o"/"0O")
全てのGMP関数が、"0o123"のような値を受け入れるようになりました。
8進数表記として"0o123"ができるようになったので、そのための変更です。
gmp_init('0o123');
// PHP8.1
エラー出ない
// PHP8.0
Fatal error: Uncaught TypeError: gmp_init(): Argument #1 ($num) is not an integer string
PDO ODBC
PDO::getAttributes() with PDO::ATTR_SERVER_INFO and PDO::ATTR_SERVER_VERSION now return values instead of throwing PDOException.
PDO::getAttribute()へ引数PDO::ATTR_SERVER_INFO
やPDO::ATTR_SERVER_VERSION
を渡すと、エラーを出すかわりに値を返すようになりました。
ODBCだけなので、PDO_MySQL等はこれまでも問題なく値を取得できていました。
Reflection
ReflectionProperty::setAccessible() and ReflectionMethod::setAccessible() no longer have an effect.
ReflectionProperty::setAccessible()とReflectionMethod::setAccessible()が、何の効果も持たなくなりました。
privateなプロパティにも、リフレクション経由であれば即アクセスできるようになります。
class HOGE{
private static $foo = 'bar';
}
var_dump((new ReflectionProperty(HOGE::class, 'foo'))->getValue());
// PHP8.1
bar
// PHP8.0
Fatal error: Uncaught ReflectionException: Cannot access non-public property
どうせ毎回setAccessible(true)
するんだから最初からデフォルトでいいだろ、という判断です。
Standard
syslog() is now binary safe.
関数syslog()がバイナリセーフになりました。
New Functions
新しい関数。
Core
array_is_list(array $array)
0始まりでキーの抜けがない配列である場合のみtrueになります。
array_is_list([0=>1, 1=>2]); // true
array_is_list([0=>1, 2=>2]); // false
他言語で言うところの配列であるかを区別できます。
pcntl
Added pcntl_rfork for FreeBSD variants
FreeBSD向けに関数pcntl_rfork()が追加されました。
pcntl_fork()と何がちがうのかはよくわかりません。
Reflection
Added ReflectionFunctionAbstract::getClosureUsedVariables
メソッドReflectionFunctionAbstract::getClosureUsedVariables()が追加されました。
無名関数に渡された変数を取り出すことができます。
$foo = 1;
$function = function () use ($foo) { };
$reflector = new ReflectionFunction($function);
var_dump($reflector->getClosureUsedVariables()); // ["foo"=>1]
どんなときに使うんだこれ。
Standard
Added fsync() and fdatasync()
関数fsync()およびfdatasyncが追加されました。
C言語のfsync・fdatasyncのラッパーのようです。
Sodium
Added the XChaCha20 stream cipher interface functions
関数sodium_crypto_stream_xchacha20
・sodium_crypto_stream_xchacha20_keygen
・sodium_crypto_stream_xchacha20_xor
が追加されました。
libsodiumがXChaCha20に対応したので、Sodiumライブラリが追随したようです。
Added the Ristretto255 functions
関数sodium_crypto_core_ristretto255_add()
・sodium_crypto_core_ristretto255_from_hash()
・sodium_crypto_core_ristretto255_is_valid_point()
・sodium_crypto_core_ristretto255_random()
・sodium_crypto_core_ristretto255_scalar_add()
・sodium_crypto_core_ristretto255_scalar_complement()
・sodium_crypto_core_ristretto255_scalar_invert()
・sodium_crypto_core_ristretto255_scalar_mul()
・sodium_crypto_core_ristretto255_scalar_negate()
・sodium_crypto_core_ristretto255_scalar_random()
・sodium_crypto_core_ristretto255_scalar_reduce()
・sodium_crypto_core_ristretto255_scalar_sub()
・sodium_crypto_core_ristretto255_sub()
・sodium_crypto_scalarmult_ristretto255()
・sodium_crypto_scalarmult_ristretto255_base()
が追加されました。
libsodiumがRistrettoに対応したので、Sodiumライブラリが追随したようです。
New Classes and Interfaces
新しいクラス・インターフェイス。
Intl
Added IntlDatePatternGenerator
クラスIntlDatePatternGeneratorが追加されました。
Intlのそれのラッパーです。
$skeleton = 'yyyyMMddHmmss';
(new \IntlDatePatternGenerator('ja_JP'))->getBestPattern($skeleton); // "yyyy/MM/dd H:mm:ss"
(new \IntlDatePatternGenerator('en_US'))->getBestPattern($skeleton); // "MM/dd/yyyy, HH:mm:ss"
(new \IntlDatePatternGenerator('pt_BR'))->getBestPattern($skeleton); // "dd/MM/yyyy HH:mm:ss"
(new \IntlDatePatternGenerator('de_DE'))->getBestPattern($skeleton); // "dd.MM.yyyy, HH:mm:ss"
各国の日時形式に合った感じのフォーマットにしてくれるので国際化対応がやりやすくなります。
ただ渡せるフォーマットがdateのやつじゃなくてICUのフォーマットなのでめんどくさい。
Removed Extensions and SAPIs
削除されたエクステンション・SAPIは無し。
Other Changes to Extensions
その他の変更点。
GD
imagewebp() can do lossless WebP encoding by passing IMG_WEBP_LOSSLESS as quality.
関数imagewebp()は、引数qualityに定数IMG_WEBP_LOSSLESSを渡すとロスレス圧縮できるようになりました。
Mbstring
Unicode data tables have been updated to Unicode 14.
UnicodeテーブルがUnicode 14に更新されました。
MySQLi
The mysqli_stmt::next_result() and mysqli::fetch_all() methods are now available when linking against libmysqlclient.
libmysqlclientを使っている場合でも、
mysqli_stmt::next_resultとmysqli_result::fetch_all
が使えるようになりました。
まあ余程の理由でもないかぎりmysqlndを使いましょう。
OpenSSL
The OpenSSL extension now requires at least OpenSSL version 1.0.2.
OpenSSLエクステンションが要求するOpenSSLライブラリの最低バージョンが1.0.2になりました。
これまでは、PHP7.0以降OpenSSL0.9.8以上、PHP7.1以降OpenSSL1.0.1以上でした。
OpenSSL 3.0 is now supported.
OpenSSL3.0がサポートされました。
デフォルトではレガシーな暗号化形式の多くが無効化されているようです。
Phar
Use SHA256 by default for signature.
pharアーカイブのシグネチャのデフォルトがSHA256になりました。
これまではSHA1でした。
Add support for OpenSSL_SHA256 and OpenSSL_SHA512 signature.
pharアーカイブのシグネチャがOpenSSL_SHA256とOpenSSL_SHA512をサポートしました。
Phar::setSignatureAlgorithmで設定可能です。
SNMP
add SHA256 and SHA512 for security protocol.
SNMPがSHA256とSHA512をサポートしました。
SNMP::setSecurityで設定可能です。
Standard
--with-password-argon2 now uses pkg-config to detect libargon2.
コンパイルオプション-with-password-argon2
は、libargon2
の場所を環境変数PKG_CONFIG_PATH
ではなくpkg-config
を使って探すようになりました。
Windowsには関係ないのでよくわかりません。
--with-external-libcrypt now allows to use system libcrypt/libxcrypt instead in PHP own implementation.
コンパイルオプション--with-external-libcrypt
を指定すると、システムに入っているlibcrypt/libxcryptを使用します。
未指定の場合は、これまでどおりPHPに組み込まれている暗号化処理を使用します。
Windowsには関係ないのでよくわかりません。
New Global Constants
グローバル定数。
MySQLi
MYSQLI_REFRESH_REPLICA has been added as a replacement for MYSQLI_REFRESH_SLAVE
定数MYSQLI_REFRESH_REPLICAが追加されました。
値はMYSQLI_REFRESH_SLAVEと同じです。
そしてMYSQLI_REFRESH_SLAVEは将来のバージョンで削除されます。
ポリがコレでなんちゃらのアレです。
Sockets
The following socket options are now defined
定数SO_ACCEPTFILTER / SO_DONTTRUNC / SO_WANTMORE / SO_MARK / TCP_DEFER_ACCEPTが追加されました。
BSDソケットのラッパーのようです。
Changes to INI File Handling
iniファイルの変更点。
The log_errors_max_len ini setting has been removed.
ini設定log_errors_max_lenが削除されました。
実はPHP8.0以降効果がなかったんだよとか言ってるんだけど、これまでそんな話出てきてたっけ?
A leading dollar in a quoted string can now be escaped.
二重引用符で囲まれた先頭の$
をエスケープできるようになりました。
すなわち"\${"
は"${"
と解釈されます。
とか書いてあるんだけど、これずっと前からそうなってるんですよね。
いったい何を言いたいのかよくわからない。
Backslashes in double quoted strings are now more consistently treated as escape characters.
二重引用符で囲まれた文字列のエスケープの扱い方がより一貫的になりました。
例として、"foo\\"
の後ろに改行以外の文字があったときの動作が変わります。
とか書いてあるんだけど、これも前から同じなんですよね。
例が悪いのか何なのかわからない。
Windows Support
Windowsのサポートに変更はありません。
即ち、これまでどおり使い続けることができます。
Performance Improvements
UPGRADINGには何故か何も書かれていないのですが、ランディングページにパフォーマンスの改善点が記載されています。
・ARM64(AArch64)へのJITバックエンド対応。
・リクエスト毎にクラスを再リンクせず、キャッシュを継続する。
・クラス名の解決の高速化。
・timelib
およびext/date
の高速化。
・SPLイテレータの改良。
・serialize/unserializeの最適化。
・いくつかの内部関数(get_declared_classes()・explode()・strtr()・strnatcmp()・dechex()等)の最適化。
・JITの改善。
JITの無い状態でもSymfonyが23%高速化、WordPressが3.5%高速化されています。
Symfonyが高速化されたということは、Laravelも高速化されるということです。
……いや23%って何だよ。
いくらなんでもおかしくないか???
感想
PHP8.1で目立つのは、型に関する機能の追加、そしてレガシーの排除です。
列挙型に交差型にnever型に新潟アクセス修飾子にその他諸々と、型の表現方法が大幅に拡充されました。
なんか書いたらなんとなく動くというインターネット黎明期から引き継がれてきた大らかさはますます狭まり、きっかりかっちり型を縛ったstrictプログラミングがPHPでもほぼ主流となっています。
まあ、当時のように多少ゆるふわでもなあなあでどうにかなる時代はとうに過ぎ去り、ほんの少しでも穴があったら事業存続に繋がる損失になるレベルまでインターネットの領域が広まってきたので、これは仕方のない方向性であると言えるでしょう。
そしてFiberはいまだ未知数ですが、もしかしたら今後のPHPのパラダイムが転換するほどの機能になるかもしれません。
何も起こらないかもしれません。
そしてどんどん新機能が追加され続けているにもかかわらず、何故か高速化も相変わらず進んでいます。
ふしぎですね。
今回はE_DEPRECATEDの追加が目立ちますが、それ以外でいきなり動かなくなるって事態はほぼ無いはずなので、PHP8.0で動いているコードなら概ねそのままいけると思います。
とはいえ初物に飛びつくのは危ないので、PHP8.1.3くらいになったら移行を検討してみてはいかがでしょうか。
これからのPHPは、Nikitaの離脱という痛手こそあったものの、同時にPHP財団が設立され、大きな節目を迎えました。
この試みがうまくいけば、今後もPHPはきっと進化し続けることでしょう。