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.