モックライブラリ「Prophecy」と「PHPUnit_Framework_MockObject」の比較

1人AdventのDay-6です。

adventar.org

前回の記事は @o0hさんでした。本日は、私@o0hがお送りします。

さて、皆さんはPHPUnitを利用する際に、モックを使っていますか?
PHPUnitには、標準で2つのモックオブジェクトが入っています。

1つ目が、MockObject です。これがデフォルト・・・という言い方も、「2種類とも最初から使える状態になっている」以上は微妙な感じもするのですが、まぁそんな感じです。
2つ目が、Prophecy です。PHPUnitの公式Docを見ると、以下のように説明がされています。

クセは強いけれども、強力で柔軟な、PHP のオブジェクトモッキングフレームワークです。 最初は phpspec2 のニーズを満たすために作られましたが、今やそれ以外のテスティングフレームワークでも、 最小限の努力で使えるようになりました」

・・・よくわかんないですね!
ということで、今回は「この2つを実際に使ってみるとどんな感じになるの」を比べて見たいと思います。

本題に入る前に

Prophecyについて

まず、Prophecyについてはこちらの記事が大変参考になるので、ご一読されることをおすすめします。

qiita.com

ダブル、スタブ、モック、スパイ

モックオブジェクトについて語るので、よく混同される用語の整理をまずしておくのが良いかと思います。 ・・・と思ったのですが、シンプルに纏めてくれてい記事があったのでご紹介を。

qiita.com

といっておいてなんですが、本記事中では特に意識せずに「モック」という言葉を利用します。モック方式・スパイ方式という言い方をした場合にだけ、テスト作法に関しての話題にフォーカスしているものとして、使い分けているとご理解いただければと。

モックっていつ使うの?

「テストが難しいもの」を登場させる必要があった場合に利用しますね。よく「インターフェイスに対してテストをかけ」などといいますが。
例えば、「決済APIを叩く処理」についての実装をしているとき、そのテストは「テストを実行するたびに決済を行う」わけには行きません。そこで、決済という外部システム=「依存コンポーネント」をモック化してしまえ、見たいな話です。

「決済して、その結果を返す部分」について「決済に必要なパラメータを受け取って、実行したふりをして値を返す」という振る舞いをする"ハリボテ"。それが、モックです。

PHPUnitでモックを使ってみよう

こんなに雑なサンプルコードを用意してみました!「あ、外部サービスを叩いているのねふむふむ」くらいのイメージをしてください。それ以上でも以下でもありません。

<?php
namespace App;

use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;

/**
 * Class HogeService
 * @package App
 */
class HogeService
{
    /**
     * HogeService constructor
     */
    public function __construct()
    {
        $this->http = new Client();
    }

    /**
     * Request user object to Hoge
     * 
     * @param int $id user id to request
     * @return ResponseInterface
     */
    public function getUser(int $id)
    {
        return $this->http->get("/user/{$id}");
    }
}

さて、 getUser()の単体テストを書きたいわけですが、ここで「テストの実行のたびに実際に「ほげ」にアクセスさせるわけには行きません。*1

また、HogeServiceはGuzzleHttp\Clientに依存しています。ということで、「実際にテストが困難な依存コンポーネント」として、Clientをモック化してしまえ!!という捉え方をしました。

実際にモックを用いたテストコード

ここからは、「モックを使ってみよう」のコーナーです。

まず簡単に、次のようなテストクラスを作成しておきます。

<?php
namespace App;

use GuzzleHttp\Client;
use Psr\Http\Message\ResponseInterface;

/**
 * Class HogeService
 * @package App
 */
class HogeService
{
    /**
     * HogeService constructor
     */
    public function __construct($client = null)
    {
        $this->http = $client ?? new Client();
    }

    /**
     * Request user object to Hoge
     *
     * @param int $id user id to requestc
     * @return ResponseInterface
     */
    public function getUser(int $id)
    {
        return $this->http->get("/user/{$id}");
    }
}

ここに、説明用にいろいろとテストケースを追加していきます。

1. PHPUnit MockObjectのpartial mockを用いた例

まずは、以下の内容で検査をできると考えました。

  • HogeService::getUser($userId)の呼び出し実行時に
  • Client::get()に対して
  • /user/:user_id を引数として
  • 呼び出しが1回行われている

これをもって、「ちゃんとHogeをキックできている」と判断することとします

素直に書いてしまえば、この様になりました。

