0

The other day I was given this huge set of arrays and told to make a HTML page with a bunch or selects/radio buttons so I wrote some simple functions to simplify things.

This is my function to generate very large HTML selects.

function genSelect($name) {
    $selectReturn = '<select name="'.$name.'">';
        foreach(${$name} as $value=>$text){
            $selectReturn .= '<option value="'.$value.'"';
            if($evalThis->loaded_settings[$name]['value']==$value)
                $selectReturn .= ' SELECTED ';
            $selectReturn .= '>'.$text.'</option>';
        }
    $selectReturn .= '</select>';
return $selectReturn;
}

This doesn't seem to work because ${$name} simply does not call anything / work like I expect it too. I already have a work around where I just pass the array though the function call but its been bugging me what I was doing wrong with the variable variables in this code.

Edit: To give some context this is being loaded in a joomla view to build the giant UI for entering in settings. This function is in a lib file and is loaded with a require_once along side another file containing all the arrays I use. The database holds only the current values of these settings and the arrays contain all the possible options for the various selects/radio/dropdown menus and are centralized in a separate file for language/translation reasons.

Clarifying some questions people asked, $name simply contains the name of the array used and also the name of the HTML select/radio/checkbox input. $evalThis is a array containing the values the database currently has.

Spunkie
  • 137
  • 6

2 Answers2

1

it seems an array with name stored in $name is defined in global context, not in this function.

$somearr = array('x', 'y');
function genSelect($name) {
    $selectReturn = '<select name="'.$name.'">';

    foreach(${$name} as $value=>$text){
        $selectReturn .= '<option value="'.$value.'"';
        if($evalThis->loaded_settings[$name]['value']==$value)
            $selectReturn .= ' SELECTED ';
        $selectReturn .= '>'.$text.'</option>';
    }

    $selectReturn .= '</select>';
    return $selectReturn;
}
echo genSelect('somearr'); //doesnt work, somearr is global


$somearr = array('x', 'y');
function genSelect($name) {
    global $somearr;
    $selectReturn = '<select name="'.$name.'">';

    foreach(${$name} as $value=>$text){
        $selectReturn .= '<option value="'.$value.'"';
        if($evalThis->loaded_settings[$name]['value']==$value)
            $selectReturn .= ' SELECTED ';
        $selectReturn .= '>'.$text.'</option>';
    }

    $selectReturn .= '</select>';
    return $selectReturn;
}
echo genSelect('somearr'); //works, note 'global $somearr' line at the beginning of genSelect

Generally it is quite bad design to use variable names of functions/arrays when it is not necessary/at least justified. If I were you I would just rewrite the method to

function genSelect($array, $name) { ... }

echo genSelect($someArr, 'someArr');

It may seem like duplication of typying, but it's better to not have your methods depend on global scope. Btw, your $evalThis var is also out of function scope.

Mariusz Sakowski
  • 3,232
  • 14
  • 21
  • 2
    Use the [PHP DOM](http://php.net/manual/en/book.dom.php) for creating HTML with PHP! – noob Jan 03 '12 at 22:38
  • Forgive me if this is a stupid question I'm still new to PHP. Would that mean `${$name}` would work if the `require_once` that loaded the file containing all the arrays was moved inside the function from its current location, directly above the `require_once` that loads the file containing this function? – Spunkie Jan 04 '12 at 02:07
  • I'm not sure which code you are referring to, but if you do a `require_once` from within a function, then anything that has 'global' scope in the included file will be in function scope. It is not recommended though to include from within a function; instead include functions and call them when needed. Also note that `require_once` (or `include_once`) will not do anything if the same file has already been included before, even in a different scope. – The Nail Jan 04 '12 at 09:55
1

The problem is that ${$name} is not defined inside the function's scope. You would need to either reference the global variable like this:

$GLOBALS[$name]  // bad

Or add this at the top of the function:

global ${$name};  // worse

WARNING: This is horrible. Don't do it :-) I advise simply passing the array like you mentioned before.

FtDRbwLXw6
  • 27,774
  • 13
  • 70
  • 107
  • First answer who gets it right (at least about the global part). haven't verified your answer though :) – PeeHaa Jan 03 '12 at 22:36
  • 2
    If using globals is the chosen solution (one would hope not), you could also use `$GLOBALS[$name]` directly instead of defining `${$name}` global first. – Bart Jan 03 '12 at 23:30
  • @Bart: You're absolutely correct. I'll modify my answer to reflect this. Thank you. – FtDRbwLXw6 Jan 04 '12 at 13:54