このエントリーをはてなブックマークに追加

オープン・クローズドの原則に則ってコードを書こうと思うと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クラスが完成です。

楽ですね!


このエントリーをはてなブックマークに追加

7月に大阪で行われたPHPカンファレンス関西2018にて、「すばやく実装するための戦略とテクニック」というタイトルで発表してきました。

内容について

スライド: サンプルコード: https://github.com/77web/phpkansai2018-hellopage

※ 当日にSlideShareでスライドを公開しましたが、PDFをアップロードしたにも関わらず全画面表示にしないと文字が出ないという問題が発生し、SlideShareのサポートに問い合わせてもやる気ない返答が返ってきたので、改めてSpeakerdeckに公開しました。

準備について

この発表は、同僚からのリクエストで実現したものでした。PHPカンファレンス関西に行きたいなーと思い、「なにか聞きたいネタありますか?」とSlackで聞いたところ「これが聞きたい」と出てきたものです。(カルテット開発部には勉強会・カンファレンスの交通費補助制度があり、支給される条件タイプの1つとして「発表する」というものがあります :sweat_smiles: )

当日の発表の中でも言いましたが、普段チームの皆から「速さ」を認めてもらい、頼りにしてもらって仕事をしているので、皆にコツや気をつけていることを伝えられるように発表内容を練りました。
今までLTメインで出ていたので割とぶっつけ本番で発表することが多かったのですが、今回ははじめての30分セッションということで、何回も社内で発表練習をさせてもらい、フィードバックを受けながら完成させました。

当日

前夜祭でinterfaceとレイヤーアーキテクチャについて発表した方がいたり、同じ時間枠の他のセッションでinterfaceの話をする方がいたり、「PHP界にinterfaceブームが来ている…!?」とワクワクしながら朝の新幹線に乗って大阪に向かいました。

1個前の発表から結構入れ替わりがあったにも関わらず、発表開始時点で満員になっており、立ち見で聞いてくださった方もいたほどで、感謝感激です。
今回はじめて発表中にデモを入れたため、途中画面切り替えに失敗するハプニングもありましたが、なんとか最後まで喋りきることができました。

発表後も久しぶりの師匠や知人に会い、色々な話を聞いて、とても楽しく刺激的な一日になりました。

まとめ

PHPカンファレンス関西には何回か行っていますが、今回特に「いいな」と思ったのは実行委員会の方から発表中の写真を送ってもらえたことです。
登壇者には嬉しいサービスだと思います。

大阪は東京に比べて近いですし、また来年も行きたいです! (あるいはPHPカンファレンス名古屋…?)


このエントリーをはてなブックマークに追加

はじめに

Symfonyの Dotenvコンポーネント を使うと、.env というファイルに環境変数を定義しておくことで、アプリケーション内から getenv() $_ENV $_SERVER などを通してその環境変数にアクセスできるようになります。

Symfony 3.3以上ではフレームワークにビルトインされており、Syfmonyアプリケーションのdev環境では .env ファイルを使って環境変数を設定することができるようになっています。

この記事でお伝えすること

今回、.env ファイルで 値に改行文字を含む ような環境変数を設定したい状況に遭遇し、方法を調べましたので、小ネタですが記事として残しておきたいと思います。

結論

symfony/dotenvのテストコード を見てみたら、知りたいことがほぼ全て書かれていました :+1:

複数行に渡る文字列を1つの環境変数にセットしたい場合

結論としては、以下のようにすれば複数行に渡る文字列を1つの環境変数にセットできます。

FOO="a
b
c"

これで、FOO 環境変数に

a
b
c

という値がセットされます。

"" で囲む代わりに '' でも同じことができないのかな?と思い、テストケースの中にはなかったので手元で実験してみたところ、Missing quote to end the value というエラーになってダメでした。

さらにその中に \n という文字列を含ませたい場合

これはちょっとレアなケースかもしれませんが、例えば以下のような文字列を環境変数にセットしたい場合、少し話がややこしくなります。

{
  "private_key": "-----BEGIN PRIVATE KEY-----\naaaaa\nbbbbb\nccccc\nddddd\neeeee\n-----END PRIVATE KEY-----\n"
}

この場合、"\" とエスケープしなければならないのは分かるとしても、その上で先ほどのように単純に

JSON="{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----\naaaaa\nbbbbb\nccccc\nddddd\neeeee\n-----END PRIVATE KEY-----\n\"
}"

としてしまうと、文字列の中に含まれる \n が展開されてしまい、JSON 環境変数の値は

{
  "private_key": "-----BEGIN PRIVATE KEY-----
aaaaa
bbbbb
ccccc
ddddd
eeeee
-----END PRIVATE KEY-----
"
}

となってしまいます。これではJSONとしてパースできません。\n は文字列として値の中に残したいのです。

文字列連結を使う

symfony/dotenvのテストケースのこの部分 を見ると、文字列の連結ができるようです。

また、この辺り を見る限り、""'' の使い分けは、PHPの文字列リテラルと同様、"" では \n が展開されて改行文字として出力され、'' では展開されずそのまま \n が出力されるようです。

というわけで、今回のケースでは以下のように書けば意図したとおりの文字列を環境変数にセットできます。

JSON="{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----"'\n'"aaaaa"'\n'"bbbbb"'\n'"ccccc"'\n'"ddddd"'\n'"eeeee"'\n'"-----END PRIVATE KEY-----"'\n'"\"
}"

ちょっと分かりにくいですが、要するに以下の文字列を連結しているわけです。\n の部分のみ "" ではなく '' で囲んであるので、改行文字に展開されずにそのまま出力できるというわけです。

"{
  \"private_key\": \"-----BEGIN PRIVATE KEY-----"
'\n'
"aaaaa"
'\n'
"bbbbb"
'\n'
"ccccc"
'\n'
"ddddd"
'\n'
"eeeee"
'\n'
"-----END PRIVATE KEY-----"
'\n'
"\"
  }"

おわりに

最後に改めて結論をまとめておきます。

  • 複数行に渡る文字列を環境変数にセットしたい場合は、"" で囲んで普通に改行しちゃえばOK
  • 文字列中に " という文字列を含みたい場合は \" とエスケープする
  • 文字列中に \n という文字列を含みたい場合は、その前後で文字列を切って、\n だけは '' で囲む形にして、連結する
    • 実践的には、\n"'\n'" で一括置換すればOK

以上です。

小ネタでしたが、どこかで誰かのお役に立てば幸いです :raised_hands:

カルテット開発部では、Symfonyを使いこなしたい仲間を募集しています!