📘

PHP8.2から8.3で変更となった「staticプロパティと一緒にトレイトを使う場合」の挙動

2024/12/10に公開

概要

PHP8.2から8.3への移行ガイドを見ていたところ以下の記載があったが、ぱっと見理解できなかったため検証してみた。

static プロパティと一緒にトレイトを使うと、親クラスから継承する static プロパティを再宣言するようになりました。つまり、現在のクラスのために別の static プロパティを作成するということです。これは、トレイトを使わずに直接 static プロパティを追加する操作に似ています。

環境

PHP検証用テンプレートリポジトリのDockerfileを8.2と8.3にして検証
https://github.com/TR0205/php8.3-template

検証

クラスでstaticプロパティを使用し継承する場合

各クラスのstaticプロパティへ値を入れても、クラスごとに独立している。

<?php

class A {
    static $test;
}
class B {
    static $test;
}

A::$test = 'A';
B::$test = 'B';

var_dump(A::$test, B::$test);

// string(1) "A"
// string(1) "B"

各クラスが同一のトレイトを使用する場合

各クラスで同一のトレイトを導入しstaticプロパティへ値を代入すると、クラスAのstaticプロパティも"B"となってしまう。

<?php
trait Foo {
    static $test;
}

class A {
    use Foo;
}

class B extends A {
    use Foo;
}

A::$test = 'A';
B::$test = 'B';
var_dump(A::$test, B::$test);

// string(1) "B"
// string(1) "B"

ちなみにクラスCを追加しても同様。最終的に代入した値が反映されてしまう。

trait Foo {
    static $test;
}

class A {
    use Foo;
}

class B extends A {
    use Foo;
}
class C extends B {
    use Foo;
}

A::$test = 'A';
B::$test = 'B';
C::$test = 'C';
var_dump(A::$test, B::$test, C::$test);

PHP8.3にして確認

それぞれ独立した値となっている。

<?php

trait Foo {
    static $test;
}

class A {
    use Foo;
}

class B extends A {
    use Foo;
}
class C extends B {
    use Foo;
}

A::$test = 'A';
B::$test = 'B';
C::$test = 'C';
var_dump(A::$test, B::$test, C::$test);


まとめ

そもそもトレイトのstaticプロパティへ値を追加する機会はあるんだろうか?

参考

https://qiita.com/rana_kualu/items/f03efb9810c3ac5b2ab6

https://github.com/php/php-src/issues/10935

https://qiita.com/suin/items/0897adc7dc653b9c20de

GitHubで編集を提案

Discussion