<?php

    /**
     * test to get()
     */
    public function testGet()
    {
        $userId = 100;

        /** @var MockObject|HogeService $mock */
        $httpMock = $this->createPartialMock(Client::class, ['get']);
        $httpMock->expects($this->once())
            ->method('get')
            ->with("/user/{$userId}");
        $this->subject->http = $httpMock;


        $this->subject->getUser($userId);
    }
  1. createPartialMock() で、partial mockを作ります
    • これは、「指定したメソッドだけ無効化=モック化する」という方法です
  2. 「1回だけ」「getメソッドが」「user取得用パス文字列を引数として」呼び出されることを期待する・・・というモックを作成する
  3. そのモックを、subjetクラスのメンバとして注入し
  4. 実際に、getUser()をコールしてみる!

という内容です。これで、もし「期待されたとおりの内容で呼び出されていない」となると、テストケースにfailureが記録されます。

2. Prophecyのモック方式を用いた例

さて、同じ発想で今度はProphecyを利用して書いてみます。

<?php
    /**
     * test to get()
     */
    public function testGetByProphecy()
    {
        $userId = 100;

        /** @var ObjectProphecy|Client $clientP */
        $clientP = $this->prophesize(Client::class);
        $clientP->get("/user/{$userId}")->shouldBeCalledOnce();
        $this->subject->http = $clientP->reveal();


        $this->subject->getUser($userId);
    }

事前に「何が、何回、どうやって呼ばれるか」を宣言しておく持っk方式です。

  1. prophesizeに対象クラスを渡して、ObjectProphecyインスタンスを取得します
  2. get()が実際に呼び出されるような形式でmethodを書き・・・ 「1度だけ呼び出されるべき」という指定を最後にくっつけます
  3. reveal()により、モック*2を取得します

あとは実際に、subject->getUser()をコールしてみて、どうなるかな?といった具合です。

3. Prophecyのスパイ方式を用いた場合

今度は、事後に「呼ばれたかな?」を検査するスパイ方式です。

<?php
    /**
     * test to get()
     */
    public function testGetByProphecySpy()
    {
        $userId = 100;

        /** @var ObjectProphecy|Client $clientP */
        $clientP = $this->prophesize(Client::class);
        $this->subject->http = $clientP->reveal();

        $this->subject->getUser($userId);

        $clientP->get("/user/{$userId}")->shouldHaveBeenCalledOnce();
    }
  1. いきなりrevealして
  2. subject側の実行が終わってから、 「have been called: shouldHaveBeenCalled()」と検査する

という違いです。

さて、これで「MockObject」「Prophecyのモック方式」「スパイ方式」の3種類の書き方を抑えました。

Prophecyは「モックしたクラス」として型の制約をパスできる

例えば、HogeService::setClient() という利用するクライアントオブジェクトを注入できるメソッドを用意したとします。

<?php
    /**
     * HogeService constructor
     *
     * @param ?Client Client to use..
     */
    public function __construct(?$client = null)
    {
        $this->setClient($client ?? new Client());
    }

    /**
     * Inject Client object.
     *
     * @param Client $client
     */
    public function setClient(Client $client)
    {
        $this->http = $client;
    }

これに関連して、先程用意したテストケースを書き換えます

<?php
     /**
     * test to get()
     */
    public function testGetByProphecySpy()
    {
        $userId = 100;

        /** @var ObjectProphecy|Client $clientP */
        $clientP = $this->prophesize(Client::class);
        $this->subject->setClient($clientP->reveal());

        $this->subject->getUser($userId);

        $clientP->get("/user/{$userId}")->shouldHaveBeenCalledOnce();
    }

reveal()で得たオブジェクトは、これでも受け入れられることができます。

感想

Prophecyは、思想として「絶対に部分的モックなんてやるものか!」というのがある、と先程のHirakuさんの記事で紹介sれていました。テストの美しさ、そもそもあるべき思想として「モックが実際の動作を部分的に実現している状態」への気持ち悪さ・不完全さというのは、何となく分かる部分もあります。
それゆえに、PHPUnitもMockObjectは「部分的モックが使える」という点は、ある意味では強みでもあるのかな〜と感じました。実際、「挙動をぶっ壊してモックとする部分は最小限に抑えたほうが安心」という場合も、ないとも言い切れないとも思うからです。

