LoginSignup
95
54

More than 1 year has passed since last update.

【PHP8.1】PHP8.1がリリースされたので新機能全部やる

Last updated at Posted at 2021-11-30

PHP8.2 / PHP8.1 / PHP8.0

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_encryptopenssl_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関数は、これまで第三引数の比較演算子に非公式な引数!lgなどを受け付けていたのですが、これが禁止されました。
これはドキュメント化されておらず、ユーザノートにも記載はなく、そもそも知ってる人が何人いたのだろうというレベルの謎機能です。

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&quot;b&#039;c

// PHP8.0
a&quot;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(...),

Closure::fromCallable糖衣構文です。

// 同じ
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関数hashhash_filehash_initに第四引数array $options=[]が追加されました。

アルゴリズムに特有のオプションを渡せるようになります。

Added MurmurHash3 with streaming support.

ハッシュアルゴリズムMurmurHash3が追加されました。

$h = hash("murmur3f", 'hoge', options: ["seed" => 42]);
var_dump($h); // "231990405db0441823f7f90ce310315d"

実装されたのはmurmur3amurmur3cmurmur3fの3種類です。
MurmurHash3は引数にシード値を渡せるため、第四引数$optionsが必要となりました。

Added xxHash.

ハッシュアルゴリズムxxHashが追加されました。

$h = hash("xxh128", 'hoge', options: ["secret"=>"secret値は136バイト以上の長さが必要".str_repeat('a',100)]);
var_dump($h); // "d5ace21ffc307b3ae0737e70c0e7525e"

実装されたのはxxh32xxh64xxh3xxh128の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_sunrisedate_sunset非推奨になりました

date_sun_infoが完全上位互換なのでそちらを使いましょう。

The strftime() and gmstrftime() functions have been deprecated

strftimegmstrftime非推奨になりました

これらはプラットフォームによって出力がかわってしまうためです。
影響を受けない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非推奨になりました

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.

mysqli::init非推奨になりました

これは生成メソッドなのに何故かクラスメソッドではなくインスタンスメソッドであり、使い道がわからない代物でした。

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.

関数strptime()非推奨になりました

この関数はプラットフォームやロケールに影響を受けてしまうためです。
影響を受けない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_INFOPDO::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)

関数array_is_list()追加されました

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_xchacha20sodium_crypto_stream_xchacha20_keygensodium_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_resultmysqli_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の改善。

01.png

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はきっと進化し続けることでしょう。

95
54
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
95
54