views:

503

answers:

3

Scenario/Problem Isolation: Lets suppose my program uses MULTIPLE variables. At the program beginning I want to manipulate MANY of the variables AT ONCE through a general function with LITTLE CODE, before then later in the process using only distinctive few variables in specific functions.

Question: How do I pass multiple variables by reference to a foreach loop? Or is there a better/alternative method for looping through multiple determined variables?

Post(s) related to topic, but didn't solve my issue:

http://stackoverflow.com/questions/1186274/php-foreach-loop-on-multiple-objects

Background (for those concerned): I have a command line program which uses getopts http://hash-bang.net/2008/12/missing-php-functions-getopts/ to get various arguments, thus I get about 20 variables. I want to run all variables, which contain filepath(s) (about 10) through the "general" function reduceHierarchyDots() at ONCE (instead of calling the function 10 times).

<?php

/// The "general" function:

function reduceHierarchyDots ($file) {
    while (preg_match('|./\.{2}/|', $file)) { $file = preg_replace('|/([^/]+)/\.{2}/|', '/', $file, 1); }
    $file = preg_replace('|(/(\./)+)|', '/', $file);
    $file = preg_replace('|^(\./)+|', '', $file);
    return $file;
}

function reduceHierarchyDotsRef (&$file) {
    while (preg_match('|./\.{2}/|', $file)) { $file = preg_replace('|/([^/]+)/\.{2}/|', '/', $file, 1); }
    $file = preg_replace('|(/(\./)+)|', '/', $file);
    $file = preg_replace('|^(\./)+|', '', $file);
}

/// The "many" variables:

$x = "something";
$y = 123;
$y = array ("a", "B", 3);
$a = "/Users/jondoe/Desktop/source/0.txt";
$b = "/Users/jondoe/Desktop/source/../1.txt";
$c = "/Users/jondoe/Desktop/source/../../2.txt";
$arrOne = array (
    "v1" => "/some/thing/../1.pdf",
    "v2" => "/some/thing/../../2.pdf",
    "v3" => "/some/thing/../../../3.pdf"
);
$arrTwo = array (
    "./1.doc",
    "/so.me/.thing/ends./././2.doc",
    "./././3.doc"
);

/// At the beginning I want to run multiple determined variables through a "general" function:

/// Debugging: Variables BEFORE the manipulation:
echo("BEFORE:\n"); var_dump($b, $arrOne["v2"], $arrTwo[2]); echo("\n");

/// Method works, but is long! (1 line/statement per function call)
reduceHierarchyDotsRef($b);
reduceHierarchyDotsRef($arrOne["v2"]);
reduceHierarchyDotsRef($arrTwo[2]);

/// Hence, I'd like to pass all variables by reference at once to a foreach loop:
//// These cause: Parse error: syntax error, unexpected '&':
// foreach ( array($b, $arrOne["v2"], $arrTwo[2] ) as &$file) { $file = reduceHierarchyDots($file); }
// foreach (array(&$b, &$arrOne["v2"], &$arrTwo[2] ) as &$file) { $file = reduceHierarchyDotsRef($file); }
//// These have no effect on the intended variables:
// foreach (array(&$b, &$arrOne["v2"], &$arrTwo[2] ) as $file) { $file = reduceHierarchyDots($file); }
// foreach (array(&$b, &$arrOne["v2"], &$arrTwo[2] ) as $file) { $file = reduceHierarchyDotsRef($file); }

/// Debugging: Variables AFTER the manipulation:
echo("AFTER:\n"); var_dump($b, $arrOne["v2"], $arrTwo[2]);

/// After the "general" function ran over various variables, the more specific actions happen: ...

?>
A: 

Pass by reference is defined in the function signature:

function func(&$passByRef);

That's why your code is throwing errors.

See: http://php.net/manual/en/language.references.pass.php

Mr-sk
I have the foreach loop in 2 "styles" (using / not using by-reference) and the function in 2 "styles" (using / not using by-reference). And tried them in all possible combinations, but failed.Hence I sincerely aks again how to accomplish to run multiple variables through a general purpose function at once.
porg
@porg Store the values in an array, and pass the array by reference.
meagar
A: 

Passing an arbitrary number of arguments to a function only works via func_get_args() which cannot take values by reference. The best solution is to store your values in an array, and pass the array by reference.

If you still want to have access to the values as individual variables, store them using key/value pairs, and then extract() the array after it's been passed to the function.

<?php

function test(&$array) {
  /* foreach($array) ... */
}

$ar['x'] = "something";
$ar['y'] = 123;

test($ar);

extract($ar); // pull key/values into the local symbol table

echo $x;
echo $y;
?>

?>

meagar
Thanks for the hint for compact()/extract()! Nevertheless if you have types with different "dimensions", both "0-dimensional" objects such as single strings like $a = "aaa" $b = "bbb" and on the other side multi-dimensional objects such as arrays like $arr = array ("a", "b", "c") or $arr = array ["k1" => "x", "k2" => "y", "k3" => "z"] then you cannot use it. But for 0-dimensionals its very handy!
porg
A: 

You could try generating an array of the variable names, then using variable variables:

$x = '/bees/../ham';
$y = 'some/other/path';

$arr = array('x', 'y');

foreach($arr as $item) {
    reduceHierarchyDotsRef($$item);
}

not sure if this works with passing by reference, but I see not reason for it not to work.

PeterJCLaw
Passing variable variables by reference worked fine for "0-dimensional" objects like string variables, but I couldn't figure out the syntax for "multi-dimensional" objects such as indexed or keyed arrays.The PHP man page says:${$a[1]} means to use $a[1] as a variable.${$a}[1] means to use $$a as the variable and then the [1] index from that variable.But that didn't help me so far.
porg
I can only suggest that you build a dummy script and try things out if the docs aren't quite clear - I do this all the time. It should work regardless if you want to pass the whole array though.
PeterJCLaw