[PHP] Waarde van variabele opbouwen bij recursieve functie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Ik maak gebruik van een aantal recursieve functies, waaronder een om een option list te bouwen van de array $menuItems. Tot nu toe maakte ik een static variabele $output aan, zodat de waarde van $output niet verloren gaat als de functie opnieuw wordt aangeroepen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
 * Expanded node list
 */
function tree($menuItems, $curItem=1, $depth=0)
{
  static $output;

  foreach ($menuItems as $itemKey=>$item) 
  {
    if ($item['pid'] == $curItem)
    {
      $output.= '<option value="'.$itemKey.'">'.
          str_repeat('&nbsp;', $depth).$item['title'].'</option>';
      tree($menuItems, $itemKey, $depth+1);
    }
  }
  
  return $output;
}

Nu loop ik echter tegen de lamp: als ik 2 keer binnen dezelfde pagina tree() aanroep, bevat $output bij de tweede keer, twee keer de option list. Als ik tree() drie keer aanroep, is het resultaat van de derde aanroep een option list met drie keer het menu erin.

Dat heeft dus te maken met die static variabele, die ik (zo leerde ik nu) helemaal verkeerd toepas. Ik heb dus geprobeerd mijn code aan te passen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function tree($menuItems, $curItem=1, $depth=0, $output='')
{
  foreach ($menuItems as $itemKey=>$item) 
  {
    if ($item['pid'] == $curItem)
    {
      $output.= '<option value="'.$itemKey.'">'.
          str_repeat('&nbsp;', $depth).$item['title'].'</option>';
      tree($menuItems, $itemKey, $depth+1, $output);
    }
  }
  
  return $output;
}

Maar dit werkt ook niet. $output wordt nu elke ronde leeg gegooid.

Hoe los ik dit op?

[ Voor 56% gewijzigd door Reveller op 30-11-2004 19:37 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • ixi
  • Registratie: December 2001
  • Laatst online: 27-08 23:59

ixi

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<? 
/** 
 * Expanded node list 
 */ 
function tree($menuItems, $curItem=1, $depth=0) 
{
  foreach ($menuItems as $itemKey=>$item)  
  { 
    if ($item['pid'] == $curItem) 
    { 
      $output .= '<option value="'.$itemKey.'">'. 
          str_repeat('&nbsp;', $depth).$item['title'].'</option>'; 
      $output .= tree($menuItems, $itemKey, $depth+1); 
    } 
  } 
   
  return $output; 
} 
?>

[ Voor 92% gewijzigd door ixi op 30-11-2004 19:38 ]


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Dank je! Nu kan ik al mijn functies ombouwen :)

[update]
Waarom gaat het hier nu verkeerd? PHP zegt dat output een undefined variabele is op regel 9 en 12, maar ik heb $output toch in regel 4 kenbaar gemaakt?
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function buildTrail($menuItems, $activeItem, $depth=0)
{
  if ($depth == 0)
    $output = '<a href="'.BASE_URL.'">Home</a>';
 
  if ($menuItems[$activeItem]['pid'] != 0)
  {
    $href = BASE_URL.href($activeItem, $menuItems);
    $output.= buildTrail($menuItems, $menuItems[$activeItem]['pid'], $depth+1);    
    $output.= ' &gt; <a href="'.$href.'">'.$menuItems[$activeItem]['title'].'</a>';
  }
  return '<div id="trail">'.$output.'</div>';
}

[ Voor 156% gewijzigd door Reveller op 30-11-2004 20:15 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 13:32

Creepy

Tactical Espionage Splatterer

Alleen als de diepte 0 is is maak je die var aan. Bij een andere diepte dus niet.

Je moet output dus ook definieren als de diepte ongelijk is aan 0.

Maar dit had je natuurlijk zelf ook al gevonden toen je nog eens rustig naar je code keek en aan het debuggen ging, niet? ;)

In je topicstart in het tweede stukje code ben je er bijna. Je moet alleen nog de uitkomst van de tree aanroep in de tree functie toekennen aan output. Zo heb je dus geen static of globale variabele meer. En dan hoef je ook niet op diepte ==0 te controleren omdat je in de eerste aanroep van tree je de baseURL mee kan geven als parameter.

