📜 ⬆️ ⬇️

Practical use

Now I will talk about how you can associate 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 - directory in which we will add source codes.
2. gen - directory with code generation scripts.
3. result - results directory.

And one file to the root: make.php - it will determine the rules of code generation, run the process of code generation.
')

Process


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

In general, it will look like this:

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

Let's start


First, let's implement just copying data from source to result without processing. I will read the contents of each file and record 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 you 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 that I found on php.net and resulted almost unchanged.

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

Now let's create a filter in the file gen / filter.php :
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 have implemented a certain concept, which is still useless, but has a certain potential.
Let's improve the filter!

Preprocessor


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

I always didn’t like that in order to use the usort function, it was necessary to create a separate function, and the use of create_function was not at all pleasing. Let's implement some limited lambda syntax.

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

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


To handle 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 ! = '' ? "<? php \ n $ additional_code ?>" : '' ). $ input ;
}

And now we will improve the filter function:
function filter ( $ input )
{
$ output = $ input ;
$ output = filter_lambda ( $ output );
return $ output ;
}

Result


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

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

Run make.php and get result / index.php :
<? php
function lambda_0 ( $ value1 , $ value2 ) { return (strlen ( $ value1 )> strlen ( $ value2 ));}
?> <? php

$ numbers = array ( 'much longer' , 'short' , 'longer' );
usort ( $ numbers , 'lambda_0' );

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

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

Conclusion


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

Stride further


I propose to implement the material to implement such interesting tasks as:
1. Try recursively processing php files from the source directory to avoid writing each file to make.php .
2. Try to implement conditional generation (as in C) - analogues #define, #ifdef, #elif, #endif.

Source: https://habr.com/ru/post/24266/


All Articles