対して、記述の簡潔さはProphecyの方が優位だな・・?と感じています。どう考えても、標準のMockObjectのほうが「癖が強い」のでは・・・・・・? ;;
expectsの指定もそうですし、スパイ方式での検査の提供によって、実際に検査する箇所を物理的に「actualの実行のあと」に持ってこれる、というのはテストコードの「見た目の気持ちよさ」において魅力を感じるのです。
最もベーシックな単体テストは、「実行結果をメモしてそれについてassertionを行う」というものでしょう。つまり、実行→結果検査という順序で記述がなされます。それを、「事前設定式」のモック方式の場合、期待する内容 -> 実行となっているわけです。冷静に考えると、これは気持ち悪いかもしれない・・・

そんなところで、隙があらばProphecyの実戦投入も狙ってみたいな!と思った次第でした😁

*1:なお、このコードはそもそもアクセス可能なURIを生成できないので、外部アクセスを生じないのですが

*2:スパイ方式で利用することもあるので、doubleという方が正しい

SymfonyはPHP-FIGから離脱するのかな?

1人AdventのDay-5です。

adventar.org

PHP的にはそろそろPHP7.3が出るよ〜ってことで、明るい話をしたいなぁ!って頃だと思うのですが。。今日は「最近あったニュース」でいう事では、個人的にこちらも注目しています。

※ 本記事は、私が普段Symfonyやそのコミュニティに接していなかったり、PHP-FIGの動向・思想やメンバーの変遷についても過去から深く追っていた訳ではないので、間違いに気づいたりご指摘をいただけたら積極的に訂正していきたいスタイルです・・・

なお、書くにあたって情報を収集していたところ、とても良くまとまっている記事が見つかりました。
こちらもぜひご覧ください。

hub.packtpub.com

何が起きているのか? / 事の発端

Remove Symfony by fabpot · Pull Request #1120 · php-fig/fig-standards · GitHub

From 6fea4246955bf33648579f6822146dd49b48383e Mon Sep 17 00:00:00 2001
From: Fabien Potencier <fabien@potencier.org>
Date: Tue, 20 Nov 2018 19:19:51 +0100
Subject: [PATCH] Remove Symfony

---
 personnel.md | 2 --
 1 file changed, 2 deletions(-)

diff --git a/personnel.md b/personnel.md
index a7a48d684..519bd1360 100644
--- a/personnel.md
+++ b/personnel.md
@@ -67,7 +67,6 @@ Feel free to contact the secretaries at info AT php-fig.org. For more informatio
 | [Stash]                           | Robert Hafner ([@tedivm])             |
 | [Stormpath PHP SDK]               | Brian Retterer ([@bretterer])         |
 | [SugarCRM]                        | Andreas Sandberg ([@yellowandy])      |
-| [Symfony]                         | Fabien Potencier ([@fabpot])          |
 | [Flow] and [Neos]                 | Karsten Dambekalns ([@kdambekalns])   |
 | [Wikibase] and [Semantic Media]   | Jeroen De Dauw ([@JeroenDeDauw])      |
 | [Yii framework]                   | Alexander Makarov ([@sam_dark])       |
@@ -214,7 +213,6 @@ Feel free to contact the secretaries at info AT php-fig.org. For more informatio
 [Stash]: http://www.tedivm.com/stash
 [Stormpath PHP SDK]: http://www.stormpath.com
 [SugarCRM]: http://developers.sugarcrm.com/wordpress
-[Symfony]: http://www.symfony.com
 [The League of Extraordinary Packages]: http://thephpleague.com
 [Wikibase]: http://www.wikiba.se
 [Yii framework]: http://www.yiiframework.com

ということで、中々にインパクトのあるdiffだな!という内容のPRが、提出されました。

本題に入る前に

蛇足っぽいのですが、この話のスコープをはっきりさせるためにいま一度整理します。

PHP-FIGについて

PHP-FIGは、 PHP Framework Interop Group という集団です。
もともとは、「PHPに標準を送ろうぜ!」みたいな動機で集まってきました(雑)。
発足とそのあとの歴史については、この記事にまとまっているので御覧ください。

www.sitepoint.com

諸々を端折って、今は、「FIG」を名乗っているわけです。その目的は、(過去の反省を踏まえて「より柔軟・踏み込んだ提案をしていく」というスタンスに基づき)「フレームワーク間の相互運用を推し進める」ことにあります。

