tags:

views:

58

answers:

7

Consider the following piece of code:

$tests = array( 
array ("a", "b", "c"),  array ("1", "2", "3"), array ("!", "@")
);

foreach ($tests as $test) 
 test($test[0], $test[1], $test[2]);

function test($param1, $param2, $param3) {
 // do whatever
}

This will work with no issues until it gets to the $test[2], which of course doesn't have a third element in the array, causing PHP to spit out:

Notice: Undefined offset: 2

Is there a way to get around this besides:

foreach ($tests as $test) {
 if (count($x) == 2) 
  test($test[0], $test[1]);
 else 
  test($test[0], $test[1], $test[2]);
}

function test($param1, $param2, $param3=null) {
 // do whatever
}

Which gets unwieldy as the size of each $test array gets bigger. Or should I just ignore the notice after all?

EDIT: Here is what I am actually trying to do:

// wanted this:
function validate() {
    $pass = true;
    $rules = array (array ('field1', '!=', 'banana'),
            array('field2', 'notempty')
    );

    for ($i=0; $i<count($rules) && $pass; $i++)
        $pass = check($rules[$i][0], $rules[$i][1], $rules[$i][1]);

    return $pass;
}

function check($field, $operator, $expected) {
    $value = $this->getValue($field);

    switch ($operator) {
        case '!=':
            $pass = ($value != $expected);
            break;

        case '==':
            $pass = ($value == $expected);
            break;

        case 'empty':
            $pass = empty($value);
            break;

        default:
            $pass = !empty($value);
            break;
    }

    return $pass;
}

//instead of
function validate() {
    $pass = true;

    for ($i=0; $i<count($rules) && $pass; $i++)
        $pass = check($rules[$i]);

    return $pass;
}

function check($check) {
    $value = $this->getValue($check[0]);

    switch ($check[1]) {
        case '!=':
            $pass = ($value != $check[2]);
            break;

        case '==':
            $pass = ($value == $check[2]);
            break;

        case 'empty':
            $pass = empty($value);
            break;

        default:
            $pass = !empty($value);
            break;
    }

    return $pass;
}

Basically for stylistic reasons.

+6  A: 

Interesting.

Why don't you juse do something like this?

foreach($tests as $test) {
   test($test);
}

function test($test) {
   // loop through $test to get all the values as you did originally
}

If you have a dynamic size of an array, I don't see why you can't just pass the entire array into the function instead of having separated arguments.

Bartek
I'm going with that now, but I wanted what I had originally for stylistic reasons.
quantumSoup
Which is explained in the edited post above
quantumSoup
A: 

Use this instead:

$tests = array( 
array ("a", "b", "c"),  array ("1", "2", "3"), array ("!", "@")
);

foreach ($tests as $test) 
test($test);

function test($test) 
{
    for($i=0; $i < count($test); $i++)
    {
        if (! isset($test[$i]) )
            $test[$i] = '';
    }

 // do whatever
}
Jauzsika
A: 

Why are you using $param1, $param2 and not directly the Array for the parameters, example:

$tests = array( 
 array( 'a', 'b', 'c' ),
 array( '1', '2', '3' ),
 array( '!', '@' )
);

foreach ( $tests as $test )
{
 test( $test );
}

function test( $params )
{
 $param1 = $params[0]; // Or use directly $params[index], than you need not to set it.
}

Or another way (but this way is not the best way, the way above is better ;))

$tests = array( 
 array( 'a', 'b', 'c' ),
 array( '1', '2', '3' ),
 array( '!', '@' )
);

foreach ( $tests as $test )
{
 test( $test );
}

function test( $params )
{
 for( $i=0; $i<=count( $params )-1; $i++ )
 {
  $param$i = $params[$i];
 }
}
ahmet2106
A: 

If the point of the question is simply how to iterate a multidimensional array, then do

$iterator = new RecursiveIteratorIterator(
                new RecursiveArrayIterator($theArray)
                RecursiveIteratorIterator::SELF_FIRST);

foreach($iterator as $key => $val) {
    echo "$key = $val \n"
}

If you want to know how to pass a variable number of arguments to a function, consider

function throwItAtMe()
{
    $args = func_get_args();
    print_r($args);
}
throwItAtMe(1,2,3,4,5, 'foo', 'bar', 'baz');

For your Rules/Assertions simply use a Strategy Pattern or have a look at the Specification pattern.

Gordon
A: 

You really should go with Bartek's solution, but for completeness here is one, that is probably more like you want it:

foreach ($tests as $test) {
    test($test[0], $test[1], isset($test[2]) ? $test[2] : null);
}

But honestly: If the sizes of the arrays can increase, do you really want to change the function signature every time? Enjoy our live and pass the array.

If it has at max 3 entries then you will be fine with the code above.

Felix Kling
A: 
foreach($tests as $test) {
  test($test);
}

function test($test) {
   @list($field, $operator, $expected) = $test;
   // if $test size is 2 then $expected will be NULL, @ is to suppress Notice, if you don't show notices you may ommit it
}
Kamil Szot
A: 

There is also ugly but short way to do it via call_user_func_array:

foreach ($tests as $test) {
    call_user_func_array('test', $test);
}

function test($param1, $param2, $param3 = null) {
    // ...
}

Though most likely I would prefer Bartek's solution.

Alexander Konstantinov