Why does this PHP function call work only once? - php

I've wrote a simple array, and I would use it to print an html list option set, with a selected element.
My problem starts if I try to print multiple lists in my page, because only the first list is printed correctly, why?
<?php
$units = array (
'0' => 'Units',
'kJ' => 'Kilojoule: kJ',
'g' => 'Grams: g',
'mg' => 'Milligrams: mg',
'mcg' => 'Micrograms: mcg, µg');
function unit_select_option ($attributes, $code = "") {
global $units;
$html = "<select title=\"Kilojoule: kJ;
Grammi: g;
Milligrammi: mg;
Microgrammi: mcg, µg;\" $attributes>\r";
while (list($key, $name) = each($units)) {
if ($key == "0") {
$html .= " <option title=\"$name\" value='$key'>$name</option>\r";
} else if ($key == $code) {
$html .= " <option title=\"$name\" selected=\"selected\" value='$key'>$key</option>\r";
} else {
$html .= " <option title=\"$name\" value='$key'>$key</option>\r";
}
}
$html.= "</select>\r";
return $html;
}
print unit_select_option ('class="units_select"', "g");
print unit_select_option ('class="units_select"', "mg");
print unit_select_option ('class="units_select"', "mcg");
?>
the code shouldn't be nothing strange but I haven't found the issue because the page doesn't return any error.
html code:
<select title="Kilojoule: kJ;
Grammi: g;
Milligrammi: mg;
Microgrammi: mcg, µg;" class="units_select">
<option title="Unità" value='0'>Unità</option>
<option title="Kilojoule: kJ" value='kJ'>kJ</option>
<option title="Grammi: g" selected="selected" value='g'>g</option>
<option title="Milligrammi: mg" value='mg'>mg</option>
<option title="Microgrammi: mcg, µg" value='mcg'>mcg</option>
</select>
<select title="Kilojoule: kJ;
Grammi: g;
Milligrammi: mg;
Microgrammi: mcg, µg;" class="units_select">
</select>
<select title="Kilojoule: kJ;
Grammi: g;
Milligrammi: mg;
Microgrammi: mcg, µg;" class="units_select">
</select>

each() advances the internal array cursor. Because $units is a global variable, your first call of unit_select_option() advances the cursor to the end of $units, and there it remains for the subsequent calls.
You need to rewind your array using reset($units); at the end of unit_select_option().
PHP Documentation: reset

You should reset the array pointer: use reset()
But why don't you use a foreach loop?
foreach($units as $key => $name){ ... }
And don't use global, it's evil. Declare $units array as static within the function body.

From each():
Return the current key and value pair
from an array and advance the array
cursor.
After each() has executed, the array
cursor will be left on the next
element of the array, or past the last
element if it hits the end of the
array. You have to use reset()
if you want to traverse the array
again using each.
So:
function unit_select_option ($attributes, $code = "") {
global $units;
$html = "<select title=\"Kilojoule: kJ;
Grammi: g;
Milligrammi: mg;
Microgrammi: mcg, µg;\" $attributes>\r";
reset($units);
while (list($key, $name) = each($units)) {
if ($key == "0") {
$html .= " <option title=\"$name\" value='$key'>$name</option>\r";
} else if ($key == $code) {
$html .= " <option title=\"$name\" selected=\"selected\" value='$key'>$key</option>\r";
} else {
$html .= " <option title=\"$name\" value='$key'>$key</option>\r";
}
}
$html.= "</select>\r";
return $html;
}
I tend to avoid each() because its non-reentrant, meaning if inside your loop you call something else that uses it on the same array it'll affect your outer call. Not good. You tend to be better off just using a foreach loop:
function unit_select_option ($attributes, $code = "") {
global $units;
$html = "<select title=\"Kilojoule: kJ;
Grammi: g;
Milligrammi: mg;
Microgrammi: mcg, µg;\" $attributes>\r";
foreach ($units as $key => $name) {
if ($key == "0") {
$html .= " <option title=\"$name\" value='$key'>$name</option>\r";
} else if ($key == $code) {
$html .= " <option title=\"$name\" selected=\"selected\" value='$key'>$key</option>\r";
} else {
$html .= " <option title=\"$name\" value='$key'>$key</option>\r";
}
}
$html.= "</select>\r";
return $html;
}
and you avoid all those issues.

You need to reset your array after or before your while block.

The other answers should have already solved your question.
I want to add that PHP has the foreach construct, so instead of the while loop you can just write
foreach ($unit as $key => $name) {
...
}
You don't need to reset() if you use foreach.