De oplossing van Ixi gaat uit van een static of globale output.

[ Voor 75% gewijzigd door Creepy op 30-11-2004 20:27 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
@Creepy - als ik je post opvolg kom ik volgens mij uit op
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function tree($menuItems, $curItem=1, $depth=0, $output=NULL)
{
  foreach ($menuItems as $itemKey=>$item) 
  {
    if ($item['pid'] == $curItem)
    {
      $output.= '<option value="'.$itemKey.'">'.
          str_repeat('&nbsp;', $depth).$item['title'].'</option>';
      $output.= tree($menuItems, $itemKey, $depth+1, $output);
    }
  }
  
  return $output;
}

Dit gaat alleen niet goed - ik krijg nu een option list met tig keer dezelfde info. Kun je misschien uitleggen wat je bedoelt met
Je moet alleen nog de uitkomst van de tree aanroep in de tree functie toekennen aan output.
Volgens mij zit daar de voud bij mij?

Het is overigens inderdaad de bedoeling de output niet static of global te maken. Want als ik het goed begrijp, kan dat ook de output van andere functies die $output gebruiken in de war gooien :)

[ Voor 31% gewijzigd door Reveller op 30-11-2004 20:39 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 13:32

Creepy

Tactical Espionage Splatterer

Je geeft de output al mee aan de functie. In de functie plak je de nieuwe output erachter.
Maar dan moet je niet ook nog eens het result van de functie erachter plakken, want dat stond er al :)
code:
1
2
3
4
5
  $output.= '<option value="'.$itemKey.'">'. 
          str_repeat(' ', $depth).$item['title'].'</option>';

  //toekennen, niet erachter plakken.
  $output = tree($menuItems, $itemKey, $depth+1, $output);

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Een laatste uitleg alsjeblieft - die eerste functie werkt nu goed, maar waarom werkt dezelfde oplossing bij mijn buildTrail functie niet?
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
function buildTrail($menuItems, $activeItem, $depth=0, $output=NULL)
{
  if ($depth == 0)
    $output.= '<a href="'.BASE_URL.'">Home</a>';
 
  if ($menuItems[$activeItem]['pid'] != 0)
  {
    $href = BASE_URL.href($activeItem, $menuItems);
    $output = buildTrail($menuItems, $menuItems[$activeItem]['pid'], $depth+1, $output);
    $output.= ' &gt; <a href="'.$href.'">'.$menuItems[$activeItem]['title'].'</a>';
  }
  return '<div id="trail">'.$output.'</div>';
}

Hierbij is $menuItems natuurlijk een Array met node informatie. De output is bijvoorbeeld:
HTML:
1
2
3
<div id="trail"><a href="http://localhost/cms">Home</a></div> &gt; 
<a href="http://localhost/cms/dennis/">Persoonlijk</a></div> &gt; 
<a href="http://localhost/cms/dennis/cv/">CV</a></div>

Met andere woorden - de </div> verschijnt achter elke node in plaats van alleen achteraan. Waarom werkt het wel bij de vorige maar niet bij deze functie?

