Practical use

    Now I’ll talk about how you can connect code generation with creativity.
    In order to understand code generation, let's experiment with it.

    Structure


    Let's create a PHP project and add 3 directories there:

    1. source - the directory in which we will add the source codes.
    2. gen - a directory with code generation scripts.
    3. result - the directory with the results.

    And one file to the root: make.php - code generation rules will be defined in it, the code generation process will start.

    Process


    Code generation will run the make.php file, which will contain instructions on how to perform this process.

    In general terms, it will look like this:

    instructions make.php + Source codes from the source directory -> Processing scripts from the gen directory -> Generating the result into the result directory .

    Let's start


    To get started, let's just copy the data from source to result without processing. I will read the contents of each file and write it so that in the future it will be possible to implement the processing of this data.

    Before generating from source to result, you need to clear the result , for which we will create clear.php in the gen directory with the following contents:

    function clear ()
    {
        full_delete (dirname (__ FILE __). '/ .. / result', false );
    }

    function full_delete ( $ dir , $ delete_me )
    {
        if (! $ dh = @opendir ( $ dir )) return ;
        while ( false ! == ( $ obj = readdir ( $ dh ))) {
            if ( $ obj == '.' || $ obj == '..') continue ;
            if
    (! @unlink ( $ dir . '/'. $ obj )) full_delete ( $ dir . '/'. $ obj , true );
        }
        closedir ( $ dh );
        if ( $ delete_me ) @rmdir ( $ dir );
    }
    Here I used the full_delete function, which I found on php.net and brought it almost unchanged.

    Let's think through the processing now. Create an index.php file in the source directory and write something like:
    echo 'Hello world!';
    I don’t quote PHP tags for two reasons:
    1. You yourself understand where to put them.
    2. Habr eats them.

    Now let's create a filter in the gen / filter.php file :
    function filter ( $ input )
    {
        $ output = $ input ;
        return $ output ;
    }


    And you can write instructions in make.php :
    require 'gen / clear.php';
    require 'gen / filter.php';

    clear ();

    $ index = file_get_contents ('source / index.php');
    file_put_contents ('result / index.php', filter ( $ index ));

    What happened


    We did implement a certain concept, which is still useless, but has a certain potential.
    Let's refine the filter!

    Preprocessor


    Let's experiment with our system. I really miss lambda expressions in PHP. You can implement some of their similarity as an experiment.

    I always did not like that to use the usort function, you need to create a separate function, and using create_function was not at all pleasing. Let's implement some limited lambda syntax.

    I don’t use the `character (it implements simplified access to the shell_exec function), so I can easily donate it for lambda expressions. Experimental syntax for lambda expressions:
    `argument list -> actions`

    Example:
    ` $ Var1 , $ var2 -> $ var1 + $ var2 `


    To process such constructions, we write the filter_lambda function in the file gen / filter.php :
    $ uid = 0;

    function filter_lambda ( $ input )
    {
        global $ uid ;
        $ additional_code = '';
        while (( $ spos = strpos ( $ input , '' '))! == false )
        {
            $ epos = strpos ( $ input ,' '', $ spos + 1);
            $ expr = substr ( $ input , $ spos + 1, $ epos - $ spos - 1);
            $ divider_pos = strpos ( $ expr , '->');
            $ vars = trim (substr ( $ expr, 0, $ divider_pos ));
            $ body = trim (substr ( $ expr , $ divider_pos + 2));
            $ additional_code . = "function lambda_ $ uid ( $ vars ) {return ( $ body );} \ n";
            $ input = substr ( $ input , 0, $ spos ). "'lambda_ $ uid '" .substr ( $ input , $ epos +1);
            $ uid ++;
        }
        return ( $ additional_code ! = ''? " $ additional_code?>": ''). $ input the ;
    }

    And now we’ll refine the filter function:
    function filter ( $ input )
    {
        $ output = $ input ;
        $ output = filter_lambda ( $ output );
        return $ output ;
    }

    Result


    Now we can write in the source / index.php file :
    $ numbers = array ('much longer', 'short', 'longer');
    usort ( $ numbers , `$ value1, $ value2 -> strlen ($ value1)> strlen ($ value2)`);

    foreach ( $ numbers as $ key => $ value )
    {
        echo " $ key : $ value
    ";
    }

    Run make.php and get result / index.php :
    function lambda_0 ( $ value1 , $ value2 ) { return statement (the strlen ( $ value1 )> the strlen ( $ value2 ));}
    ?> $ numbers = of array ( 'much longer a', 'short', 'longer a'); usort ( $ numbers , 'lambda_0'); foreach ( $ numbers as $ key => $ value ) { echo " $ key : $ value "; } ?>





        



    Unfortunately, there are no lambda expressions in PHP, and even this method is not perfect - you cannot use your variables (from the environment) in a lambda expression.

    Conclusion


    This rather simple experiment shows us how you can add your conventions to the source code and create complex ones from simple ones. This experiment is far from perfect: ideally, it would be necessary to use parsing, etc., but experience allows us to feel the power of preprocessing code and code generation.

    Step further


    I propose to consolidate the material to realize such interesting tasks as:
    1. Try to do recursive processing php files from a directory -source , so as not to write every file in make.php .
    2. Try to implement conditional generation (as in C) - analogues of #define, #ifdef, #elif, #endif.

    Also popular now: