views:

209

answers:

8
+2  Q: 

PHP 'Years' array

I am trying to create an array for years which i will use in the DOB year piece of a form I am building. Currently, I know there are two ways to handle the issue but I don't really care for either:

1) Range:

I know I can create a year array using the following

<?php 
     $year = range(1910,date("Y"));
     $_SESSION['years_arr'] = $year;
?>

the problem with Point 1 is two fold: a) my function call shows the first year as 'selected' instead of "Year" as I have as option="0", and b) I want the years reversed so 2010 is the first in the least and shown decreasing.

My function call is:

PHP

<?php
    function showOptionsDrop($array, $active, $echo=true){
        $string = '';

        foreach($array as $k => $v){
            $s = ($active == $k)? ' selected="selected"' : '';
            $string .= '<option value="'.$k.'"'.$s.'>'.$v.'</option>'."\n";     
        }

        if($echo)   echo $string;
        else        return $string;
    }
?>

HTML

<table>
            <tr>
            <td>State:</td>
            <td><select name="F1State"><option value="0">Choose a year</option><?php showOptionsDrop($_SESSION['years_arr'], null, true); ?></select>
            </td>
            </tr>
</table>

2) Long Array

I know i can physically create an array with years listed out but this takes up a lot of space and time if I ever want to go back and modify.

ex: PHP

$years = array('1900'=>"1900", '1901'=>"1901", '1902'=>"1902", '1903'=>"1903", '1904'=>"1904", '1905'=>"1905", '1906'=>"1906", '1907'=>"1907", '1908'=>"1908", '1909'=>"1909", '1910'=>"1910", '1911'=>"1911", '1912'=>"1912", '1913'=>"1913", '1914'=>"1914", '1915'=>"1915", '1916'=>"1916", '1917'=>"1917", '1918'=>"1918", '1919'=>"1919", '1920'=>"1920", '1921'=>"1921", '1922'=>"1922", '1923'=>"1923", '1924'=>"1924", '1925'=>"1925", '1926'=>"1926", '1927'=>"1927", '1928'=>"1928", '1929'=>"1929", '1930'=>"1930", '1931'=>"1931", '1932'=>"1932", '1933'=>"1933", '1934'=>"1934", '1935'=>"1935", '1936'=>"1936", '1937'=>"1937", '1938'=>"1938", '1939'=>"1939", '1940'=>"1940", '1941'=>"1941", '1942'=>"1942", '1943'=>"1943", '1944'=>"1944", '1945'=>"1945", '1946'=>"1946", '1947'=>"1947", '1948'=>"1948", '1949'=>"1949", '1950'=>"1950", '1951'=>"1951", '1952'=>"1952", '1953'=>"1953", '1954'=>"1954", '1955'=>"1955", '1956'=>"1956", '1957'=>"1957", '1958'=>"1958", '1959'=>"1959", '1960'=>"1960", '1961'=>"1961", '1962'=>"1962", '1963'=>"1963", '1964'=>"1964", '1965'=>"1965", '1966'=>"1966", '1967'=>"1967", '1968'=>"1968", '1969'=>"1969", '1970'=>"1970", '1971'=>"1971", '1972'=>"1972", '1973'=>"1973", '1974'=>"1974", '1975'=>"1975", '1976'=>"1976", '1977'=>"1977", '1978'=>"1978", '1979'=>"1979", '1980'=>"1980", '1981'=>"1981", '1982'=>"1982", '1983'=>"1983", '1984'=>"1984", '1985'=>"1985", '1986'=>"1986", '1987'=>"1987", '1988'=>"1988", '1989'=>"1989", '1990'=>"1990", '1991'=>"1991", '1992'=>"1992", '1993'=>"1993", '1994'=>"1994", '1995'=>"1995", '1996'=>"1996", '1997'=>"1997", '1998'=>"1998", '1999'=>"1999", '2000'=>"2000", '2001'=>"2001", '2002'=>"2002", '2003'=>"2003", '2004'=>"2004", '2005'=>"2005", '2006'=>"2006", '2007'=>"2007", '2008'=>"2008", '2009'=>"2009", '2010'=>"2010");

$_SESSION['years_arr'] = $years_arr;

Does anybody have a recommended idea how to work - or just how to simply modify my existing code?

Thank you!

A: 

In option 1 add:

$year = array_reverse( $year );

or just use:

$year = range( date("Y") , 1910 );
drawnonward
thanks for the advice but part 1a) is still an issue there. I might try and fool around with it some more but good to know
JM4
A: 

If just reversing the order of your year array is the goal you can use the array_reverse() function.

http://www.php.net/manual/en/function.array-reverse.php

Tim
great - thanks for the formula
JM4
A: 

part 2:

$years = array();
for($i = 1900;$i<= 2010;$i++)
    $years["$i"] = $i;
ortuna
this actually doesn't work for the function I'm using. I tried before and ran into issues.
JM4
Hardcoding 2010 is probably a bad idea, but I understand you might have done it for the simplicity of the example?
majelbstoat
yea for simplicity. He could see the where the range is, and perhaps do some other processing inside the for loop.Also, what where the issues?
ortuna
+1  A: 