Ok, as others have said the problem was because you weren't resetting the global array.
However, I'd be tempted not to use a global and instead pass it into the unit_select_option every time. (Arrays and objects are passed by reference in recent versions of PHP, so there's no reason not to do this and it's generally accepted as better programming practice.)
Secondly, you're doing some wierd things in the while loop - I'd have thought a foreach iterator would make more sense in this instance as such:
foreach($units as $key => $value)
Just an idea. :-)

Related

Generate "select inputs" through loops in arrays

I have the following array:
$selects = array(
'Select1' => array('select1_name' => array('select1_value1','select1_value1')),
'Select2' => array('select2_name' => array('select2_value1','select2_value2'))
);
I wonder how I can generate these "selects inputs" with their options through a loop?
You need one cycle, which will loop through selects array and inside this cycle, you need another one, which will loop through selects. And inside this one, you need one more, which will loop through the option values:
$selects = array(
'Select1' => array('select1_name' => array('select1_value1','select1_value1')),
'Select2' => array('select2_name' => array('select2_value1','select2_value2'))
);
foreach($selects as $select) {
foreach($select as $item) {
echo "<select>";
foreach($item as $value) {
echo "<option value=".$value.">".$value."</option>";
}
echo "</select>";
}
}
This will produce:
<select>
<option value=select1_value1>select1_value1</option>
<option value=select1_value1>select1_value1</option>
</select>
<select>
<option value=select2_value1>select2_value1</option>
<option value=select2_value2>select2_value2</option>
</select>
foreach($selects as $select) {
foreach($select as $selectName => $value) {
echo '<select> ';
echo '<option>'.$selectName.'</option>';
foreach($value as $v) {
echo '<option>'.$v.'</option>';
}
echo '</select>';
}
}
echo '<select> ';
foreach($selects as $array) {
foreach($array as $value) {
foreach($value as $v) {
echo '<option value="'.$v.'">'.$v.'</option>';
}}}
echo '</select>';

Print out something only when value is within specific group during loop in PHP

I have a big array that is being used throughout the site and changing its structure just for the following task would be a pain. I want to make several select boxes with another array. The output I want to get is like this:
/* Example Array:
$allAnimals = array("Frogs","Toads","Bats","Elephants","Rats","Seals",
"Crocodilians","Turtles");
$group = array("Frogs"=>"Amphibian","Bats"=>"Mammal","Crocodilians"=>"Reptile");
*/
<select name='Amphibian'>
<option value='0'>Frogs</option>
<option value='1'>Toads</option>
</select>
<select name='Mammal'>
<option value='2'>Bats</option>
<option value='3'>Elephants</option>
<option value='4'>Rats</option>
<option value='5'>Seals</option>
</select>
<select name='Reptile'>
<option value='6'>Crocodilians</option>
<option value='7'>Turtles</option>
</select>
I can't figure out how to print out the options only when the value is within the specific animal group during each iteration of $group. I have tried each() to get the next animal $endAnimal from $group and then break the internal loop if $animal matches the $endAnimal, but I also need to make the loop start printing options at specific values.
<?php
$allAnimals = array("Frogs","Toads","Bats","Elephants","Rats","Seals","Crocodilians","Turtles");
$group = array("Frogs"=>"Amphibian","Bats"=>"Mammal","Crocodilians"=>"Reptile");
foreach($group as $thisAnimal=>$category){
$nextKey = (each($group));
$endAnimal = $nextKey['key'];
print "<select name='$category'>";
foreach($allAnimals as $idx=>$animal){
print "<option value='$idx'>$animal</option>";
if($endAnimal === $animal){
break;
}
}
print "</select>";
}
?>
Please check this out:-
<?php
$allAnimals = array("Frogs","Toads","Bats","Elephants","Rats","Seals","Crocodilians","Turtles");
$group = array("Frogs"=>"Amphibian","Bats"=>"Mammal","Crocodilians"=>"Reptile");
$group_keys = array_keys($group); // get the keys of group array
$j = 0;
foreach($group_keys as $key => $group_k){
print "<select name='$group[$group_k]'>";
if(isset($group_keys[$key+1])){
$new_value = $group_keys[$key+1];
}else{
$new_value = '';
}
if($new_value ==''){
foreach($allAnimals as $key => $allAnm){
print "<option value='$j'>$allAnm</option>";
unset($allAnimals[$key]);
$j ++;
}
}else{
$key_from = array_search($new_value,$allAnimals);
for($i = 0; $i<$key_from; $i++){
print "<option value='$j'>$allAnimals[$i]</option>";
unset($allAnimals[$i]);
$j ++;
}
}
$allAnimals = array_values($allAnimals);
print "</select>";
}
Output:- https://eval.in/379462 (eval.in)
local end :- (for better showing) :- http://prntscr.com/7fmtbi
Array of Array is the solution I think
$group = array( "Amphibian" => array("Frogs", "Toads"), "Mammal" => array("Bats", "Elephants", "Rats", "Seals"), "Reptile" => array("Crocodilians", "Turtles") );
foreach($group as $thisAnimal=>$category){
print "<select name='$category'>";
foreach($category as $idx=>$animal){
print "<option value='$idx'>$animal</option>";
}
print "</select>";
}
Thank you for your responses and answers. I just sort of get that to work by checking whether $thisAnimal from $group is the same as $animal from $allAnimals during the internal loop. If it's the same, turn $passThis to true and then proceed to print out the option until $endAnimal matches $animal. Example
<?php
$allAnimals = array("Frogs","Toads","Bats","Elephants","Rats","Seals","Crocodilians","Turtles");
$group = array("Frogs"=>"Amphibian","Bats"=>"Mammal","Crocodilians"=>"Reptile");
foreach($group as $thisAnimal=>$category){
$nextKey = (each($group));
$passThis = false;
$endAnimal = $nextKey['key'];
print "<select name='$category'>";
foreach($allAnimals as $idx=>$animal){
if($animal === $thisAnimal){
$passThis = true;
}
if($endAnimal === $animal){
break;
}
if($passThis === true)
{
print "<option value='$idx'>$animal</option>";
}
}
print "</select>";
}
?>

