LoginSignup
2
0

More than 5 years have passed since last update.

PHPのInterfaceで__invokeを使うべきか?

Last updated at Posted at 2019-04-15

PHPのinterfaceを使う場合、__invokeメソッドを使うことができます。これを使うとメリット・デメリットは何だろう?と(どうでもよさそうな)ことを考えたので書いてみます。

例えば、

interface DoItInterface {
    public function __invoke(): DoneInterface;
}

とします。このinterfaceを実装したDoItクラスがあるとすると、こんな風に使えます。

$do = new DoIt();
$done = $do();

ほんのちょっとコードが減ります。便利なような、そうでもないような… メインのメソッドが一つしかない場合に、__invokeを使うのはメリットはあるのでしょう?

TL;DR

いきなり結論を書くと、interfaceなどで__invokeは使わないほうがいい、と考えます。

メリット

メソッドの名前を考えなくていい

すでにinterface名で体を表しているのであれば、メソッド名を考えなくてすみます。これは大きい。

callableとして使える

Closureなどと混ぜて使える。

デメリット

クラスのプロパティに使うと残念な感じになる

こういうコードになります。

class DoAll {
    /**
     * @var DoItInterface
     */
    private $doIt;
    public function do() {
        // $this->doIt();        // <- そのまま呼べない!
        $this->doIt->__invoke(); // <- なんか格好悪い!!
    }
}

PHP7.2でも、まだ対応できてません。パーサー変えるとき、対応するという話を聞いた記憶がかすかにありますが、まだみたいです。結局__invokeを使うことになるなら、普通にメソッド名をつけたくなります。

IDEで検索に引っかからない

IDEというか「PhpStorm 2019.1」での話ですが、DoItInterface::__invokeを「Find Usage」で検索した場合、検索対象になりませんでした。このコードです。

$do(); // <- 検索で出てこない!

これはPHP自体の問題ではないですが、開発から見ると結構大きな問題と思います。リファクタリングするときに修正箇所を見落としたり、自動で修正できないことになります。

この一点だけですが、__invokeを使わないことにしました。

メソッド名は?

では、メソッドの名前は何がいいのでしょう?

interface名と似た名前を使う

例えばSendMailInterface::send()のように、インターフェース名と同じような名前を使うことです。インターフェースだけを見ると妙な感じがしますが、クラス名が正しくつけられていれば、問題ないはず… 例えば、$notifyUser->send()であれば違和感はないです。

英語でよくある言葉を使う

こういうメソッドでよく使われてる動詞を使います。

  • handle
  • apply
  • invoke
  • executeあるいはexec
  • do

PHPで「do」は見たことないかも…

ともあれ、インターフェースに合わせて、うまく動詞を選ぶ必要はありそう。Filterならapplyとか。英語のセンスが必要ですね。

2
0
0

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
2
0