M1ke

Phing Conditional Builds

Back in June at the monthly meeting of PHP North West, Jeremy of Magma Digital spoke about Phing, a build tool for PHP projects, based on Apache Ant and written in PHP. It took me 6 months before I actually committed the time to change all my projects to use Phing for deployment, but it has been a game changing experience. It has allowed me to streamline processes, avoid forgetting to upload updated libraries or new versions of my framework when deploying projects and add in steps such as PHP Lint and JS Minifying to my deployment process.

In the past month I've also finally begun using SASS, a way to build style sheets with variables functions and all sorts of other useful time saving tools, making stylesheets easier to write and maintain, whilst compiling it into compressed CSS that renders in any browser. Add to this the simply Ruby program JS-Preprocessor to compile multiple JavaScript dependencies into a single file and you've got a great tool set for being able to structure your build environment any way you like, whilst having your output in the most efficient form possible, and all automated by Phing.

What I'd like now is to be able to have Phing not only run these pre-processors on my other output, but be able to do the same with my actual PHP code. The theory is fairly simple; at present, like many developers, I construct or use applications to fit specfic purposes. Because these are often used across multiple clients, each may need to have slightly different interface options, data processing etc. There are 3 conventional ways of doing this directly inside PHP. All require including additional files for each client using the application:

  • The PHP function function_exists() can be used in a page of the application as so:

    if ( function_exists( 'do_more_stuff_here ') ) do_more_stuff_here( $parameters);

  • Or the same method but with a fallback:

    // app.php

    do_something_here( $parameters );

    // client_funcs.php

    function do_something_here () { }

    // default_funcs.php

    if ( ! function_exists( 'do_something_here' ) ) function do_something_here() { }

  • If we're doing stuff inside an object we can obviously extend the object:

    // app.php

    $myObject->doStuff();

    // default_class.php

    class regularObject { function doStuff() {

    if (method_exists( $this ,'doMoreStuff' )) $this->doMoreStuff();

    else { }

    }

    // client_class.php

    class clientObject extends regularObject { function doMoreStuff(); }

    Or various other methods

However all of those require some level of overhead in the program, whether its checking for functions or even just requiring files - especially if require_once has to be used. The main reason for the existence of these methods in PHP is for dynamically themeable sites, things like Wordpress where a user can change the entire site theme, plugins and widgets directly from their browser. However in complex applications, the user generally has less control over these base functions and themes, in preference to a more solid interface experience. Plugins and the like are sandboxed into specific areas, whilst the normal pages that make up the interface can be streamlined and as quick as possible.

So what I'd like is to do away with the dynamic features and simply write my PHP like this

$var = standard_function();

// if ($CLIENT== business1)

$var = more_advanced_function( $var );

// else if ($CLIENT == business2)

$var = different_function ( $var );

// END

$var = another_function($var);

Then upon running my Phing build, the lines not relevant to whichever CLIENT is set would be removed as the project is deployed (to staging, live or wherever). This way when constructing the application it becomes very easy to see what happens to different clients' interface/data as the script runs, as well as very easily port certain features between clients or (as has often been the case) make a client specific feature a common part of the system. It would also remove the need to constantly rewrite functions as I add new variables or change the previous flow of code.

This seems somewhat of a weird move in a programming language, but with the sudden freedom that SASS and JSPP have added to mix and customise different builds of my front-end code it would be at least a great experiment to see how portable this method was to back-end code.

Find us on StuRents