PHP8.5がリリースされました。新機能は例によって次のページが読みやすく
PHP: PHP 8.5 Release Announcement
【PHP8.5】PHP8.5の新機能 #rfc – Qiita
次ページが詳しいです。
PHP: PHP 8.4.x から PHP 8.5.x への移行 – Manual
この記事は私視点で便利そうな機能と修正が必要そうな非推奨となった機能を紹介します。
私的に特に便利そうな機能はパイプ演算子、#[\NoDiscard] 属性、array_first / array_last 関数あたりです。Uriクラスもそれなりに扱うことがありそうです。
パイプ演算子は値を左から右へ流しながら処理をつないで書ける構文です。PHPの関数の引数は歴史的経緯により散らかっており、フレームワークやライブラリではしばしばこれをラッピングしてメソッドチェーン的に書けるようにするものがありました。パイプ演算子を用いると素のPHPでこれを整理して書きやすくなります。これは例えば次のように使えます。
<?php
// 配列関数を複数そのまま使うとネストした上に上下に変に移動する読み方をする必要があります。
// ↓の処理順を一見で理解しきるのは難しいです
$arr = [1, 2, 3, 4, 5];
$result = array_values(array_map(
fn($x) => $x + 1,
array_filter(
array_map(
fn($x) => $x * 2,
$arr
), fn($x) => $x > 5
)
));
echo json_encode($result) . "\n";
// [7,9,11]
// パイプ演算子を使うと上から順に書き下すことができ、すっきりします。
// パイプ演算子は左側の値を、右側の一つの callable にそのまま渡します。
// ですので(fn($a) => 処理本体) のようにすると構文エラーを起こさず、自由に読みやすく処理を書けます。
$arr = [1, 2, 3, 4, 5];
$result = $arr |> (fn($a) => array_map(fn($x) => $x * 2, $a))
|> (fn($a) => array_filter($a, fn($x) => $x > 5))
|> (fn($a) => array_map(fn($x) => $x + 1, $a))
|> (fn($a) => array_values($a));;
echo json_encode($result) . "\n";
// [7,9,11]
#[\NoDiscard] 属性は呼び出し元が返り値を使わなかった場合に警告してくれます。よく使うのは恐らく例外の代わりにエラーを返り値として返す関数を書く時でしょう。例えば次です。
<?php
#[\NoDiscard("save_user の返り値を必ず確認してください。")]
function save_user(array $payload): array
{
// 簡易バリデーション
if (!isset($payload['name']) || $payload['name'] === '') {
return [
'ok' => false,
'error' => 'name が空です',
];
}
// ここに永続化処理
return [
'ok' => true,
'error' => null,
];
}
// #[\NoDiscard] を付けた関数の返り値を何もしないで捨てると、
// 「この返り値は本来使われるべきだったのでは?」という警告の対象になります。
save_user(['name' => '']); // 返り値を無視 → 警告される想定のコード
// 正しい使い方。呼び出し側でちゃんと結果を見て分岐します。
$result = save_user(['name' => 'Taro']);
if (!$result['ok']) {
echo "保存に失敗しました: {$result['error']}\n";
} else {
echo "保存に成功しました\n";
}
array_first と array_last はシンプルに名前の通りの動きをします。これまで次のように冗長に書いていた部分を関数で一発で解決できるようになります。
<?php $arr = [ '1st' => 'first', '2nd' => 'second', '3rd' => 'third', ]; // 従来の書き方 $first = $arr[array_key_first($arr)]; $last = $arr[array_key_last($arr)]; var_dump($first, $last); // string(5) "first" string(4) "third" // PHP8.5からできるようになる書き方 $first = array_first($arr); $last = array_last($arr); var_dump($first, $last); // string(5) "first" string(4) "third"
非推奨項目は次ページに一覧があります。
PHP: PHP 8.5.x で推奨されなくなる機能 – Manual
扱っているコードにもよるでしょうが、自分にとって影響がありそうなのは「配列のオフセットに null を指定」「数値でない文字列をインクリメント」あたりです。
PHP 8.5では、配列のキーとして null を渡すことが非推奨となりました。array_key_exists() に null を渡す場合も同様です。これは次のようなコードで起き、またそれを直せます。
<?php
$keyList = [1, null, 0, ""];
$arr = [];
foreach ($keyList as $key) {
// PHP8.5では null が配列のキーになると
// Deprecated: Using null as an array offset is deprecated, use an empty string instead
// という警告が出るようになります
$arr[$key] = "value_" . $key;
}
var_dump($arr);
// 出力結果はPHP8.4以前でも次のようになります。
// array(3) {
// [1]=>
// string(7) "value_1"
// [""]=>
// string(6) "value_"
// [0]=>
// string(7) "value_0"
//}
foreach ($keyList as $key) {
// 次のように $key が null ならば空文字列になる様に明示して解決するのが無難そうです
$arr[$key ?? ''] = "value_" . $key;
}
nullは従来から内部で “” にキャストして配列のキーになっていました。このため空文字列があり得ない配列キーになりうる変数と連想配列で構わない配列がある時はそのまま null を配列のキーにする時がありました。この null は空文字列には暗黙のうちにキャストされ、恐らくこれが不具合を招きやすいとして非推奨になりました。これは ?? を使って null の場合は明示的に空文字列キーにする、と書けばこれまで通りに動き、非推奨警告もなくなります。
PHP8.5では 文字列++ のような数値でない文字列をインクリメントが非推奨となりました。a->b->c->…->z->aaと続くExcelの列名生成などで便利だった書き方です。zの次がaaなのが本当にExcel用って感じでした。これが非推奨になり str_increment 関数を使ってください、とメッセージが出るようになりました。これは次の感じです。
<?php $v = 'z'; $v++; // Deprecated: Increment on non-numeric string is deprecated, use str_increment() instead echo $v . "\n"; // aa $v = str_increment($v); // メッセージにしたがって str_increment() を使う echo $v . "\n"; // ab