例えばPSR-0 autoloading standard *1などは、「PHP5.3で名前空間が入って、便利だけど、命名規則とかばらけちゃうとね」「もっとポテンシャル生かしてちゃんと使いたいよね」といった問題意識に端を発している訳です。
今では後継のPSR-4がPHPの「スタンダード」ですが、composerを含む「多種多様なライブラリを気軽に使える」エコシステムは、こうした提案力を持った存在により成立・推進されている面は大いにあると思います。ライブラリの作者からしても、より汎用性の高いものを作る上で、明確に「よくある」といえる実装やパターンがあると助かることもあるのではないでしょうか。そして、ライブラリの作成に関わる人数が増え、手が増えていくことで質の高いソフトウェアも生まれ・・・というサイクルがあると思います。

PSRについて

PSRは、有力なフレームワークの代表者や個人といった有識者が採択などを行っています*2。 その内容には、コーディングスタイルのガイドからキャッシュの使い方、DIコンテナに関する議論まで多岐にわたります。
これを「利用者が増えてくれば、その利用者の受ける恩恵は増えていく」というのを理想としてはいると思いますが、必ずしも「参画したら従うこと」と取り決めているわけではありません。
PHP-FIGホームページに有るFAQを見ると、以下のように記述がされております。

[Q] Do voting members have to comply to the standards?
[A] No. Becoming a voting member on the PHP-FIG in no way forces a member or project to implement every - or any - accepted PSRs. Projects have to consider backwards-compatibility issues when upgrading and make the changes at the right time, so it is assumed most projects will eventually adopt, but it is not a requirement.

Frequently Asked Questions - PHP-FIG

「強制的に従わなくちゃいけないものでもないし、互換性とかあると思うし、使うものを好きに選んでね」という話になっています。

PHP-FIGは、様々なプロジェクトが「相互運用性を尊重」した作成するための共通基盤として、素晴らしいやり方「だった」

さて、件のツイートに立ち返ってみます。

Fabien Potencier氏(@fabpot)はSymfonyのオリジナルの作者で、SynfonyはPHP-FIGのメンバープロジェクトです。「PHPの世界でのメジャーが集まって方向性を決めよう」というPHP-FIGの性質上、歴史・知名度・普及度のいずれの観点から見てもSymfonyは重要なプレイヤーといえるでしょう。

そんな @fabpot 氏が、過去形で「相互運用性のため」に「よいもの だった 」と語っているわけです。

スレッドを見ると、何が「よく」て何が「悪かっ」たのかが語られています。

めちゃくちゃな超訳もどきにはなりますが、大体こんな事を言っています

  • PSR-0/4: autoloadingは、ライブラリを互いに乗り入れるための最高の1歩だった
  • PSR-1/2: conding-standardは、些末な事に気を取られずに上手くやるのを推し進めてくれた
  • PSR-11: containerは協働のための見本。私を含め、最初こそ批判的に見ていた人はいるが、既存PJをより簡単にDIに乗っけていくための落とし所を見つけることができた。

このあたりは、"相互"のためにという思想を体現しているな〜と賛成しているように見えます。
PSR-7/14に関する言及は、かなり批判的です。

www.php-fig.org

github.com

  • PSR-7は、相互運用のためのものではない。結局の所、なにか(FIGが)「新しいフレームワークを作り始めた」ようなもの
  • PSR-14も同じ道を辿るだろうな

なお、まだ私は具体的な言及を探してはいないのですが、PSR-7に対して「思想に反する」「やりすぎ」のような立場をとっているのですから、これを前提とした15/17/18についても「そうじゃない!」という感じなのかなーと思います。。

そして、「PHP-FIGは、もう(多様なプロジェクトの)相互運用のためのものでもないし、彼らが独自的なカラーを持ったフレームワークを作るためにあるんだ」とまで言います。

「相互運用可能な」とは

PHPは、言語自体の思想としても、多くのフレームワークにしても「互換性を保つ」ことを非常に大事にしているように感じます。また、先程述べたとおり、PHP-FIGも「後方互換性を尊重し、PSRを実装しない事は大いに有り得る(可能である)」としているわけです。

そのうちにあって、PSR-7(やPSR-14)が「終わりの始まり」とされているわけですが・・・
同じくSymfony勢から、Titouan Galopin氏のこのリプライが問題をわかりやすく描き出します。

「既存のやり方を、寄せていく道がない。そんなのは、「相互運用」とは言えないでしょう。」という失望を感じます。

