Phing: a build system for PHP

Phing (recursive acronym for PHing Is Not GNU make) is a PHP project build system closely modelled on Apache's Ant tool for Java development and implemented in PHP. Phing, like Ant, uses simple XML build files to determine what to do as part of the build process. Why would you need a build system? Certain tasks might need to be performed repeatably during application development (on a large project or a small one). These might include:

  1. collect files from different folders and assemble them in one folder, optionally renaming them in the process
  2. automatically check that the code adheres to a coding standard
  3. extract code from a repository and run unit tests
  4. change configuration files from development settings to production/staging settings
  5. generate project documentation from code
  6. strip comments from production code to make it lighter-weight
  7. automatically search and replace words or phrases in files
A build system, such as Phing, can go a long way towards helping you do this with only a few keystrokes. Phing can call tools/packages, and is also easily extended, using your favourite language - PHP, to handle any reasonably strange requirement you might have.

Installing Phing

We can't use Phing unless we actually install it - let's get that over with. You can install in two ways:

  1. PEAR install
  2. Non-PEAR install
Installing Phing using the PEAR channel is simplicity itself. From the command line enter: > pear channel-discover pear.phing.info
> pear install phing/phing
Use the '-a' flag if you want to install all dependencies (be careful what you wish for): > pear install -a phing/phing Alternatively, you can download a PEAR package, e.g. phing-2.4.2.tgz, and install using PEAR: > pear install phing-2.4.2.tgz

See Getting Phing for more on using the non-PEAR installation.

Running Phing

Phing execution on the command line is very simple - we just need to make sure there is a build file or else Phing will whinge. Just change to the folder where your build file (which should be named build.xml) resides and type: > phing

You can use command line arguments to configure Phing - see Phing Fact Sheet for the arguments available. Some of these arguments are shown below:

Parameter Meaning Usage
-h -help Display the help screenphing -h
-v -version Print version information and exitphing -v
-l -list List all available targets in buildfilephing -l
-D<property>=<value> Set the property to the specified value to be used in the buildfilephing -Ddbpass=demo -Ddbuser=demo
-buildfile <file> Specify an alternate buildfile name. Default is build.xml phing -buildfile "/home/demo/project1/mybuild.xml"

Anatomy of a build file

A valid Phing build file must be a valid XML document with the following basic structure:

  1. A root element called <project>. Required
  2. Several Phing type elements (i.e. <property> , <fileset> , <patternset> etc.). Optional
  3. One or more <target> elements containing built-in or user defined Phing task elements (i.e. <install> , etc). At least one target element must be defined - the default target as specified in the <project> tag.

Here is an example of a very simple build file is which prints out three statements: <?xml version="1.0" encoding="UTF-8"?>

<project name="Foo" default="main">
    <target name="main" description="The default target" >
        <echo msg="Simple project build" />
        <echo>command line parameter (dbuser): ${dbuser}</echo>
        <echo>command line parameter (dbname): ${dbname}</echo>
    </target>
</project>

To execute the build, type this on the command line: > phing -buildfile C:\Websites\phingbuild.xml -Ddbuser=userdemo -Ddbname=demo where C:\Websites\phingbuild.xml is the location of the above build file. The output is something like: Phing simple build

The Phing website gives good examples of an XML build file. Here is a more complex example using filterset, patternset, dependencies, and filterchain:

<?xml version="1.0" encoding="UTF-8"?>

<project name="Foo" default="main">
    <property name="builddir" value="C:\Websites\demo\foo\output" override="true" />

    <!-- Define a fileset -->
    <fileset dir="/home" id="foobar">
        <!-- include all files within /home/foo and its subdirectories -->
        <include name="foo/**" />
        <!-- include all files within /home/bar and its subdirectories with extension php -->
        <include name="bar/**/*.php" />
        <!-- exclude all files within home/foo/tmp and its subdirectories -->
        <exclude name="foo/tmp/**" />
    </fileset>

    <!-- This is the same as:
    <fileset dir="/home" id="foobar"
        include name="foo/**"
        include name="bar/**/*.php"
        exclude name="foo/tmp/**" />
    -->

    <!-- Implementing a filterset using patternset elements -->
    <patternset id="php_code">
        <include name="**/*.php" />
        <include name="**/*.inc" />
    </patternset>

    <patternset id="template_code">
        <exclude name="**/*.tpl.php" />
    </patternset>

    <fileset dir="${sourcedir}">
        <patternset refid="php_code" />
        <patternset refid="template_code" />
    </fileset>

    <target name="main" description="The default target" depends="setsource">
        <echo msg="Build to format code and copy files to destination folder" />
        <echo>command line parameter (dbuser): ${dbuser}</echo>
        <echo>command line parameter (dbname): ${dbname}</echo>

        <copy todir="${builddir}" overwrite="yes">
            <fileset refid="foobar" />
            <!-- Filter chains enable flexible file transformations like rather Unix's pipe operator -->
            <filterchain>
                <stripphpcomments />
                <tabtospaces tablength="2" />
                <replacetokens>
                    <!-- Token is key enclosed by @ characters by default e.g. @dbname@ -->
                    <token key="dbname" value="${dbname}/" />
                    <token key="dbuser" value="${dbuser}" />
                </replacetokens>
            </filterchain>
        </copy>
    </target>

    <target name="setsource" description="set the source folder">
        <property name="sourcedir" value="C:\Websites\demo\foo\source" override="true" />
    </target>

    <target name="anothertarget" description="A target which will not be automatically run">
        <echo>To run this, command line should be something like: phing anothertarget</echo>
    </target>
</project>
Tags: