views:

133

answers:

5

Hello.

Here's a piece of PHP code I think is not very "pretty", I'm sure it's possible to simplify it with for or something. I'm trying to find and algorithm that would work for this, but I can't figure it out, please help me.

Here's the code:

if(isset($four))
{
 if(isset($navi[$one][$two][$three][$four])) echo "/content/" . $one . "/" . $two . "/" . $three . "/" .$four . ".php";
 else echo "error";
}
else if(isset($three))
{
 if(isset($navi[$one][$two][$three]))  echo "/content/" . $one . "/" . $two . "/" . $three . ".php";
 else echo "error";
}
else if(isset($two))
{
 if(isset($navi[$one][$two])) echo "/content/" . $one . "/" . $two . ".php";
 else echo "error";
}
else if(isset($one))
{
 if(isset($navi[$one]))echo "/content/" . $one . ".php";
 else echo "error";
}
else
{
 echo "error";
}

Thanks!

+2  A: 

Updated, tested:

$parts = array($one, $two, $three, $four);
$reversed = array_reverse($parts);

function getPath($ret, $n) {
    global $parts;
    foreach (range(0, $n) as $i) {
        $ret = $ret[$parts[$i]];
    }
    return $ret;
}

$error = false;
foreach (range(0, count($reversed)) as $i) {
    if (!$reversed[$i]) {
        unset($reversed[$i]);
        continue;
    }

    if (!getPath($navi, count($parts) - $i - 1)) {
        $error = true;
        break;
    }
}

if ($error) {
    echo "error!";
} else {
    echo "/content/" . implode("/", array_reverse($reversed)) . ".php";
}
Victor Stanciu
A: 

The problem is that you are using isset(foo), which makes it hard to put the variables into an array. If testing the length of the variable will do, then use:

$parts = array_reverse(array($one,$two,$three,$four));
foreach ($parts as $i => $value) 
    if(strlen($value)==0) 
        unset($array[$i]);
$final = join('/',parts);
if(isset($navi[$final])) echo "/content/" . $final . ".php";
else echo "\nerror\n\n\n";

But this will require you to change your $navi construct to look like

$navi['foo/bar/baz'] = "someval";

instead of

$navi['foo']['bar']['baz'] = "someval";

because we will be using the concatenated string $final to look up in the $isset. Otherwise the only route is dynamically generated php which is horrible.

Could you structure your data differently? Looping for array dimensions is not nice, whereas the above flat list is much more easily accomplished.

Phil H
A: 

I think there is deeper problems with Your code. But to solve just this problem -- there is my guess:

$urls = array();
$tempNavi = $navi;
foreach (array('one', 'two', 'three', 'four') as $var) {
    if (!isset($$var) || !isset($tempNavi[$$var]))
        break;
    $tempNavi = $tempNavi[$$var];
    $urls[] = $$var;
}

if ($urls) {
    echo '/content/' . implode('/', $urls);
} else {
    echo 'error';
}
petraszd
A: 

A recursive solution, for the sake of completeness:

function navi_recurse(&$navi, &$steps, $i = 0) {
  if ($i < count($steps) - 1) {
    $step = $steps[$i];
    if ( isset($navi[$step]) )
      return navi_recurse($navi[$step], $steps, $i+1);
    else
      return "error\n";
  } 
  return '/content/'.implode('/', $steps).'.php';
}

Call like this:

$steps = array($one, $two, $three, $four);
echo navi_recurse($navi, $steps);
Tomalak
A: 

@petraszd:
Thanks, I like your version the best. I'd like to use this in a function, but then how will I be able to access the $one, $two, $three and $four variables, which are outside of the local function scope?

EDIT: NVM, I just realized that your version doesn't work correctly.

did you test mine? :D
Victor Stanciu