Why don't you do this on your first approach

    foreach($array as $k){
        $string .= '<option value="'.$k.'">'.$k.'</option>'."\n";     
    }

Semantically, and functionally, speaking it's better to use the year as value than an int.

Also, use drawnonward method to get an inverted array so the year 2010 is the first, and default, value on your list.

Ben
I am unfamiliar with the drawnonward array bu will certainly look into it
JM4
@J M 4 - I was talking about the guy who posted an answer here, he said you can use $year = array_reverse( $year ); in order to get the 2010 first.
Ben
A: 

I'd go with option #1. However all you need to do is prepend a value to the array before you print it:

<?php 
$years = $_SESSION['years_arr'];
// reverse the year list
rsort($years);
// prepend the 'choose a year' value to the array
array_unshift($years, 'Choose a year');
?>

<td><select name="F1State"><?php showOptionsDrop($years, null, true); ?></select>
Ben Rowe
Thanks Ben - i have to define the session variable first though because i use it on page 1 and again 4 other times during the form collection. good advice though
JM4
+3  A: 

Not sure why you're using the session for this, but generating the array can be done with the array_combine function.

$years = array_combine(range(date("Y"), 1910), range(date("Y"), 1910));

Reversing the parameters to range will give you a descending array and array_combine will use the first array as the keys and the second as the values, giving the array(1910 => 1910, ...); map you're after.

Brenton Alker
Thanks Brenton - the SESSION is being used because I am using the same array on several pages throughout the form.
JM4
Using session means you're storing a separate copy of this to disk for every user. Just build it once, `serialize()` it, and store it in a single file on disk.
Frank Farmer
This is not an expensive array to build. How about a compromise? Have the function put it in a static variable. That way each page that wants it builds it once and you don't have the overhead of storing it.
staticsan
@staticsan That's not a valid solution in PHP, as everything is local to the one request and destroyed at the end of the request cycle. Any variable, even a static one, only has a lifespan of 1 request.
Brenton Alker
I would suggest not bothering with storing the array at all and just generate it each time. At least until you can prove that it's a bottleneck. It's just simpler that way.
Brenton Alker
It's easier to just generate the array each time. If performance is very, very, very critical, then run a benchmark to see whether or not it is faster to create it or to deserialize it - we can't exactly know until we try.
Matchu
I'd also store that `range(...)` bit in a variable up top so that you're not repeating yourself and it's not generated twice. Did a quick benchmark - unsurprisingly, it almost cuts the run time in half, in addition to being DRY.
Matchu
@Matchu Yes, I would probably pull the range() out of the actual line and assign it to a variable to reuse it. But I'd still be skeptical of the benchmarks. Sure, for that micro code it's almost twice as fast, but in the context of the rest of the request it's probably still insignificant.
Brenton Alker
@Brenton Alker - of course it's insignificant. The benchmark simply removes any possible reason to repeat one's self, as if being DRY weren't enough.
Matchu
Wow - i think you all make great points. I'm not familiar with 'serializing' the code but I can simply run the function at on each page as needed if that is the best method of doing so. I originally had built as text input with 4 max characters and validations done so just wanted something that looked cleaner.
JM4
@Brenton Aiker: yes, that's the point. When a page wants it, it's built. When the same page -- still running -- wants it a second or third time, it's already built. I have used this technique for a long time and it creates measurable savings in PHP.
staticsan
+1  A: 

reverse the numbers in the range to get years in descending order

$years = range(2010, 1900); // => [2010, 2009, 2008, ... ]

use date('Y') instead of hard-coding the current year

$years = range(date('Y'), 1900);

append an option "Select year" at the beginning

array_unshift($years, "Select year");

And finally why have a select drop-down for year or date of birth at all? It might be prevalent but it's super irritating. A simple text-box with validations, something like dd/mm/yyyy or mm/dd/yyyy is way better. Having drop-downs for date, month, and year only means that a user is allowed to select valid values and not necessarily correct values if they find it convoluted just to input a date. Moreover, since users can still enter junk values by modifying the DOM, validations need to be done on the server side. If validations are being done on the server-side, might as well just offer them a simple text box.

Also drop-downs make client-side coding complex. For example, if Feb and a leap year are selected, then a days dropdown should contain 29 days, otherwise 28.

Anurag
Anurag - you make good points. I think the reason I wanted to go with this flow however was to simply a process for the consumer. We originally had a simple text box, max 4 characters and ran JV/php validation on the backend. Just though it looked cleaner to go this way.
JM4
+1  A: 

Why do you need to store the array into the session?

Based on your use case, you do not need to use the array to store data beforehand.

define('DOB_YEAR_START', 1900);

$current_year = date('Y');

for ($count = $current_year; $count >= DOB_YEAR_START; $count--)
{
    print "<option value='{$count}'>{$count}</option>";
}
xdallen
it is stored into session because I call on the function several times throughout the form process (different pages).
JM4
@JM4, you may take advantage of function construct to produce a piece of reusable codes. You may then include the function in those pages needed.Storing in session may cause heavy memory usage since every browser (consuming different sessions) will get a copy of same year array.
xdallen