Upgrade to Pro — share decks privately, control downloads, hide ads and more …

導⼊から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将...

sji
September 25, 2022

導⼊から 10 年、PHP の trait は滅びるべきなのか その適切な使いどころと弱点、将来について

sji

September 25, 2022
Tweet

More Decks by sji

Other Decks in Programming

Transcript

  1. WEB+DB PRESS の現 PHP 連載担当 昨年 6 月から WEB+DB PRESS

    の PHP 連載 だいたいわりと真面目な話をしてる
  2. 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; // トレイトの利用 }
  3. もともと PHP 専用とかではない 2002 年に Nathanael Schärli らが ECOOP2002 向けに出した論文で提案

    いくつかの言語でアイディアが取り入れられた https://www.cs.cmu.edu/~aldrich/courses/819/Scha03aTraits.pdf
  4. ちなみに当初論文の案ではtrait は状態を持たなかった 多重継承は状態の衝突への対応が難しいので、あえて外されてた プロパティが定義できるのは PHP が独自に入れた変更 元論文では trait が abstract

    で実装クラス側へアクセッサ提供を要求する形を提案 それだとボイラープレートが増えるので辛いとはみんな思ってた アカデミアのほうでも Stateful Traits のような拡張が後追いで提案された https://link.springer.com/chapter/10.1007/978-3-540-71836-9_4
  5. 品質とは バートランド・メイヤーさんの『オブジェクト指向入門 第2 版 原則・コンセプト』(訳:酒匂寛さん)は品質とはなんぞ やで始まる 品質: 外的要因 + 内的要因

    外的要因: 性能とか使いやすさとか、ユーザが認識する部分 内的要因: 外的要因の達成に必要な専門家だけが見る部分 達成すべきは目標は外的要因
  6. 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; }
  7. 5 つの規則から見る trait 問題領域の直接的な写像: ◦ 少ないインタフェース: △ 小さいインタフェース: ☓ 利用クラス内で全てのメンバへのアクセスが全開放

    同居する他 trait のメンバにも自由にアクセス 明示的なインタフェース: ☓ 利用クラス側の private メンバへのアクセスさえ断りなく可能 プロパティの名前衝突のマージに問題がある場合も気づけない 情報隠蔽: ☓ trait local なメンバを定義できない private / protected / public は利用クラス側の可視性としてコピペ展開される
  8. 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';} }
  9. その前に前提として DI (合成)で済むならそっちのほうがよい DTO っぽいのにちょっとデータ取得メソッド生やしたいとか には DI より向く 他に頼れるやつがいない時に使う最終兵器 //

    これより class C1 { use FunctionalityTrait1; use FunctionalityTrait2; } // クラスの DI にするほうが楽 class C2 { public function __construct( private FunctionalityClass1 $functionality1, private FunctionalityClass2 $functionality2, ) { } }
  10. インタフェースのデフォルト実装 リッチインタフェースを利用者が扱いやすい形で採用可能 利用コードへ影響を与えずにインタフェースをあとから拡張 可能 PSR-3 の LoggerAwareInterface と LoggerAwareTrait 、

    LoggerInterface と LoggerTrait など interface HogeInterface { public function method1(): void; } trait HogeDefaultImplementation { public function method1(): void { echo 'hoge'; } } class Hoge implements HogeInterface { use HogeDefaultImplementation; }
  11. インタフェースとあわせての実質的な多重継承の実現 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 {}
  12. クラスの分割実装 機械生成コードに手書きのコードを足したい場合などに嬉し い 直接修正するとスキーマ変更時の再生成で上書きされる ORM とか IDL からのコード生成とかへデータアクセス用の 処理をちょっと足したいとか //

    機械生成コードをクラス側に置く構成も可 trait MachineGeneratedCodes { // 中略(機械生成されたコード) } // ↓ 別ファイルで定義 // 手書きコードをトレイト側に置く構成も可 class HandWrittenCodes { use MachineGeneratedCodes; // 中略(手書きのコード) }
  13. - 宣伝 - WEB+DB PRESS vol.130 の PHP 連載でも trait

    の扱いについて書いてます! このトークと被る部分もありつつ、切り口は違い、文章としてまとめてあります 興味があればぜひ https://gihyo.jp/magazine/wdpress/archive/2022/vol130