PHP shows array keys 1 number higher

I want to get all keys of an array showing on my page.
Right now I have this:
$subjectcodes[1] = "Mathematics";
$subjectcodes[2] = "Physics";
$subjectcodes[3] = "Charlie";
$subjectcodes[4] = "Chemistry";
$subjectcodes[5] = "Biology";
$subjectcodes[6] = "English";
$subjectcodes[7] = "Dutch";
$subjectcodes[8] = "German";
$subjectcodes[9] = "Sociology";
$subjectcodes[10] = "Physical Education";
$subjectcodes[11] = "Art";
$subjectcodes[12] = "General Science";
$subjectcodes[13] = "Philosophy";
$subjectcodes[14] = "Management and Organization";
$subjectcodes[15] = "Research and Design";
foreach ($subjectcodes as &$value) {
$key = key($subjectcodes);
echo "<option value=" . $key . ">" . $value . "</option>";
}
When I go to my page with that code I get:
<option value=2>Mathematics</option>
<option value=3>Physics</option>
<option value=4>Charlie</option>
<option value=5>Chemistry</option>
<option value=6>Biology</option>
<option value=7>English</option>
<option value=8>Dutch</option>
<option value=9>German</option>
<option value=10>Sociology</option>
<option value=11>Physical Education</option>
<option value=12>Art</option>
<option value=13>General Science</option>
<option value=14>Philosophy</option>
<option value=15>Management and Organization</option>
<option value=>Research and Design</option></select>
As you can see all keys are 1 higher number then supposed. And the last option doesn't even have a key...
Does anyone why this is, and how I can solve this?
Thanks!
Try:
foreach ($subjectcodes as $key=>$value) {
//$key = key($subjectcodes);
echo "<option value=" . $key . ">" . $value . "</option>";
}
you can use key and value in foreach(), so change:
foreach ($subjectcodes as &$value) {
$key = key($subjectcodes);
echo "<option value=" . $key . ">" . $value . "</option>";
}
to
foreach ($subjectcodes as $key => $value) {
echo "<option value=" . $key . ">" . $value . "</option>";
}
Foreach iterates over the array, this means that when you use the key method the "current" array element is the next on your foreach cycle. Your code is not well constructed for what you are trying to acomplish.
Use this instead:
foreach ($subjectcodes as $key => $value) {
echo "<option value=" . $key . ">" . $value . "</option>";
}
Note: Unless you want to change the value of the array element inside the foreach cycle there is no need to use &$value.
A note to complete the info about using reference as foreach loop variables:
From http://php.net/manual/en/control-structures.foreach.php:
Reference of a $value and the last array element remain even after
the foreach loop. It is recommended to destroy it by unset().
So if you decided to use a reference as a foreach variable, you have unset it after the foreach.
foreach ($subjectcodes as &$value)
{
}
unset($value)