PHP-FIGはどうなっちゃうの・・?

PR自体はまだマージされていないのですが、これ離脱しないシナリオあるのかな・・・・
FIGは、過去にLaravelやGuzzle、Auraといったプロジェクトが離脱しています。そこに今回のSymfonyの離脱となると、「いろんなフレームワークとかでよく見かける名前」が大きく減りそうだなぁ、と個人的には感じるところ。これらのプレイヤーたちが「PSRに物申す」立場でなくなっていくというのは「策定されたPSRを利用する」可能性も落ちるわけで、「PSRってあまり見かけないよね」な状態になってしまったら・・存在意義が問われそうです。

また、実装(API)が揃っていても、現実的には、結局の所「どこへでも、持ってきてすぐに使える」という状況は作れていないし今後もそうなのだと思います。それも踏まえ、「必要とされる共通のインターフェイスとは」については、今までと少し考え方が変わっていくのでしょうか・・・・?

「やりやすくするため」の仕組みづくりだと思うので、「やりにくいから抜ける」というのは悲しみがありますね・・

*1:これがまさに、「PHP Standards Group」の当初の目的の1つ

*2:プロセスにはこちらを参照 https://www.php-fig.org/bylaws/psr-workflow/

「Hugoでgithub-pages使ってカスタムドメインなブログを構築する」を0から

1人AdventのDay-4です。
元々は「PhpStormでGit/GitHubを使うと便利」みたいなの書くつもりだったのですが、別の作業をしていたらちょっとしたメモができたので、代わりにそちらを使います。

adventar.org


以前書いたコレ

daisuki.nichiyoubi.land

ちょっと用事があって、「1つブログ的なのを増やそう」としています。

「メモ程度の雑に書いたのをとっとと放り込みて〜」というニーズでして、そうすると「ターミナルでも何でもいいから書いてpushしたら終わり!」っていう気軽さ。それだったら、重い腰を立ち上げる!までもなく書けるし。

ということで、同じことやるぞ!!
と思ったわけです。

が、↑の記事だと「自動ビルド・デプロイ」のとこしか抑えてないな〜と思ったので、「レポジトリを作るところから」でいうと、前面カバー出てきていない。
ので、やるか!という記事です。

やりたいこと

  1. githubユーザーアカウント hogeyamahogehoge にて
  2. 任意のレポジトリ github.com/hogeyamahogehoge/fuga
  3. github paegsで、カスタムドメイン(サブドメイン) pagepage.hogeyamahogehoge.com
  4. hugoで作成したページを公開する

ドメインとかGitHub Pagesの設定

1. レポジトリを作る

  1. github.com行って
  2. f:id:o0h:20181204152114p:plain
    new repositoryを押します

2. github-pagesセットアップ

  1. 最初に gh-pages ブランチ作っておくのがいいかも
    1. 何かしら(READMEとか.gitignore)とかがmasterブランチに存在していれば、ブラウザから作れるので
    2. f:id:o0h:20181204152448p:plain
      gh-pagesという名前を入れて Branchesを選択
      *1
    3. すると Create Branch 的なリンクが出てくるので押す
  2. レポジトリのSettingsから「Github Pages」を
    1. Soureに gh-pages Branch を選択、save
    2. Custom Domain にFQDN pagepage.hogeyamahogehoge.com を指定、save

3. カスタムドメインセットアップ

