Question

I have this function that fetches dynamic db data and supposed to convert constants and variables from the db result string to their matching values. The function works perfectly fine if I just make the code run as a "straight" code instead of making it a function, but I want to make it more universal so I tried making it a function and when it's a function - it converts only the constant to its' value, but not the variable. This is the straight code which works fine.

$text = 'The sky is $color and<br> the grass is GRASS_COLOR'; // Example value taken from the database

$color = 'blue';
define('GRASS_COLOR', 'green');

// collect all defined variables and filter them to get only variables of string and numeric type
$values = array_filter( get_defined_vars(), function( $item ) {
    return is_string($item) || is_numeric($item);
});

// append the dollar sign to keys
$keys = array_map( function( $item ) { 
    return '$'.$item;
}, array_keys( $values ) );

// create the final array by comining the arrays $keys and $values
$vars = array_combine( $keys, array_values( $values ) );

// relpace names of the variables with values
$text = str_replace( array_keys( $vars ), array_values( $vars ), $text );

// collect all constants and replace user defined constants with values
$constants = get_defined_constants( true );
$text = str_replace( array_keys( $constants['user'] ), array_values( $constants['user'] ), $text );

// we are done
echo $text;

How can I convert it to a universal function that will access outside unknown variables and output the correct result, like in this case:

The sky is blue and
the grass is green

EDIT This is the function:

$foo = 'The sky is $color and</br> the grass is GRASS_COLOR'; // place here value from database

$color = 'blue';
define('GRASS_COLOR', 'green');

function db_fetch_vars_constants($text) {

// collect all defined variables and filter them to get only variables of string and numeric type
$values = array_filter( get_defined_vars(), function( $item ) {
    return is_string($item) || is_numeric($item);
});

// append the dollar sign to keys
$keys = array_map( function( $item ) { 
    return '$'.$item;
}, array_keys( $values ) );

// create the final array by comining the arrays $keys and $values
$vars = array_combine( $keys, array_values( $values ) );

// relpace names of the variables with values
$text = str_replace( array_keys( $vars ), array_values( $vars ), $text );

// collect all constants and replace user defined constants with values
$constants = get_defined_constants( true );
$text = str_replace( array_keys( $constants['user'] ), array_values( $constants['user'] ), $text );

// we are done
echo $text;
}

db_fetch_vars_constants($foo);

EDIT #2 As @deceze suggested, I have changed the function to the following and it works.

$color = 'blue';
define('GRASS_COLOR', 'green');
$foo = 'The sky is $color and</br> the grass is GRASS_COLOR'; // place here value from database

function db_fetch_vars_constants($text) {

// collect all defined variables and filter them to get only variables of string and numeric type
//$values = array_filter( get_defined_vars(), function( $item ) {
$values = array_filter( $GLOBALS, function( $item ) {
    return is_string($item) || is_numeric($item);
});

// append the dollar sign to keys
$keys = array_map( function( $item ) { 
    return '$'.$item;
}, array_keys( $values ) );

// create the final array by comining the arrays $keys and $values
$vars = array_combine( $keys, array_values( $values ) );

// relpace names of the variables with values
$text = str_replace( array_keys( $vars ), array_values( $vars ), $text );

// collect all constants and replace user defined constants with values
$constants = get_defined_constants( true );
$text = str_replace( array_keys( $constants['user'] ), array_values( $constants['user'] ), $text );

// we are done
echo $text;
}

db_fetch_vars_constants($foo);
Was it helpful?

Solution

This sounds like a bad approach. Variable scope exists to separate and isolate parts of the application against each other to prevent it from stomping all over itself. You're essentially asking for a flat variable namespace, and that any variable anywhere in your application could be interpolated into template text. You shouldn't do that.

Instead, make an array of all the possible values which are destined to be used for end-user presentation and pass them as array to your text-interpolation function. Don't let the function grab all possible variables, but explicitly pass the values it is supposed to work with to it. That's a much saner application structure.

Just imagine you having a variable $password which holds your secret database connection credentials or other sensitive information, and a string 'Your password is $password'. You're now inadvertently outputting your secrets for anyone to see. Oops.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top