Handling missing array offsets
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.
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.
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
}
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];
}
}
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.
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
}
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.
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.
精彩评论