webForumDet fria alternativet

Rekursiv funktion, alternerande rader

PHP

2 svar · 2 249 visningar · startad av MickeA.com

Medlem sedan feb. 20034 441 inlägg
Frågan#1

Tja,

Håller på att bli tokig... Skriver ut en tabell rekurisvt och behöver fixa alternerande rader. Blir fel eftersom funktionen kallar på sig själv mellanåt.

public function OverviewByType($Data, $Type = null, $Depth = 0){
	$Sb = "";

	$Row = <<<EOT
		<tr class="%s">\n
		<td class="ColumnCBox">%d</td>\n
		<td class="ColumnTitle" style="padding-left: %dpx;"><a href="{$Path}content.add.php?Do=Edit&amp;ContentId=%d"><strong>%s</strong></a>%s%s</td>\n
		<td>%s</td>
		<td><a href="%s" title="">%s</a></td>
		<td>%s</td>
		</tr>\n
EOT;
	
	
	$Depth++;
	
	Static $Alt = 0; // <-- 'Static' skulle göra susen läste jag, men fungerar ej.

	foreach($Data as $Item){
		
		$Class = ($Alt%2 == 0 ? "row-odd" : "row-even"); // <-- Här sätts klassen.
		$Sb .= sprintf($Row, $Class);
		$Sb .= $this->OverviewByType($Item['Child'], $Type, $Depth);
		$Alt++;
	}
	return $Sb;
}

Koden ovan är inte helt komplett, men visar det som är viktigt i sammanhanget.

Läste på StackOverflow (http://stackoverflow.com/questions/5473633/php-alternate-row-color-help?answertab=active#tab-top) att det ska räcka med att deklarera alt-variabeln som static men det fungerar inte i mitt fall ovan.

Några förslag på hur man löser det? Jag menar det bör ju gå på något sätt, eller hur?

Tack!

Medlem sedan aug. 20039 340 inlägg
#2

Static? Näe... Det betyder ju att en variabel deklareras en gång för hela klassen istället för separat per objekt. Det bör inte alls göra någon skillnad i ditt fall, så länge allt sker inom ett och samma objekt. Dessutom, att deklarera en variabel som static inuti en funktion, sense it does not make! Variabler i en funktion deklareras ju separat för anrop till funktionen.

Men, så till att lösa ditt problem. Allra helst bör du nog lösa det i ren CSS, typ:

tr.klassnamn:nth-child(even) { ... }
tr.klassnamn:nth-child(odd) { ... }

Men om du inte vill göra detta av någon anledning eller bara är nyfiken på hur man eventuellt kan göra i PHP...

Ett sätt är att deklarera variabeln som en objetvariabel (eller vad det nu heter), dvs ute i klass-scopet, utanför funktionen. (Jag tror man kan göra så i PHP iaf.) Men ska du göra flera körningar så bör du nolla funktionen innan varje ny körning, annars behåller den det sista värdet sen sist. Kanske inte helt optimalt.

$Alt = 0;

public function OverviewByType($Data, $Type = null, $Depth = 0){

Min favorit är nog att passa variabeln som en referens. Med andra ord skickar du runt samma variabel. Typ:

public function OverviewByType($Data, $Type = null, $Depth = 0, &$Alt = 0){ 
    $Sb = ""; 

    $Row = <<<EOT 
        <tr class="%s">\n 
        <td class="ColumnCBox">%d</td>\n 
        <td class="ColumnTitle" style="padding-left: %dpx;"><a href="{$Path}content.add.php?Do=Edit&amp;ContentId=%d"><strong>%s</strong></a>%s%s</td>\n 
        <td>%s</td> 
        <td><a href="%s" title="">%s</a></td> 
        <td>%s</td> 
        </tr>\n 
EOT; 
     
     
    $Depth++; 

    foreach($Data as $Item){ 
        $Class = ($Alt++%2 == 0 ? "row-odd" : "row-even"); // <-- Här sätts klassen. 
        $Sb .= sprintf($Row, $Class); 
        $Sb .= $this->OverviewByType($Item['Child'], $Type, $Depth, $Alt); 
    } 
    return $Sb; 
}

Saker värda att notera med koden ovan.

  1. & betyder att variabeln skickas som referens, alltså att förändringar i anropet bevaras.
  2. "= 0" sätter ett standardvärde som används om det argumentet utelämnas, vilket är användbart för det första anropet. Utan detta skulle man behöva göra en liten krusidull vid det första anropet:
$AltInitial = 0;
$this->OverviewByType($Item['Child'], $Type, $Depth, $AltInitial);

Enbart

$this->OverviewByType($Item['Child'], $Type, $Depth, 0);

Skulle inte fungera eftersom man måste skicka med n variabel, inte bara ett värde.
3) Jag har flyttat på inkrementeringen eftersom det är problematiskt att ha den sist i loopen vid ett rekursivt anrop. Strikt sett behöver du inte använda den kluriga ++ notationen på samma rad som resten av grejerna, utan du kan gott flytta ut $Alt++ till en egen rad.

Men oavsett hur resten av koden ser ut, måste inkrementeringen ske innan det rekursiva anropet. Annars komemr ingen inkrementering ske innan den första raden i ett rekursivt anrop skrivs ut, och på samma sätt kommer två eller fler inkrementeringar ske vid returen.

Medlem sedan feb. 20034 441 inlägg
#3

Grymt, tack!

Dumma mig... Testade tidigare att skicka med Alt-värdet in i funktionen, fast med felen:

  • Glömde &-tecknet fram $Alt = 0.
  • Hade $Alt++; efter det rekursiva anropet.

Det var rätt fram att det blev ett visst antal rader, med olika djup. Nu fungerar dock allt precis som det ska.

Tack!

259 ms totalt · 4 externa anrop · v20260731065814-full.a51de22e
125 ms — deklarationer (db)
0 ms — hämta statistik (cache)
132 ms — hämta tråd, inlägg och bilagor (db)
121 ms — ändringar (db)