SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

ますます便利になるPHPの新機能を探ろう!

より使いやすくなったPHP 8.3の新機能──クラスや変数定義、エラーと例外の強化ポイントを解説

ますます便利になるPHPの新機能を探ろう! 第3回


  • X ポスト
  • このエントリーをはてなブックマークに追加

クラスと変数定義の機能強化

 まずは、クラス定義と変数定義の機能強化について紹介します。

Overrideアトリビュートによるオーバーライドメソッドの明示

 PHP 8.3では、Overrideアトリビュートにより、オーバライドするメソッドを明示できるようになりました。メソッドのオーバライドとは、クラスやインタフェースのメソッドを派生クラス(実装クラス)のメソッドで上書きすることです。このとき、オーバライドするメソッドとオーバライドされるメソッドのシグネチャは、完全に一致する必要があります。JavaやPythonをはじめとする多くの言語のように、誤ったシグネチャによるメソッド定義を防止することができます。

 以下のリストは、クラスとインタフェースのメソッド定義で、Overrideアトリビュートの付与がどのように働くか確認する例です。

リスト override.php
class P {
    protected function cmethod(): void {}	(1)
}

interface I {
    public function imethod(): void;		(2)
}

class CGood extends P implements I {		(3)
    #[\Override]
    public function cmethod(): void {}
    #[\Override]
    public function imethod(): void {}
}

class CBad extends P implements I {		(4)
    #[\Override]
    public function cmesod(): void {}
// エラー:CBad::cmesod() has #[\Override] attribute, but no matching parent method exists
    #[\Override]
    public function imesod(): void {}
// エラー:Class CBad contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (I::imethod) 
}

 クラスPでは引数も戻り値もないメソッドcmethodを(1)、インタフェースIでも同様にメソッドimethodを定義しています(2)。クラスCGoodでは、オーバライドメソッドcmethodとimethodをOverrideアトリビュートを付与して定義しており、これらは問題なくオーバライドされます(3)。

 これに対してクラスCBadでは、継承元にないメソッドcmesodとimesodにOverrideアトリビュートを付与して定義していますが、これは適切でないオーバライドとしてエラーになります(4)。

 インタフェースでは、メソッドは無条件に抽象メソッドとなるので、実装クラスで定義がないとOverrideアトリビュートの有無にかかわらずエラーになります(上記でエラーメッセージの内容が異なるのはそのためです)。ただしOverrideアトリビュートの付与でオーバライドの意図が明確になるので、できるだけ指定した方がよいでしょう。

クラス定数への型の指定

 PHP 8.3では、クラス定数に型を指定できるようになりました。従来は、クラス定数には型が指定できませんでした。そのため、別のコンテキストで定義された定数を参照して新たに定数を定義する場合、その型がよく分からないという問題がありました。

リスト typed_constant.php
enum E1 {
    const NAME = "Non-typed YAMAUCHI Nao";	// こっちは文字列だと分かる
}

class C1 {
    const NAME = E1::NAME;	// E1::NAMEの型は何?
}

 これが、以下のようにハッキリ分かりやすくなります。なお、互換性のない型を指定するとエラーになります。

リスト typed_constant.php
enum E2 {
    const string NAME = "Typed YAMAUCHI Nao";
}

class C2 {
    const string NAME = E2::NAME;
    const int INAME = E2::NAME;		// TypeError
}

readonlyプロパティの再初期化

 PHP 8.3では、readonlyなプロパティをインスタンスのクローン時に1回だけ再初期化できるようになりました。具体的には、クローンのためのマジックメソッド__clone内において、readonlyなプロパティの変更が可能です。__cloneメソッドから呼び出された関数内でも変更できます。

リスト readonly_amend.php
class MyClass {
    // stringとDateTimeを持つクラス
    public function __construct(
        public readonly string $str,
        public readonly DateTime $dt
    ) {}

    // クローンメソッド。dtフィールドはクローンする。strフィールドは無効化
    public function __clone()
    {
        $this->dt = clone $this->dt;		(1)
        $this->unsetStr();
    }

    // strフィールドを無効化する関数。__cloneメソッドから呼び出される場合のみ有効
    private function unsetStr()
    {
        unset($this->str);			(2)
    }
}

$c1 = new MyClass("Hello", new DateTime());
var_dump($c1->dt);	// object(DateTime)#2 (3) { ……
var_dump($c1->str);	// string(5) "Hello"
$c2 = clone $c1;	// クローンだがstrフィールドは無効化されてしまう
var_dump($c2->str);	// 初期化されていないというError

 従来は、readonlyなプロパティは書き換えることができなかったため、オブジェクトのディープコピーを目的としてプロパティをクローンしようとしても、それができないという問題がありました(シャローコピーでは問題ありません)。

 例えば、リストの(1)のようにreadonlyプロパティであるdtをクローンしたくてもエラーとなります。PHP 8.3では、__cloneメソッド内に限定してreadonlyプロパティを変更できるようになったので、(1)のようにプロパティのクローンも、(2)のようにプロパティの値の破棄も可能になりました。

動的なクラス定数の参照

 PHP 8.3では、文字列をキーにしてクラス定数を取得できるようになりました。これは、変数などでは可能であった記法を定数にも拡張したものです。これにより、取得したいクラス定数が実行時にならないと決まらない場合に対応できます。なお、従来はconstant関数を使って同様のことを行っていました(constant関数はPHP 8.3でも引き続き利用可能)。

リスト refer_constant.php
class C {
    const string NAME = 'YAMAUCHI Nao';
}

$constName = 'NAME';

echo constant("C::$constName") . "\n";		// 従来方式
echo C::{$constName} . "\n";			// PHP 8.3

 また、この機能により、PHP 8.1で導入されたENUM型(列挙型)において文字列からの列挙子の値の取得も簡単になります。

リスト refer_constant.php
enum Creature:string {
    case Insects = '昆虫';
    case Birds = '鳥';
    case Fishs = '魚';
    case Animals = '動物';
}

$creatureName = 'Insects';
echo Creature::{$creatureName}?->value;		// 昆虫

静的変数(static変数)の任意の初期化

 PHP 8.3では、静的変数(static変数)の初期化子に変数や関数の戻り値を指定することができるようになりました。静的変数とは、関数内でのみ有効で、かつプログラムの実行中に値を保持し続ける変数です。静的変数の初期化は、従来は定数による初期化のみが可能でした。

リスト init_static.php
function init() {
    return (int)fgets(STDIN);	// 標準入力から開始値(例えば101)を取得して返す
}

function countUp() {
    //static $count = 101;	// 従来は定数による初期化のみが可能
    static $count = init();	// 一度だけ初期化される
    echo "{$count}\n";
    $count++;
}

countUp();	// 例えば101
countUp();	// 例えば102
countUp();	// 例えば103

 関数countUpの静的変数countは、関数の呼び出しで一度だけinit関数の戻り値で初期化されます。以降の呼び出しでは、変数countの値をインクリメントしながら表示します。このような、開始値を外部から与えるような使い方が可能です。

次のページ
エラーや例外に関する機能強化

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
ますます便利になるPHPの新機能を探ろう!連載記事一覧

もっと読む

この記事の著者

WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)

WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書記事多数。 RSS Twitter: @yyamada(公式)、@yyamada/wings(メンバーリスト) Facebook <個人紹介> WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

山田 祥寛(ヤマダ ヨシヒロ)

静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるReact実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/18818 2024/01/15 17:32

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング