More Related Content Similar to 導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について (20) 導入から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について20. trait ってこういうやつ
2012 年リリースのPHP 5.4 で導入
クラスへ追加するメンバーを切り出して定義
プロパティ、メソッド、定数(8.2から)を定義可能
クラスやtrait、Enum からuse
use 先へコピペされたよう振る舞う
直接インスタンスを作れない
複数trait を同時にuse できる
型宣言に使えない
trait T { // トレイトの定義
public string $property = self::class;
public function method(): void {
echo $this->property, PHP_EOL;
}
}
class C {
use T; // トレイトの利用
}
36. 5 つの基準、5 つの規則、5 つの原則
『オブジェクト指向入門』の重点はモジュール性(拡張性と再利用性)
モジュール性についての5 * 3 の15 の確認事項
41. 5 つの基準から見るtrait
分解しやすさ: ○
組み合わせやすさ: ○
分かりやすさ: ☓
traitは利用クラスの中でメンバの名前空間を共有
自身の中にスコープの閉じたメンバを持てない
プロパティは名前衝突時に定義がマージ
自身の定義したプロパティを操作するだけで他部品の不変
条件が壊れる可能性がある
連続性: ○
保護性: △
trait HeightModifiable { // 身長操作trait
private int $value;
public function modifyHeight(int $value): void {
$this->value += $value
}
}
trait WeightModifiable { // 体重操作trait
private int $value;
public function modifyWeight(int $value): void {
$this->value += $value
}
}
class C { // わかりづらいことが起きる!
use HeightModifiable, WeightModifiable;
}
42. 5 つの規則から見るtrait
問題領域の直接的な写像: ○
少ないインタフェース: △
小さいインタフェース: ☓
利用クラス内で全てのメンバへのアクセスが全開放
同居する他trait のメンバにも自由にアクセス
明示的なインタフェース: ☓
利用クラス側のprivate メンバへのアクセスさえ断りなく可能
プロパティの名前衝突のマージに問題がある場合も気づけない
情報隠蔽: ☓
trait local なメンバを定義できない
private / protected / public は利用クラス側の可視性としてコピペ展開される
45. 5 つの原則とtrait: 自己文書化の原則: ☓
部品についてのすべての情報を部品の一部として持つようにするという原則
かなりクラスに近い表現力はある
PHP 8.2 からは定数定義もできる
「特定のinterface を実装するために使われるもの」をコメントでしか書けない
信頼性高く書けるクラスより弱い
46. 5 つの原則とtrait: 統一形式アクセスの原則: △
プロパティの値を読み書きする時もメソッドを呼ぶ時も同じ表記を使うという原則
できないが、クラスもできないのでクラスより悪くはない
将来クラスで可能になればtrait でも可能になる
internals でProperty Accessors の議論を進めている人もいる
47. 5 つの原則とtrait: 開放/閉鎖の原則: ☓
既存の部品への修正をせず部品を拡張できるという原則
abstract メソッドでtrait 中心の部品構成でも一応可能
interface 側とtrait 側で同じシグネチャを記述するようなこ
とが起きがち
特定のinterface を実装していることの要求をできるクラス
とくらべるとやや弱い
trait T1 {
abstract public function f1(): void;
public function f2(): void {
f1();
}
}
trait T2 {
use T1;
public function f1(): void { echo 'T2';}
}
trait T3 {
use T1;
public function f1(): void { echo 'T3';}
}
48. 5 つの原則とtrait: 単一責任選択の原則: ☓
選択肢を提供する際、システム内の1 つの部品だけがその選択肢のすべてを把握すべきという原則
言語的にサポートされているとは言い難い
どのtrait を使うかが利用側の各クラスなどへ静的にuse で分散して埋め込まれる
use 先を分岐するような仕組みがtrait にはない
53. インタフェースとあわせての実質的な多重継承の実現
trait は型を伴わない実装
interface は実装を伴わない型
2 つあわせて(だいたい)多重継承
// 単一継承だとこういうのを小分けにできない
// traitなら小分けに分割できる
class P {
public function common_function(): void {}
// A、Bにのみ必要な機能がC、Dにも導入
public function ab_function(): void {}
// C、Dにのみ必要な機能がA、Bにも導入
public function cd_function(): void {}
}
class A extends P {}
class B extends P {}
class C extends P {}
class D extends P {}
59. - 宣伝-
WEB+DB PRESS vol.130 のPHP 連載でも
trait の扱いについて書いてます!
このトークと被る部分もありつつ、切り口は違い、文章としてまとめてあります
興味があればぜひ
https://gihyo.jp/magazine/wdpress/archive/2022/vol130