Generating PHP with Ruby

Ran into an interesting article recently on PHP Web Site Generation using Ruby, over at codegeneration.net (the site runs a PHP section here). The article makes a good starting point for exploring what works and what doesn’t.

Think PHP is underestimated where code generation is concerned, given how easy it is to generate and dynamically execute code e.g.;


< ?php
// Some code
$code = '
echo "Hello World!";
?>
';

// Write code to file
file_put_contents('generated.php',$code); # PHP5 function!

// Include the generated code for execution
include 'generated.php';
?>

Also interesting that Ruby (a dynamic language in more or less the same category as Python and Perl) was used as the generator.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://www.computerbase.de Steffen

    Why not simply use eval() ?

  • enygma

    there is a reason that “eval” is only one letter off of “evil”

  • hlellelid

    For Propel [1], I use PHP templates (to create PHP classes). It’s a bit like looking at magic eye pictures [2], but having an editor that is able to highlight as you switch context is very helpful.

    Certainly PHP is great to gen PHP, but I’d also be interested in finding (or maybe creating) some classes that did this in a more organized way. I can imagine, for example:

    $c = new Class(‘MyClass’);
    $c->addMethod($foo, Method::PRIVATE | Method::STATIC)->addParemeter(‘bar’, ‘int’);

    Haven’t found that yet. Someone (you, Harry, I think) suggested looking at WACT, but it seemed to be rather different.

    -Hans

    [1] http://propel.phpdb.org
    [2] http://www.magiceye.com

  • hlellelid

    After having looked at the Ruby example, that is almost identical to what Propel does using PHP.

    -H

  • http://www.phppatterns.com HarryF

    Why not simply use eval() ?

    Well I’m actually hinting at the next step from here: seperation of “compile time” from “run time”. Extending that example a little more;


    < ?php
    // Only generate once
    if ( !file_exists('generated.php') ) {
    // Some code
    $code = '
    echo "Hello World!";
    ?>
    ';

    // Write code to file
    file_put_contents('generated.php',$code); # PHP5 function!
    }

    // Include the generated code
    include 'generated.php';
    ?>

    The generated code is now only being “compiled” once.

    Considering a more real world example: i18n – many PHP apps today seem to manage replace i18n strings at runtime.

    For example if I have the ini file;


    en="Good Morning"
    de="Guten Morgen"
    fr="Bonjour"

    I might display this to the user like;


    < ?php
    $langs = array('en','de','fr');

    if ( !isset($_GET['lang']) || !in_array($_GET['lang'],$langs) ) {
    $lang = 'en';
    } else {
    $lang = $_GET['lang'];
    }

    $greetings = parse_ini_file('goodmorning.ini');

    echo $greetings[$lang];
    ?>

    Problem with this approach is, when you consider applying it to a complex user interface, where there’ll be many words to translate, there’s alot of work happening at runtime but, in general, the user interface will change rarely. Instead I could do this;


    < ?php
    $langs = array('en','de','fr');

    if ( !isset($_GET['lang']) || !in_array($_GET['lang'],$langs) ) {
    $lang = 'en';
    } else {
    $lang = $_GET['lang'];
    }

    if ( !file_exists($lang.'.php') ) {
    $greetings = parse_ini_file('goodmorning.ini');

    $code = "";

    file_put_contents($lang.'.php',$code);
    }

    include $lang.'.php';
    ?>

    This now compiles three seperate “user interfaces” which the language strings hard coded. The performance cost of parsing the ini file and looking up words in the array is now reduced to a single “compile”, future requests used the compiled code.

    This approach is used by in WACT’s template engine. What is allows WACT to do is have a “compile time” stage where all sorts of OO shenanigans are taking place – the sort of thing that keeps Java coders happy but makes PHP apps run slow normally. The code generated by WACT though is fast and mainly procedural meaning WACTs runtime is very fast.

  • http://www.phppatterns.com HarryF

    Certainly PHP is great to gen PHP, but I’d also be interested in finding (or maybe creating) some classes that did this in a more organized way.

    Perhaps this will turn into something useful one day. Placing PHP in strings inside a PHP script is not fun.

  • hlellelid

    Note that Binarycloud uses Phing (PHP, of course) to create localized sites at build (aka “compile”) time. This seems rather similar to what you describe above.

    I have also used Phing to perform gettext() translations at build-time, that way I can use gettext() for runtime translations during development but have it built statically for deployment. Works quite well.

    -H

  • sike

    i use a very simple codewriter with good results (for me (: ).

    example :


    $codewriter->addComment('Association '.$name,
    '@returns IBusinessAssociation');
    $codewriter->startMethod('&get'.$name, array(), 'public');
    $codewriter->add('if (!$this->'.$assoc['name'].')');
    $codewriter->startBlock();
    $codewriter->add('$this->'.$assoc['name']." = new BusinessObjectAssociation($this, '{$assoc['class']}');");
    $codewriter->endBlock();
    $codewriter->add('return $this->'.$assoc['name'].';');
    $codewriter->endMethod();

    result :


    /**
    * Association Cars
    * @returns IBusinessAssociation
    */
    public function &getCars()
    {
    if (!$this->cars)
    {
    $this->cars = new BusinessObjectAssociation($this, 'Car');
    }
    return $this->cars;
    }

    Sike

  • http://www.lastcraft.com/ lastcraft

    Hi.

    Funny, I was going to inetrantionalise SimpleTest the same way. We have a Propel type system at work, but we use XSLT. XSLT is a great way of getting things up and running easily (although it’s text mode is fiddly); a nice easy introduction to code generation.

    I had a dalliance with Haskell as an XSLT replacement and am having a look at scheme. Both looked very impressive at first site, but I didn’t want to sally my employer with all sorts of strange recruitment requirements.

    Of course using a template engine (which is what normally happens in Ruby) is a technique very familiar to PHP programmers.

    yours, Marcus

  • wre

    How do you make this script? This on that you can post comments on

  • Atomik

    In the J2EE world there’s a lot of tools and methodology to generate code.
    For example, From an UML model made by poseidon and using andromda (or included code generation).
    I think this is a great (and powerfull) method in big projects…
    Keep an eye on this, future is there ;-)