Setting up a custom subdomain - User Documentation

  1. レポジトリ上にCNAMEファイルを設置する
  2. CNAMEというファイル名で、 pagepage.hogeyamahogehoge.comだけ 書いてコミットする
    1. 参考 GitHub Pagesにカスタムドメインを設定する - Qiita
  3. DNS管理の更新
    • hogeyamahogehoge.com
    • CNAME pagepage
    • hogeyamahogehoge.github.io に向ける
  4. 適当なタイミングが来たらdigって確認する `dig pagepage.hogeyamahogehoge.com +noall +answer

Hugoの設定

gohugo.io

ここからは、レポジトリの中身の話。 installは1回やったら済むと思うので省略

Install Hugo | Hugo

1. HugoのPJ作成

このあたりはget startedをなぞるだけだなぁ〜。

  1. さっき作ったレポをcloneして中にcdしておく
  2. hugoコマンドでPJ作成
    1. hugo new site quickstart
    2. カレントディレクトリに作りたいけど「このディレクトリ、もうなんかあるよ〜」で怒られるので、階層を掘っておく
  3. 中身を上の階層に置き直す
    1. mv quickstart/* ./
  4. テーマを設置
    • テーマはギャラリーから選ぶ感じ
      • 例えばblogならココ
      • 各テーマの詳細ページで「Download」からGitHubページに飛べる
    • document通り、submoduleで入れる
    • git submodule add ${git-repo-url}.git themes/${theme-name}
    • config.toml にテーマ指定をおいておく
      • heme = ["${theme-name}"]
  5. 起動確認
    1. hugo server -D でローカルサーバーの起動
    2. デフォだと localhost:1313 なので、開いて表示されればOK
  6. サイト設置
    1. config.toml をいじる
      1. タイトル(サイト名)あたりは最低限入れておいたほうがいいのかな?
      2. baseURLは / とかで大丈夫そう(かな?)
      3. 各種パラメータ等はテーマ依存もあるので、必要に応じて調べていじる

CI設定

CircleCI。こちらも、アカウントの設定等は省略 circleci.com

1. プロジェクト設定

  1. 前に書いた記事の内容で、ルートディレクトリにcircle.yml の設置*2
  2. そのままmasterにpush
  3. CircleCIにわたすように、github tokenを取得しておく
    1. https://github.com/settings/tokens
    2. scopeはrepoでいいかな?もう少し絞っても良いかも。f:id:o0h:20181204162654p:plain
  4. サイドメニューのAdd Projectからレポジトリを選ぶf:id:o0h:20181204161538p:plain
  5. 一旦、そのままstart buildしちゃう
    • 失敗するのでスルー
  6. そのままPJの詳細画面に進むので、そこから設定を開く
    • 右上の⚙アイコン
  7. 環境変数に、先程取得した GITHUB_TOKEN を設定するf:id:o0h:20181204162931p:plain
  8. 合わせて、同じくPJ Settingsのサイドメニューからuser ssh keyを追加しておく
    1. f:id:o0h:20181204165049p:plain
    2. コレをやっておかないと、deployのところ(git push)で The key you are authenticating with has been marked as read only. と怒られる*3
  9. PJ詳細に並んでいるジョブのところから、 rerun workflow を実行

サイト確認

これでサイトがデプロイされるはず・・!なので、実際に pagepage.hogeyamahogehoge.com を開いて動いてるかな〜って見てみましょう。


追記

先のエントリーのcircle.ymlのままだと、「デプロイ時にCNAMEファイルが消されてしまう」という症状があったのに気づいた。
その場合、デプロイ時に「gh-pages用に設定しておいたCustom Domainが消える!」という・・・設定したドメインでのアクセスが不能になります。

  • 必要な要件として「PJ ROOTにCNAMEファイルが設置されている」があり、
    • そうしないと、 hogeyamahogehoge.github.io からのリダイレクトを行えないため
  • ↑のデプロイ前の処理は「一旦、hugoで生成したコンテンツ等をすべて消して、空っぽのファイルに再ビルド」「ビルドされた内容をgh-pagesにpushする」のため。

これを防ぐために、「ビルド後〜デプロイ前にCNAMEファイルを履いてあげれば良い」。

build:stapsの「デプロイ」の直前に、以下のようなコマンドを追加しておく

      - run: echo pagepage.hogeyamahogehoge.com > public/CNAME

これで、ちゃんとCNAMEファイルを生き延びさせてあげることができる。

*1:この画像はブランチ作成後なのでわかりにくいですが・・!

*2:古いかも・・・

*3:http://jackale.hateblo.jp/entry/2018/01/14/000709 の「CircleCIとGithubにSSH用の鍵追加」の記述に助けられました多謝

Docker PHPの各種バージョンの違いについて調べてみる

adventar.org

Day-3です。

カレンダーを見ると、「docker phpの各種バージョンの違いについて調べてみる」という事でネタが設定されていました。
これに従ってまいりましょう。
はて・・・

PHPの公式Dockerイメージ

https://hub.docker.com/_/php/
これのことです。なのだけども、「長すぎて全文じゃないよ」って書いてあるので、READMEを見ましょう

github.com

こちらをいろいろと覗いてみようかな、というのが本日のエントリーです。

  1. stretch/cli
    • 7.3.0RC6-cli-stretch, 7.3-rc-cli-stretch, rc-cli-stretch, 7.3.0RC6-stretch, 7.3-rc-stretch, rc-stretch, 7.3.0RC6-cli, 7.3-rc-cli, rc-cli, 7.3.0RC6, 7.3-rc, rc (7.3-rc/stretch/cli/Dockerfile)
  2. stretch/apache
    • 7.3.0RC6-apache-stretch, 7.3-rc-apache-stretch, rc-apache-stretch, 7.3.0RC6-apache, 7.3-rc-apache, rc-apache (7.3-rc/stretch/apache/Dockerfile)
  3. stretch/fpm
    • 7.3.0RC6-fpm-stretch, 7.3-rc-fpm-stretch, rc-fpm-stretch, 7.3.0RC6-fpm, 7.3-rc-fpm, rc-fpm (7.3-rc/stretch/fpm/Dockerfile)
  4. stretch/zts
    • 7.3.0RC6-zts-stretch, 7.3-rc-zts-stretch, rc-zts-stretch, 7.3.0RC6-zts, 7.3-rc-zts, rc-zts (7.3-rc/stretch/zts/Dockerfile)
  5. alpine3.8/cli
    • 7.3.0RC6-cli-alpine3.8, 7.3-rc-cli-alpine3.8, rc-cli-alpine3.8, 7.3.0RC6-alpine3.8, 7.3-rc-alpine3.8, rc-alpine3.8, 7.3.0RC6-cli-alpine, 7.3-rc-cli-alpine, rc-cli-alpine, 7.3.0RC6-alpine, 7.3-rc-alpine, rc-alpine (7.3-rc/alpine3.8/cli/Dockerfile)
  6. alpine3.8/fpm
    • 7.3.0RC6-fpm-alpine3.8, 7.3-rc-fpm-alpine3.8, rc-fpm-alpine3.8, 7.3.0RC6-fpm-alpine, 7.3-rc-fpm-alpine, rc-fpm-alpine (7.3-rc/alpine3.8/fpm/Dockerfile)
  7. alpine3.8/zts
    • 7.3.0RC6-zts-alpine3.8, 7.3-rc-zts-alpine3.8, rc-zts-alpine3.8, 7.3.0RC6-zts-alpine, 7.3-rc-zts-alpine, rc-zts-alpine (7.3-rc/alpine3.8/zts/Dockerfile)

6種類。
「stretch or alpine」と「clit or apache or fpm or zts」の組み合わせですね。
ただし、alpine/apacheだけない模様*1

OS別

stretch

debian:stretch-slimをベースにしています。 https://hub.docker.com/_/debian/

stretchて?という方は gihyo.jp

alpine

alpine:3.8をベースにしています https://hub.docker.com/_/alpine/

alpine触ったことねぇ・・・というときには

yoshinorin.net

構成別

apache

これはDebianの方にしかない。

php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

fpm

debian php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

alpine php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

cli

無印の php:7.3-rc もCLIとイメージを共同しているので、1番の素となるイメージがこれ!という感じかな・・・

debian php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

alpine php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

zts

ztsって何?は

qiita.com

debian php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

alpine

php/Dockerfile at ee78d7883237754eb68ffb281f5835f851797e05 · docker-library/php · GitHub

どんなPHPですか?

alpine-fpmを見ると、ビルド時にこんな感じのオプションが渡されている

 && ./configure \
        --build="$gnuArch" \
        --with-config-file-path="$PHP_INI_DIR" \
        --with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \
        \
# make sure invalid --configure-flags are fatal errors intead of just warnings
        --enable-option-checking=fatal \
        \
# https://github.com/docker-library/php/issues/439
        --with-mhash \
        \
# --enable-ftp is included here because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236)
        --enable-ftp \
# --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)
        --enable-mbstring \
# --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself)
        --enable-mysqlnd \
# https://wiki.php.net/rfc/argon2_password_hash (7.2+)
        --with-password-argon2 \
# https://wiki.php.net/rfc/libsodium
        --with-sodium=shared \
        \
        --with-curl \
        --with-libedit \
        --with-openssl \
        --with-zlib \

この辺りのことが公式のdocに書いてあるわけで。

README§Image-Variantsのとこ。

php:-cli

「his variant contains the PHP CLI tool with default mods」であり「Note that all variants of php contain the PHP CLI (/usr/local/bin/php).」であると。 「使い捨てコンテナ、もしくは他の何かを作るときのベースイメージとして使ってね〜」ということ

php:-apache

「mod_php/mpm_preforkを利用するApacheのやつ」で「Debianベース」と。

document rootの変え方だったり、その他のconfの変更についてもこの docで言及されておりました

php:-fpm

fomコミコミバージョン。

php:-alpine

「人気のあるAlpine Linux projectをベースにしたもの」で「可能な限りサイズの小さなdocker imageがほしい!」ということであれば、使うべきだ・・!と説明されており。

その他のこと

php.iniとかをいじりたい

$PHP_INI_DIR というい環境変数がセットされているから、それを使えるよ!とのこと。 source

ん〜、カレンダーにネタ登録したときはもう少し面白い掘り下げ方ができると思ったのだけど。
ただコピペしました!みたいなところで終わってしまった・・

*1:ちなみに訳あって私はalpine/apacheを欲しています

将太の寿司を読んだ

あどべんと関係ないカレンダーです。

僕も!!御多分に洩れず!そのビッグウェーブに・・乗った〜〜!! と言うことです。

11月の途中から、「将太の寿司」無料配信を読んでいました。全国編まで。 来る日も来る日も、暇な時、やる気が出ない時、どこかに移動する時、疲れたぜ〜!つってベッドに飛び込んだ後、今日は休みだからグダグダでいいや!といって寝間着のまま寝転がる時、 この月、私のオフタイムは将太の寿司と共にあった気がします。

漫画が無料?ふん!はしたないねぇ!!て気持ちがあって、最初は手を出さなかったんですけど、ツイッターに次々と流れてくるインパクトのあるコマやページは楽しく眺めてました。
で、あまりにも気力が湧いてこないタイミングがあり、何も考えたくなく、とにかく頭を使わせずかつ現実逃避をしたい何か情報をかっくやいたい・・という状態になり。そうだ、あの漫画・・とりあえず、家に帰って着替える間だけでいいや、助けてくれ・・・ それが最初の出会いでした。 序盤の方で、「おお、まじだ、なんでフルネームなんだよ藤原美智子www」ってなって凄く楽しかったです。

そして、少年漫画特有の「元気さ」「真っ直ぐさ」に、すぐに引き込まれました。はぁ〜、信じられないくらい嫌な奴が多いなぁ。。むかつく!て思いながら。でも将太は強い!いいぞいいぞ!やったぜ!!て。どこまでも応援したくなるじゃないですか。その一方で、ライバルもライバルで良いやつで凄いやつで頑張ってるやつで、あいつらも負けて欲しくないじゃないですか。あ、紺屋碧悟だけは負けちまえ。敵役の胸糞加減たるや錚々たるものなんですが、それをやっつけていくシズル感。心の中でガッツポーズしながら読んでいくわけです。

とんでもない量を読んでしまったなー、これの無料公開ってどういうビジネスになるんだろう?というのも気になるところなのですが、純粋に面白く読んで元気をいただきました。

ありがとうございました。

1人でAdvent Calendarをどうにかやっていきたい・・・ @day1

アウトプット足りないな〜と思わされる日々でして、

  1. そもそもの絶対量
  2. これだ!と言えるような、まとまった、あるいはやりきった感のあるパッケージ

のいずれ(か|も)が欲しいなーと。

で、世の中的には年の瀬・クリスマス前です。アドベントカレンダーか〜〜〜と。 2018年は、今までに比べれば少し外での登壇をしたりとか、社内ブログを書いたりとかして、少しずつ「アウトプット」を意識できたのかな?という気持ちがあります。 また、今の自分にとって「CakePHPやPHPっぽい話なら、そこそこまとまった量の話とかできるんじゃね?」って気持ちもあります。とりわけ、普段の業務をしていると、PHPや開発について「何かを考えさせられる」場面も少なくなく、考えるということは何かを生み出そうとしているということですから、本当であれば「普段から何かを生み出せているのでは?」と焦燥するわけです。とりわけ、コードレビューをしたりPRを書いていたりすると「あぁ、自分は、他人と交換するに足る知識や理解があったのだな」などと思います。

ということで、そんなジレジレした気持ちを発散する & 口だけで偉そうにして「実は何もできていない」自分の首を絞めるために、25本連続で書ききっちゃる・・・!と思ってしまったのが、今年の12月です。

どうなることやら・・・・・・

adventar.org

ということで、Day-1「まえがき」でした! 走り切ること優先で内容や分量は後回し・・・!