Do You PHP?    
Search Engine Optimization  php5 powerd  Valid XHTML 1.0!  Valid CSS!  このサイトのはてなブックマーク数 



last updated
2005/08/22

counter hits
since 1999/11/06


Phing - PHP版Ant for PHP4 (binarycloud編)

alertここにある情報はかなり古くなっており、正しくなくなっている可能性があります。掲載しているサンプルコードiなどは、最新のPHPでは動作しない、もしくは、別途設定・調整が必要になるかも知れません。情報を鵜呑みにせず、あなたの手を動かして、あなたの目で確認してください。

Javaの世界ではApache Antという有名なビルドツールがあります。C言語に対するmakeのような存在で、コンパイルや各種アーカイブ化、APIドキュメントの作成、テストの実行などのタスクを自動化していました。今でもバッチやEclipseなどのIDEから実行したりして使われています。また、Makefileに相当する定義ファイル(どういうタスクを行うか)はXMLで定義します。

一方PHPは?というと、スクリプト言語ですから前もってコンパイルすることはありませんが、他の言語と同様ファイルのコピー・移動、アーカイブ化やテストの実行など必要となるタスクはあるもので、従ってそのタスクを自動化したいという要望(要求)もあるかと思います。

やはりAntが有名なのでそれに似たツールがあれば。。。ということで探してみるとあるもんです(^-^;

Phingは元々PHP用フレームワークbinarycloudの一部として開発されていましたが、現行バージョン(2005/08/09現在ver.2.1.0)は独立してPHP5専用になっています。

機能的にもAntとかなり似ていて、定義ファイルもAntと同じbuild.xmlで定義し、内容もほぼ同様です。また、独自タスクをPHPのクラスで定義することができます。

今回はPHP4を対象としたbinarycloudを使ってみました。

インストール

まずはbinarycloudのReleasesのページからアーカイブをダウンロードします。2005/08/09現在の最新バージョンは3.0.0RC4ですがRC4からPhingが含まれなくなったようなので一つ前のRC3をダウンロードします(恐らく、これがPHP4用Phingの最後のバージョンです)。

ダウンロード後、適当なディレクトリにアーカイブを展開します。

アーカイブを展開後の作業は、基本的にUnixInstallInstructionsのページ(このページはobsoleteになっています)にある通りですが、実際に行った手順を書いておきます。

アーカイブ展開後、環境変数を設定します。PHP_COMMANDに指定するphpコマンドへのパスは適宜変更してください。また、今後Phingを使い続けるのであれば、$HOME/.bash_profileなどに追記しておくと良いと思います。

●環境変数の設定
$ export BCHOME=[binarycloudのインストールパス]/binarycloud-3-0-0_rc3/r3
$ export PHING_HOME=$BCHOME/phing
$ export PHP_COMMAND="[phpコマンドへのパス]/php"
$ export PHP_CLASSPATH=.:$PHING_HOME/classes:$BCHOME
$ export PATH=${PATH}:$PHING_HOME/bin
$ 

環境変数の設定後、Phingの設定を行います。

●Phingの設定
$ cd $PHING_HOME/bin
$ chmod u+x phing.sh
$ ln -s phing.sh phing
$ 

設定が終わったら、正しくPATHが通っているか確認しておきます。

●PATHの確認
$ which phing
[binarycloudのインストールパス]/binarycloud-3-0-0_rc3/r3/phing/bin/phing
$ 

Phingの設定後、インストールのテストを行うのですが、mysqlが必要とのことで今回は割愛しましたm(_"_)m

簡単な利用例

Phingのドキュメントは、展開したアーカイブ下のr3/phing/docs/phing_guide/ディレクトリにあります。index.htmlをブラウザで開くと各種ドキュメントを参照することができます(英語ですが)。

ここでは手始めに、左メニューの[Getting Started]-[Writing A Simple Buildfile]にあるXML形式の設定ファイル(build.xml)を試してみることにします。

まずは、実行環境を整備します。適当なディレクトリ下にディレクトリと仮のソースファイルを作成します。ここではベースとなるディレクトリを「sample」としています。

●実行環境の整備
$ cd sample
$ mkdir src
$ echo "<?php echo 'File.php'; ?>" > src/File.php
$ echo "<?php echo 'File2.php'; ?>" > src/File2.php
$
  

次に、build.xmlを作成します。基本的な書き方は掲載されているXMLの通り、

  • root要素はproject要素
  • target要素でタスクをグループ化し、大きなタスクを作る(実行時に渡すtargetパラメータになる)
  • ディレクトリの作成やコピー、tarによるアーカイブ化など基本となるタスクは用意されており、それぞれタグ形式で記述する

となります。

で、このbuild.xml、整形式でない上存在しないタスクなどあり、このままでは動作しません。。。(T~_T)

ということで以下のように変更し、sample/build.xmlとして保存します。

●build.xml
<?xml version="1.0" encoding="utf-8"?>
<!--
|| プロジェクト FooBarの定義
||
|| デフォルトのターゲットは "dist"
||
|| @project FooBar
|| @default dist
|| @basedir "."
-->
<project name="FooBar" default="dist" basedir=".">

  <!--
  || ディレクトリの定義
  -->
  <property name="BUILD_DIR" value="./build" />
  <property name="DOC_DIR" value="./apidoc" />

  <!--
  || buildディレクトリを作成する
  ||
  || @target prepare
  -->
  <target name="prepare">
    <echo msg="Preparing build..." />
    <mkdir dir="${BUILD_DIR}" />
  </target>

  <!--
  || ビルドする
  || 実際にはsrcのFile2?.phpをbuildディレクトリにコピーするだけ。
  || 実行前にprepareターゲットを実行する。
  ||
  || @target build
  || @depends prepare
  -->
  <target name="build" depends="prepare">
    <echo msg="Building..." />
    <copy file="./src/File.php" tofile="./build/File.php" />
    <copy file="./src/File2.php" tofile="./build/File2.php" />
  </target>

  <!--
  || ビルドしアーカイブ furbee.tar.gz を作成する
  || 実行前にbuildターゲットを実行する。
  ||
  || @target dist
  || @depends build
  -->
  <target name="dist" depends="build">
    <echo msg="Creating archive..." />
    <tar outfile="furbee.tar.gz" usegzip="true">
      <fileset dir="./build">
        <include name="**/**" />
      </fileset>
    </tar>
  </target>

  <!--
  || ビルド環境をクリアする
  ||
  || @target clean
  -->
  <target name="clean">
    <echo msg="Cleaning up..." />
    <delete file="./build" />
  </target>
</project>

build.xmlを作成したら、いよいよphingコマンドを実行します。

●phingの実行
$ phing
Buildfile: build.xml

Target: prepare
     [echo] Preparing build...
    [mkdir] Created dir: /path/to/sample/./build

Target: build
     [echo] Building...
     [copy] Copying 1 file to /path/to/sample/./build
     [copy] Copying 1 file to /path/to/sample/./build

Target: dist
     [echo] Creating archive...

BUILD SUCCESSFUL

Total time: 0.2050 seconds
build finished at  Sun Aug 21 17:15:17 JST 2005
$

実行後、sampleディレクトリにfurbee.tar.gzが作成されていることを確認してみてください。どうでしょうか?しかし、ホントにAntと同じですね。。。

今回はパラメータなしで実行しましたが、本来は

●phingの実行
$ phing -help
phing [options] [target [target2 [target3] ...]]
Options:
  -h -help               print this message
  -l -list               list available targets in this project
  -v -version            print the version information and exit
  -q -quiet              be extra quiet
  -verbose               be extra verbose
  -debug                 print debugging information
  -logfile <file>        use given file for log
  -logger <classname>    the class which is to perform logging
  -f -buildfile <file>   use given buildfile
  -D<property>=<value>   use value for given property
  -find <file>           search for buildfile towards the root of the
                         filesystem and use it

Report bugs to <dev@lists.binarycloud.com>
build finished at  Sun Aug 21 17:26:28 JST 2005
$

のようにbuild.xmlで設定したターゲットをパラメータとして指定します。パラメータがない場合、project要素のdefault属性で指定されたターゲットが実行されますので、今回の場合、

●phingの実行
$ phing dist

と等価になります。

使い方はこれだけです。あとは用途に応じてタスクを組み替えてターゲットを作成する事になります。用意されているタスクについては、左メニューの[Appendix B: System Tasks]や[Appendix C: Core Types]を見るとすぐに分かると思います。

また、タスクとは別の重要な要素としてfilesetがあります。使い方はAntと同じですので、慣れるとかなり強力な要素です。上記のサンプルで使用しているその他タスクについては、ドキュメントを参照してください。

ドキュメントにないタスク

ドキュメントのAppendixにタスク一覧がありますが、$PHING_HOME/tasks以下のディレクトリを見てみるとドキュメントに記載されていないタスクも存在します。中でもphpDocumentorを使ってAPIドキュメントを作成するタスクPHPDocuTaskは使えそうです(DocではなくDocuです)。

このタスクを使用するには、

  • タスクtaskdefを使用してタスクを登録する
  • $PHING_HOME/tasks/defaults.propertiesにタスクを追記する

のいずれかの作業が必要になります。phpDocumentor自身については、binarycloudに同梱されていますので、別途インストールする必要はありません。

前者の場合、build.xmlを以下のように修正します。

●build.xmlの抜粋
<?xml version="1.0" encoding="utf-8"?>
                      :
<project name="FooBar" default="dist" basedir=".">
                      :
  <!--
  || phpDocumentorを使ってAPIドキュメントを作成する
  ||
  || @target apidoc
  -->
  <taskdef name="phpdoc" classname="phing.tasks.ext.PHPDocuTask" />
  <target name="apidoc" depends="build">
    <echo msg="Building API documents..." />
    <mkdir dir="${DOC_DIR}" />
    <phpdoc source="${BUILD_DIR}"
            target="${DOC_DIR}"
            package="FooBar"
            title="Phing Test"
            output="HTML:Smarty:PHP"
            clean="true" />
  </target>
</project>

後者の場合、build.xmlを以下のように修正し、

●build.xmlの抜粋
<?xml version="1.0" encoding="utf-8"?>
                      :
<project name="FooBar" default="dist" basedir=".">
                      :
  <!--
  || phpDocumentorを使ってAPIドキュメントを作成する
  ||
  || @target apidoc
  -->
  <target name="apidoc" depends="build">
    <echo msg="Building API documents..." />
    <mkdir dir="${DOC_DIR}" />
    <phpdoc source="${BUILD_DIR}"
            target="${DOC_DIR}"
            package="FooBar"
            title="Phing Test"
            output="HTML:Smarty:PHP"
            clean="true" />
  </target>
</project>

defaults.propertiesに以下の行を追加します。

●$PHING_HOME/tasks/defaults.properties
phpdoc=phing.tasks.ext.PHPDocuTask

いずれの方法を採るかはお好みでどうぞ。なお、実行結果は以下のような感じになります。

●APIドキュメントの作成
$ phing apidoc
Buildfile: build.xml

Target: prepare
     [echo] Preparing build...
    [mkdir] Created dir: /path/to/sample/./build

Target: build
     [echo] Building...
     [copy] Copying 1 file to /path/to/sample/./build
     [copy] Copying 1 file to /path/to/sample/./build

Target: apidoc
     [echo] Building API documents...
    [mkdir] Created dir: /path/to/sample/./apidoc
   [phpdoc] Cleaning target directory first
   [delete] Deleting directory /path/to/sample/./apidoc
Parsing configuration file phpDocumentor.ini...
done
using experimental tokenizer Parser

BUILD SUCCESSFUL

Total time: 0.5307 seconds
build finished at  Sun Aug 21 23:07:47 JST 2005
$

独自のタスクを作る

ドキュメントの[Extending Phing]-[Writing Tasks]にもあるように、独自のタスクを作成することもできます。当然、PHPで記述します。サンプルはドキュメントにもありますが、AntのSymlinkタスクを真似てざっと作ってみました。以下のファイルを$PHING_HOME/tasks/example/SymLinkTask.phpとして保存します。なお、「example」ディレクトリは任意で、systemディレクトリやextディレクトリにも配置可能です。

●SymLinkTask.php
  
<?php
import('phing.Task');
import('phing.system.io.FileSystem');

/**
 * シンボリックリンクを作成するタスクの例
 *
 * @create 2005/08/22
 * @author SHIMOOKA Hideyuki <shimooka at doyouphp dot jp>
 */
class SymLinkTask extends Task
{
    /**
     * Log出力されるタスク名
     */
    var $__taskname = "symlink";

    var $link_ = null;
    var $resource_ = null;

    /**
     * link属性のアクセサ
     *
     * @param string リンク名
     * @return boolean true
     */
    function setLink($link) {
        $this->link_ = $link;
        return true;
    }

    /**
     * resource属性のアクセサ
     *
     * @param string リンク元のパス
     * @return boolean true
     */
    function setResource($resource) {
        $this->resource_ = $resource;
        return true;
    }

    /**
     * initメソッド
     * 何もしなくても必ず実装する必要がある
     */
    function init() {
        // 何もしない
    }

    /**
     * このタスクのエントリポイント
     *
     * シンボリックリンクを再作成する
     */
    function main() {
        $fs =& FileSystem::getFileSystem();
        $fs->Unlink($this->link_);
        $fs->Symlink($this->resource_, $this->link_);
        return true;
    }
}
?>

PHPソースの方はかなりJavaを意識しているようで、import関数や今回は使用していませんがthrow/catch関数などが用意されています。実装のポイントとしては以下のものがあります。

  • 必要なパッケージをimport関数を使用してロードする
  • クラス名はタスク名+「Task」
  • 最低限Taskクラスを継承する
  • XML属性に対するセッタメソッドを用意する
  • initメソッドを用意する
  • mainメソッドに処理内容を記述する

一方のbuild.xmlですが、先ほどのPHPDocuTaskと同様の書き方になります。以下はtaskdef要素を使用した場合です。

●build.xmlの抜粋
<?xml version="1.0" encoding="utf-8"?>
                      :
<project name="FooBar" default="dist" basedir=".">
                      :
  <!--
  || シンボリックリンクを作成する
  ||
  || @target link
  -->
  <taskdef name="symlink" classname="phing.tasks.example.SymLinkTask" />
  <target name="link">
    <symlink resource="build" link="build.link" />
  </target>
</project>

classname属性の値はタスクのソースファイルを配置したディレクトリと連動しているため、もし「system」ディレクトリに配置した場合は

●classname属性
  <taskdef name="symlink" classname="phing.tasks.system.SymLinkTask" />

となります。実行結果は以下のようになります。

●APIドキュメントの作成
$ ls
apidoc/  build/  build.xml*  src/  test/
$
$ phing link
Buildfile: build.xml
FileSystem::Symlink() SUCCESS. build to build.link.

BUILD SUCCESSFUL

Total time: 0.1560 seconds
build finished at  Mon Aug 22 01:06:08 JST 2005
$
$ ls
apidoc/  build/  build.link@  build.xml*  src/  test/
$ ls -l build.link
lrwxrwxrwx    1 shimooka shimooka        5 Aug 22 01:13 build.link -> build/
$

まとめ

実はPhing自体はかなり前から知っていたのですが、「スクリプト言語のPHPになぜAnt?」ということで使っていませんでした。今思うと「ちょっともったいなかったなぁ」という感じです。使ってみた感じはほとんどAntと同じなので違和感はありませんでした。ただ、Antと比べタスクの数があまりないので、scpやrsync、cvsなどのリモートサーバとのやりとりはexecタスクを多用する感じになるでしょうか?

また、PHP5専用のPhingも2005/07にバージョン2.1.0がリリースされましたので、近いうちにやってみようかと思います。



About This Site |  Privacy Policy |  Contact
Copyright © 1999 - 2005 by Hideyuki SHIMOOKA all rights reserved.