LoginSignup
7
9

More than 5 years have passed since last update.

マジックメソッド(特に `__construct` )は、Traitに「メソッドの引き上げ」をしてはいけない

Last updated at Posted at 2016-06-01

発端

Traitは、メソッドの実装のコピペを回避するのに多用します。でも、マジックメソッド(特に __construct() )を引き上げると、思いの外「再利用可能な機会が狭まる」ので、やめたほうがいいなぁって感じました。

もっともらしい理由

特に使用頻度が高い(と思う)、__construct()について考えました。他のものについては、深く考察していないです。

メソッドの使用率(メソッド名の重複率)が高い(と思う)

マジックメソッドなので、「メソッド名が同じ」だから、存在すれば即重複します。複数のTraitを利用する場合に、重複していないことを毎回確認するのはつらいです。

  1. 「コンストラクタ」マジックメソッドの使用率が高いので、メソッドの重複率が高い。
  2. メソッドの重複率が高いと、意図しない上書きが発生する。
    • 特に、複数のTraitをuseした時に、発生しやすい。

特に統計とかはとってないです。ただの"感覚"。

コンストラクタは改修するのがつらい

  • コンストラクタは、クラスのデータ構造に密接に関係するので、改修することが難しい。
  • コンストラクタは、使用率が高いので、「Method Pull Down」する場合にコストが高い。

データ構造に密接に関係する

Getter/Sestterの乱用はアンチパターンなので、一旦論外とします。私の意見としては、「コンストラクタは、そのクラスのデータにおける主キーを明確にする」から、「コンストラクタの引数で一切の値を渡さずに、すべてをSetterに頼るのはダメ」という論調です。

で、これを前提にすると、コンストラクタに「主キーを明確にする」責任が発生する。「主キーの明確にする」のは、DDLの範疇になります。つまり、コンストラクタの実装とは、「そのクラスの主キーの"定義"」である、とも言えます。"定義"である以上、基本的に「変更するな」と。

Method Pull Downするときに、変更コストが高くつく

同じコードを、そのTraitを利用しているすべてのクラスにMethod Pull Downするのだと、(IDEの機能で自動でやる場合を除き)クラスの数だけコピペを繰り返すことになります。心理的なハードルが高いです。

各マジックメソッドは、何に使われるのか

自分が、各マジックメソッドを何に使ってるのか、一応考えました。結果として、どれも「データ構造とかデータの内容」に依存してて、インターフェースへの依存ではないので、ダメでしょう。

  • __construct()はそのクラスの主キーを定義する。
  • __destruct()はインスタンスが破棄される時の"状態"に依存する処理を頻繁に書く。
  • __wakeup()__sleep()は、シリアライズ前後のデータに依存した処理を頻繁に書く。
  • __toString()は、インスタンスプロパティに依存した処理を頻繁に書く。固定値を返すだけなら、別に良いだろう。
  • __invoke()は、多分、インスタンスのプロパティに依存した処理を書く。コマンドパターンのInvokerとして使うこともある。(monologのProcessorとか。)
  • __set_state()__debugInfo()は、多分、インスタンスのプロパティに依存した処理を書くと思う。

useしてる先のクラスで上書きすればいいんじゃね?

ダメだろ。「後から自由に上書きする」という点では、.htaccessみたいなもんだと思います。

一般的に、サーバの主設定ファイルにアクセスできない場合を除いて、 .htaccess ファイルの使用は極力避けてください。
普通は可能であれば .htaccess ファイルの使用は 避けてください。

この理論で行くと、「使用元のTraitにアクセス出来ない場合」となるわけだが、どういう状態だよ?ということになりますが。「Traitがスパゲッティ化しすぎて変更不可能だから、やむを得ず上書きする」くらいしか理由が思いつかないです。

上記のリンク先にある「.htaccessファイルの使用を避ける」理由を、".htaccess"を"traitやクラス"に置き換えて読んだ場合と、だいたい同じ理由になると思います。

あと、以下の様な点で、この手法はダメだと思います。

  • 各Traitが実装している処理の要件を満たす実装を、繰り返す
  • use元のTraitに変更が加わった場合に、変更し忘れるかもしれない。
    • 共通化した理由とはなんだったのか。

おわり

7
9
1

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
7
9