LoginSignup
6
2

PHP8.3の変更点をチェックしよう

Posted at

この記事について

PHPのバージョン8.3が先日2023年11月23日にリリースされました。このバージョンアップではどのような点が変更されたのか、個人的に気になったところをピックアップして紹介していきます。

変更点ピックアップ

新機能

クラス定数の型付け

クラス定数に型を書けるようになりました。

PHP8.3
class HogeClass {
    const string A = 'hoge';
}

interface HogeInterface {
    const string A = 'hoge';
}

trait HogeTrait {
    const string A = 'hoge';
}

enum HogeEnum {
    const string A = 'hoge';
}

以前は型が書けなかったので、extendsやimplimentsした際に異なる型の値で初期化してしまうことができました。型を明示してそういった事態を防ぐことができるので、ありがたい変更です。

PHP < 8.3
interface I {
    const PHP = 'PHP 8.2';
}

class Foo implements I {
    const PHP = []; // 😨
}

Override アトリビュート

PHP8からアトリビュートが実装されましたが、今回そこに#[\Override]が追加されました。これにより、メソッドがオーバーライドしたものであることを明示することができます。

PHP8.3
class C1 {
    public function hoge(): void {}
}

class C2 extends C1 {
    #[\Override]
    public function hoge(): void {}
}

これにより、親クラスやインターフェースに同じメソッドが定義されていない場合はエラーが発生します。例えば、メソッド名をtypoしてしまったり、元のメソッドが変更された場合に気がつくことができそうです。

class C1 {
    public function hoge(): void {}
}

class C3 extends C1 {
    #[\Override]
    public function hogee(): void {}
}

// Fatal error: C3::hogee() has #[\Override] attribute,
// but no matching parent method exists

クラス定数への動的なアクセス構文

クラス定数に対して動的にアクセスできるようになりました。

PHP8.3
class Sample {
    const HOGE = 'hoge';
}

$value = 'HOGE';
$getValue = fn() => 'HOGE';

var_dump(Sample::{$value}); // hoge
var_dump(Sample::{$getValue()}); // hoge

合わせて列挙型/Enumの値にも動的にアクセスできるようになりました。以前はシンプルにアクセスする方法がなかったので、これは嬉しい変更です。

PHP8.3
enum Suit: string
{
    case Hearts = 'H';
    case Diamonds = 'D';
    case Clubs = 'C';
    case Spades = 'S';
}

$param = 'Hearts';
var_dump(Suit::{$param}->value); // H

新しく追加された関数

json_validate

文字列が有効なJSONかどうかを調べるjson_validateが追加されました。検証自体はjson_decodeでもできるのですが、検証だけでデコードされた使わない場合はこちらのほうがパフォーマンスに優れるようです。例えば、単体テストで検証をたくさん実行するケースに使えそうですね。

PHP8.3
var_dump(json_validate('{ "test": { "foo": "bar" } }')); // true
var_dump(json_validate('{ "": "": "" } }')); // false

mb_str_pad

文字列に対して特定の文字列で埋めて固定長にするstr_padのマルチバイト版としてmb_str_padが追加されました。

PHP8.3
var_dump(mb_str_pad('▶▶', 6, '❤❓❇', STR_PAD_RIGHT)); // string(18) "▶▶❤❓❇❤"
var_dump(mb_str_pad('▶▶', 6, '❤❓❇', STR_PAD_LEFT));  // string(18) "❤❓❇❤▶▶"
var_dump(mb_str_pad('▶▶', 6, '❤❓❇', STR_PAD_BOTH));  // string(18) "❤❓▶▶❤❓"

var_dump(mb_str_pad("🎉", 3, "祝", STR_PAD_LEFT));   // string(10) "祝祝🎉"

Random\Randomizer::getBytesFromString

PHP8.2から乱数生成のためのrandom拡張モジュールが追加されましたが、今回はそこに、指定した文字列からランダムな文字列を生成するgetBytesFromStringが追加されました。

PHP8.3
$randomizer = new \Random\Randomizer();

echo $randomizer->getBytesFromString(
    'abcdefghijklmnopqrstuvwxyz0123456789',
    10,
);
// z0cshw5me7

これだけで暗号的にも安全なランダム文字列が生成できるのは便利ですね。

下位互換性のない変更点

空の配列に負のインデックスを割り当てた場合の挙動

空の配列に負のインデックスを割り当てた場合に次のインデックスは必ずそこから+1されていく、とのことです。具体的には次のようになります。

PHP8.3
$arr = [];
$arr[-10] = 'a';
$arr[] = 'b';
$arr[] = 'c';
var_dump($arr);
// [
//    -10 => "a",
//    -9 => "b",
//    -8 => "c"
// ]

ちなみに以前はどうだったかというと、負のインデックスを割り当てても次は0になり、そこから+1されていきます。

range関数に対するさまざまな変更

ある範囲の要素を含む配列を作成するrange関数ですが、変更を一言で表すと「より自然な挙動をするようになった」という感じでしょうか。

大まかに2つに分けると、1つは、より自然な配列が生成されるようになった点があります。

より自然な配列を生成
// PHP < 8.3
range('9', 'A'); // [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

// PHP 8.3
range('9', 'A'); // ["9", ":", ";", "<", "=", ">", "?", "@", "A"]

もう1つは、一般的でない引数が指定された時にエラーが発生するようになりました。

一般的でない引数に対してエラーが発生する
// PHP 8.3
range(1, []); // TypeError
range(1, 10, 0); // ValueError
range(1, 10, -1); // ValueError

推奨されなくなる機能

mb_strimwidth関数に負のwidthを渡すこと

文字列を指定した幅に丸めるmb_strimwidthですが、その幅を指定する引数widthには負の値を指定することができます。今回の変更により、負の値を指定するとDeprecatedエラーが発生するようになりました。

PHP8.3
echo mb_strimwidth('abcde', 0, -1);
// Deprecated: mb_strimwidth(): passing a negative integer to argument #3 ($width) is deprecated
// abcd

「指定した幅に丸める」というのが目的なので、負の値を指定するのは目的に合わないですね。

まとめ

先日(2023年11月23日)リリースされたPHPのバージョン8.3について、いくつか変更点をピックアップしてみました。型システムの強化や不自然な挙動の調整が実施され、引き続き安全性が高まっている印象です。他にも変更点はいろいろあるので、移行ガイドから一読してみてはいかがでしょうか。

さて、新しいバージョンがリリースされたということはつまり、古いバージョンのサポート終了が迫っているということです。1 8.0は終わりを迎え、8.1はあと1年、8.2はあと2年を切りました。慌てることのないよう、余裕を持って新しいバージョンへ移行しましょう(戒め)。

謝辞

今回PHP8.3を試すためにDockerイメージを待っていたのですが、プルリクエストでこのような発言がありました。

あるいは、少し我慢して待つという手もある。~中略~ 例えば、家族や友人と過ごしたり、自由な時間を楽しんだりするために、メンテナはコンピュータから離れる時間を作ることができます。(機械翻訳)2

メンテナーに感謝と敬意を払う姿勢は忘れたくないものです。PHPとDockerイメージのメンテナーの皆様ありがとうございます。

  1. https://www.php.net/supported-versions.php

  2. https://github.com/docker-library/php/pull/1464#issuecomment-1827278056

6
2
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
6
2