[ Voor 18% gewijzigd door Reveller op 30-11-2004 21:12 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • DizzyWeb
  • Registratie: Februari 2001
  • Laatst online: 05-09 14:30

DizzyWeb

Ondertiteld

Omdat je bij iedere aanroep van buildTrail je de output in een div gooit... Dus ook de recursieve aanroep.

Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
DizzyWeb schreef op dinsdag 30 november 2004 @ 21:17:
Omdat je bij iedere aanroep van buildTrail je de output in een div gooit... Dus ook de recursieve aanroep.
Wat je daar zegt vermoed ik ook, maar het klopt niet helemaal. Want dan zou de output toch zo moeten zijn:
HTML:
1
2
3
<div id="trail"><a href="http://localhost/cms">Home</a></div> &gt; 
<div id="trail"><a href="http://localhost/cms/dennis/">Persoonlijk</a></div> &gt; 
<div id="trail"><a href="http://localhost/cms/dennis/cv/">CV</a></div>

Echter, <div id="trail"> wordt maar een keer ge-ouptut, niet drie keer zoals </div> :?

[ Voor 23% gewijzigd door Reveller op 30-11-2004 21:26 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
* kick *

heeft iemand een idee waarom alleen de </div> drie keer herhaald wordt?

[ Voor 83% gewijzigd door Reveller op 01-12-2004 10:10 ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 13:32

Creepy

Tactical Espionage Splatterer

Moeilijk te zeggen. Output is geen static of globale var meer?
BASE_URL ($vergeten?) bevat ook geen </div>
Let erop dat je nu op 3 plekken $output aanpast en als parameter doorgeeft.

Misschien zou je eens $output eens gescheiden kunnen houden van de het resultaat van de functie door bijv. tijdelijk een $res variabele (van result) aan te maken die je als result teruggeeft. Zo kan je wat makkelijker je code debuggen (wat met een recursieve functie een leuke klus kan zijn ;) ).

Met zelf debuggen, eventueel wat extra echo statements zodat je kan wat je code doet moet je er denk ik wel uit kunnen komen.

Daarnaast, je eigen topic kan je kicken na 24 uur. Eerder dan dit is niet echt gewenst. En half 10 s'avonds tot 10 uur 's ochtends is echt geen 24 uur :)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • Reveller
  • Registratie: Augustus 2002
  • Laatst online: 05-12-2022
Creepy schreef op woensdag 01 december 2004 @ 10:24:
Moeilijk te zeggen. Output is geen static of globale var meer?
Je bedoelt of $output als globale variabele of in een andere functie als static variabele bestaat? Antwoord daarop is nee.
BASE_URL ($vergeten?)
BASE_URL is een gedefinieerde constante.
Let erop dat je nu op 3 plekken $output aanpast en als parameter doorgeeft.
Dat doe ik bij de eerste functie (tree()) ook - daar levert het geen probleem op.
Misschien zou je eens $output eens gescheiden kunnen houden van de het resultaat van de functie door bijv. tijdelijk een $res variabele (van result) aan te maken die je als result teruggeeft.
Dat ga ik zeker proberen. Blijft staan dat het raar is dat het hier niet en bij tree() wel werkt...
Daarnaast, je eigen topic kan je kicken na 24 uur. Eerder dan dit is niet echt gewenst. En half 10 s'avonds tot 10 uur 's ochtends is echt geen 24 uur :)
Je hebt gelijk - ik ben wat te ongeduldig :X

P.S - dit is mijn eerste post in het nieuwe GoT! Het ziet er waarzinnig uit en werkt als een trein :)

[ Voor 7% gewijzigd door Reveller op 01-12-2004 10:56 . Reden: Even voor eeuwig vastleggen dat dit mijn eerste post in het nieuwe GoT is ;) ]

"Real software engineers work from 9 to 5, because that is the way the job is described in the formal spec. Working late would feel like using an undocumented external procedure."


Acties:
  • 0 Henk 'm!

Verwijderd

Wat je daar zegt vermoed ik ook, maar het klopt niet helemaal. Want dan zou de output toch zo moeten zijn:
code:
1
2
3
 <div id="trail"><a href="http://localhost/cms">Home</a></div> &gt; 
<div id="trail"><a href="http://localhost/cms/dennis/">Persoonlijk</a></div> &gt; 
<div id="trail"><a href="http://localhost/cms/dennis/cv/">CV</a></div>


Echter, <div id="trail"> wordt maar een keer ge-ouptut, niet drie keer zoals </div>
Nee, jou code leidt volgens mij tot
code:
1
2
3
 <div id="trail"><div id="trail"><div id="trail"><a href="http://localhost/cms">Home</a></div> &gt; 
<a href="http://localhost/cms/dennis/">Persoonlijk</a></div> &gt; 
<a href="http://localhost/cms/dennis/cv/">CV</a></div>


Je gooit de <div id="trail"> namelijk altijd voor de output. Als je slechts 1 div wilt hebben kun je de div buiten de functie toevoegen of enkel aan het eind als je op diepte 0 zit

Dus zoiets

code:
1
2
3
4
  if ($depth == 0) 
    $output = '<div id="trail">'.$output.'</div>';  

  return $output;
Pagina: 1