PHP Extension docker開発環境の構築

# 概要
PHP Extensionとして追加したいモジュールがあったので、まずはdockerを利用し、その開発環境を構築しました。

## dockerの設定
[以前、Docker Toolboxを利用し、Webアプリのローカル開発環境(Apach+PHP, MySQL)を構築](http://qiita.com/takeyoshi-k/items/ea043c6325ea2c030e5e)しました。
こちらの設定を変更し、環境構築していきます。

### docker関連ファイルの編集
- フォルダ・ファイル構成

```
./docker/
|-- docker-compose.yml
|-- web
|   |-- Dockerfile
|-- html
    |-- index.php
```

docker-compose.ymlは、以下のように編集します。
dbは必要ないので設定から削除します。

```
$ vim docker-compose.yml
version: '2'
services:
  web:
    build: ./web
    ports:
      - '80:80'
    volumes:
      - ./html:/var/www/html
```

web/Dcokerfileは、以下のように編集します。
Webサーバ（apache）の設定は、ブラウザでphpinfoの設定を確認したり、動作確認・デバッグなどに利用したいため残しています。

```
$ vim web/Dcokerfile
FROM php:5.6-apache

RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "vim"]
RUN ["apt-get", "install", "-y", "git"]
COPY ./php.ini /usr/local/etc/php/php.ini
```

以下のPHP設定ファイル（php.ini）を用意し、ゲスト環境にコピーします。
`enable_dl = On`することで、拡張ライブラリ（dllやsoファイル）の読み込みを有効にします。デフォルトではOffでPHP Extensionで開発したライブラリを読み込むことができないため有効にします。（その他の設定はオプション）

```
$ vim web/php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"

enable_dl = On
```

ブラウザでのPHP設定情報確認のためindex.phpはphpinfo()を呼んでいます。

```
$ vim html/index.php
<?php phpinfo();
```

設定変更後、リビルドしコンテナを起動します。

```
$ docker-compose build
.....
Successfully built 033265de3a17

$ docker-compose up -d
Creating network "docker_default" with the default driver
Creating docker_web_1
```


## PHPのソースダウンロード
PHPのソースコードをローカルにダウンロードするため[公式PHPのミラーリポジトリ](https://github.com/php/php-src)をクローンします。

```
$ docker-compose run web bash
$ git clone https://github.com/php/php-src.git
```

webコンテナのPHPバージョンが5.6なので、同一バージョンのソースをチェックアウトします。

```
$ php -v
PHP 5.6.30 (cli) (built: Mar 21 2017 23:01:57)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies

$ cd php-src/
$ git checkout -b PHP-5.6.30 origin/PHP-5.6.30
```


## PHP Extensionスケルトンプロジェクトの作成
PHP Extensionのスケルトンプロジェクトを作成します。
作成にあたり、以下のサイトを参考にさせていただきました。
[DSAS開発者の部屋](http://dsas.blog.klab.org/archives/50777398.html)
[Born Too Late](http://blog.yuyat.jp/archives/1028)

```
$ cd ext/
$ ./ext_skel --extname=helloworld
Creating directory helloworld
Creating basic files: config.m4 config.w32 .gitignore helloworld.c php_helloworld.h CREDITS EXPERIMENTAL tests/001.phpt helloworld.php [done].
```

以下のようにビルドに必要な設定（16-18行目をコメントイン）を反映します。

```
$ cd helloworld/
$ vim config.m4
16 PHP_ARG_ENABLE(helloworld, whether to enable helloworld support,
17 Make sure that the comment is aligned:
18 [  --enable-helloworld           Enable helloworld support])
```

以下のようにビルドします。

```
$ phpize
Configuring for:
PHP Api Version:         20131106
Zend Module Api No:      20131226
Zend Extension Api No:   220131226

$ ./configure
.....
creating libtool
appending configuration tag "CXX" to libtool
configure: creating ./config.status
config.status: creating config.h

$ make
.....
Build complete.
Don't forget to run 'make test'.
```

正常にビルドが完了すると、以下のモジュールができます。

```
$ ls modules/
helloworld.la  helloworld.so
```

動作確認の前に、拡張モジュールのディレクトリを確認し、作成したモジュールをそのディレクトリにコピーします。
ブラウザでphpinfoとして出力されたextension_dirを確認しても大丈夫です。

```
$ php -i | grep extension_dir
extension_dir => /usr/local/lib/php/extensions/no-debug-non-zts-20131226 => /usr/local/lib/php/extensions/no-debug-non-zts-20131226

$ cp modules/helloworld.so /usr/local/lib/php/extensions/no-debug-non-zts-20131226/helloworld.so
```

最後に動作確認します。`helloworld.php`はビルド時に自動で生成されたファイルです。

```
$ php helloworld.php
Functions available in the test extension:
confirm_helloworld_compiled

Congratulations! You have successfully modified ext/helloworld/config.m4. Module helloworld is now compiled into PHP.
```

また、以下のようにtest.phpを作成し、動作確認もしてみます。`confirm_helloworld_compiled`は自動で生成された確認用関数です。

```
$ vim test.php
<?php
  dl('helloworld.so');
  $str = confirm_helloworld_compiled("helloworld");
  echo "$str\n";
?>

$ php test.php
Congratulations! You have successfully modified ext/helloworld/config.m4. Module test is now compiled into PHP.
```

以上で、PHP Extensionのdocker開発環境が構築できました。
コンテナを再起動すると、extension_dirにコピーしたモジュールが消えてしまうので、docker-compose.ymlを以下のように設定し、リビルドしておきましょう。

```
$ vim docker-compose.yml
version: '2'
services:
  web:
    build: ./web
    ports:
      - '80:80'
    volumes:
      - ./html:/var/www/html
      - ./html/php-src/ext/helloworld/modules/helloworld.so:/usr/local/lib/php/extensions/no-debug-non-zts-20131226/helloworld.so
```

# 参考
http://www.php.net/git.php