オープン・クローズドの原則に則ってコードを書こうと思うとResolverクラスをよく使うことになると思います。

PHPerKaigi2018でベストトーク賞を受賞した @hidenorigoto「SOLIDの原則ってどんなふうに使うの?」 の最終形態である PHPカンファレンス関西2018で「続・SOLIDの原則ってどんなふうに使うの? オープン・クローズドの原則 センパイのコーディングノート編」 の発表中には IF文禁止ギブス なる言葉も飛び出しました :sweat_smile:
つまり、コードを書いていてIF分岐したくなった箇所はinterfaceに外出ししたうえで、Resolverで解決して使うことができるというわけです。

そのResolverクラスをPhpStormで楽に書くためのコードテンプレを作ったのでシェアします。

設定方法

PreferencesEditorFile and Code TemplatesFile+ で新しいテンプレートを追加。

_2018-09-11_13_16_06

  • Name: 任意。 PHP ResolverClass とか
  • Extension: .php (さすがにイマドキ .inc の人はいないと思いたいですが、いればそうしても良いかと)

テンプレートの内容

<?php

namespace ${NAMESPACE};

#set($TARGET=$NAME.replace('Resolver', ''))
#set($VARNAME_START = $TARGET.substring(0,1).toLowerCase())
#set($VARNAME_REST = $TARGET.substring(1))
#set($VARNAME=$VARNAME_START + $VARNAME_REST)
#set($PROPERTYNAME=$VARNAME + 's')

class ${NAME}
{
    /**
     * @var ${TARGET}Interface[]
     */
    private ${DS}${PROPERTYNAME} = [];

    public function add${TARGET}(${TARGET}Interface ${DS}${VARNAME})
    {
        ${DS}this->${PROPERTYNAME}[] = ${DS}${VARNAME};

        return ${DS}this;
    }

    public function resolve(${DS}target)
    {
        foreach (${DS}this->$PROPERTYNAME as ${DS}${VARNAME}) {
            if (${DS}${VARNAME}->supports(${DS}target)) {
                return ${DS}${VARNAME};
            }
        }

        throw new \LogicException('No $TARGET defined');
    }
}

コードテンプレートにPHP ResolverClassを登録

OK を押します。

使い方

Resolverクラスを作りたいディレクトリのコンテキストメニューを開き、 NewPHP Class を選びます。

ContextMenuからNew PHP Class

いつもの新規クラス作成画面ですが、 Template で先ほど追加した PHP ResolverClass が選べるようになっているので、これを選びます。

CreateNewPHPClassでTemplateとしてPHP ResolverClassを選ぶ

Nameに Resolverクラス名 を指定してOKします。

CreateNewPHPClassでnameにFooResolver TemplateにPHP ResolverClassを選んだところ

テンプレからResolverクラスが自動で作られました。

できあがりのFooResolver

あとは実際にFooInterfaceを書いて、FooInterface::supports() の引数に合わせてresolve($target)をちょちょっと調整すればResolverクラスが完成です。

楽ですね!