Is it possible to use range to have a leading 0?

Say I want to easily list out months or days for a select menu but I want the numbers to come out as 01-09 instead of 1-9 with the leading zeros. Can I use the standard range function or do I have to modify some more. For example this is what I have that gives me no leading 0 for 1-9:


echo '<select>';
foreach (range(01, 31) as $number) {
    echo '<option value="'.$number.'">'.$number.'</option>';
}
echo '</select>';

An important consideration here, is do you only want the number shown to the user to be zero-filled, or should the number sent to the server be zero-filled as well ?

The value attribute of the <option> element is an implied or optional attribute.

<!ELEMENT option (#PCDATA)>     <!-- selectable choice -->
<!ATTLIST option
  &#37;attrs;
  selected    (selected)     #IMPLIED
  disabled    (disabled)     #IMPLIED
  label       %Text;         #IMPLIED
  value       CDATA          #IMPLIED
  >

If it’s not included, the browser will send the options #PCDATA text node as the value when the form is submitted.

This means that the following is valid.

<option>01</option>

So, if the server is expecting the same zero-filled values the user is seeing, you can do something like this.

<?php

printf('<option>0%1$s</option><option>%2$s</option>',
	implode('</option><option>0', range(1, 9)),
	implode('</option><option>', range(10,31))
);

?>

Typically 1$ is not used with sprintf, because it just takes the values that are provided and automatically assigns them to the most appropriate locations. When you want to repeat values though, or use similar values in a different order, this is when deliberately indicating which values to use becomes important, as in this case where the $number value is used twice.

I have to disagree with only using the tokens without the placement parts. It’s much easier to add new parts to something generated with the printf functions when you always use the numbered tokens.
Rather than having to reorder my tokens in the mask and figure out what goes where, I just add a value at the end of the argument list, then place the next numbered token anywhere in the string I want it to show up. This makes life a lot easier if I want to add a new value, but I want it displayed somewhere toward the middle of the tokens. It also makes things easier if you have multi-language versions of a script or site, translators can reorder things as needed. :slight_smile:

Whats the big difference between yours and the others? Is it performance or efficient structure?

The difference is that it’s making use of built in formatting techniques that are easier to understand and modify.

See the sprintf for documentation on the different ways that it can be used. sprintf returns a formatted string and is where the documentation is stored. printf outputs a formatted string, so printf is equivalent to echo sprintf

printf('<option value="&#37;1$02d">%1$02d</option>', $number);

Here’s how %1$02d is interpreted

[list][]% - use special formatting
[
]1$ - use the first value, which is important when you’re repeating the use of the values
[]02 - zero padded, two digits in length
[
]d - an integer (decimal) value
[/list]

Typically 1$ is not used with sprintf, because it just takes the values that are provided and automatically assigns them to the most appropriate locations. When you want to repeat values though, or use similar values in a different order, this is when deliberately indicating which values to use becomes important, as in this case where the $number value is used twice.

Ah I didn’t know that. Thank you!

You are thinking of for and its evaluation portion. Using a function in a foreach call is only executed once. You can test this very easily:


<?php

function test () { var_dump( "ran" ); return range( 1, 10 ); }
foreach ( test() as $var ) echo $var;

Only parts of a loop that do an evaluationare repeated.

for ( static; dynamic; dynamic )
while ( dynamic )
foreach ( static )

In addition, it’s not really a good idea to include the range() function inside the foreach, since php would have to execute the function on every iteration. Also performing str_pad twice seems superfluous. Instead you could better do


echo '<select>';
$range = range(1,31);
foreach ($range as $number) {
  $number = (str_pad($number, 2, "0", STR_PAD_LEFT));
  echo '<option value="'.$number.'">'.$number.'</option>';
} 
echo '</select>';

Slight alternative.


<select name="day">
  <?php
    foreach(range(1, 31) as $number){
      printf('<option value="%1$02d">%1$02d</option>', $number);
    }
  ?>
</select>


foreach (range(1,31) as $number {
  echo '<option value="'.(str_pad($number, 2, "0", STR_PAD_LEFT)).'">'.(str_pad($number, 2, "0", STR_PAD_LEFT)).'</option>';
}