"Array" is displaying in dropdown instead of values fetched from database

code snippet from html_form_class
<?php
$frmStr = $frm->addSelectList(
'city',
$city,
true,
'',
'--- Select City ---',
array(
'class' => 'dropdown-style5',
'id' => 'city'));
echo $frmStr; ?>
code snippet from seachcar.php
$city = $db->select('City','City_Name');
foreach($city as $row)
{
$row;
}
"Array" is displaying in dropdown instead of values fetched from database
Please Advice!
function addSelectList($name, $option_list, $bVal = true, $selected_value = NULL,
$header = NULL, $attr_ar = array() ) {
$str = "<select name=\"$name\"";
if ($attr_ar) {
$str .= $this->addAttributes( $attr_ar );
}
$str .= ">\n";
if ( isset($header) ) {
$str .= " <option value=\"\">$header</option>\n";
}
foreach ( $option_list as $val => $text ) {
$str .= $bVal? " <option value=\"$val\"": " <option";
if ( isset($selected_value) && ( $selected_value === $val || $selected_value === $text) ) {
$str .= $this->xhtml? ' selected="selected"': ' selected';
}
$str .= ">$text</option>\n";
}
$str .= "</select>";
return $str;
}
html output of addSelectList function is
<select name="city" class="dropdown-style5" id="city">
<option value="">--- Select City ---</option>
<option value="0">Array</option>
<option value="1">Array</option>
<option value="2">Array</option>
<option value="3">Array</option>
You need to rebuild the array of cities:
$city = $db->select('City','City_Name');
$city_rebuild = array();
foreach($city as $row) {
$city_rebuild[] = $row['City_Name'];
}
$city = $city_rebuild;
You do echo of array. Something is wrong in your abstraction objects. You must iterate on array to show up its values.
function addSelectList creates a "dropdown" (actually a select element)
You need to remove the html from the function output.
Edit 1
I was confused as to what you were going for. In your foreach($option_list... you need to know what keys are available in the $option_list array and what you want to appear in the select dropdown.

How do I access only second array?

I'm doing this:
$sql_glassware = 'SELECT id, name FROM glassware';
$qry_glassware = $con->query($sql_glassware);
$get_glassware = $qry_glassware->fetchAll(PDO::FETCH_ASSOC);
debug($get_glassware);
debug() is a personal function; It returns the result like this:
$get_glassware = array(19) {
[0]=>array(2) {
["id"]=>string(1) "1"
["name"]=>string(8) "Cocktail"
}
[1]=>array(2) {
["id"]=>string(1) "2"
["name"]=>string(9) "Margarita"
}
[2]=>array(2) {
["id"]=>string(1) "3"
["name"]=>string(8) "Highball"
}
...
}
I'm guessing the first array level is the rows, and the second level is the columns.
don't know why it return the id as strings thoug...
Then I'm using a class to construct a complete form; I have a public function called addSelect() where the first argument takes an array of values to build the options list: array('name0','name1', 'name2','...') and do a foreach()-loop inside:
public function addSelect($opt=array(),$param=array())
$name = $this->useEither($param['name'],'dropdown-list'); // useEither() is a personal function
foreach ($opt as $val => $name){
$options .= '<option value="'.$val.'">'.$name.'</option>';
}
$select = '<select name="'.$name.'" '.$param['string'].'>'.$options.'</select>';
$this->formElements[] = $select; // store the list for use later
}
How can re-write this litte function so I can pass $get_glassware directly into my function first argument and have it output the options like this:
<option value="1">Cocktail</option>
<option value="2">Margarita</option>
<option value="3">Highball</option>
Try this:
public function addSelect($opt=array(),$param=array())
$name = $this->useEither($param['name'],'dropdown-list'); // useEither() is a personal function
foreach ($opt as $option){
$options .= '<option value="'.$option['id'].'">'.$option['name'].'</option>';
}
$select = '<select name="'.$name.'" '.$param['string'].'>'.$options.'</select>';
$this->formElements[] = $select; // store the list for use later
}
I'm not sure why or what do you want to do there but your foreach in addSelect overwrites the $name variable.
But as far as I understand your problem, that should do the trick for you.
foreach ($opt as $val => $name){
$options .= '<option value="' . $name['id'] . '">' . $name['name'] . '</option>';
}
For the debug function... usually print_r is easier to read instead of var_dump but for debugging maybe sometimes still necessary.

Categories