Seite 1 von 1

Rekursive Funktion mit Return

Verfasst: Sa 4. Mai 2019, 10:39
von Faar
Kennt sich jemand mit rekursiven Funktionen aus, die ein return enthalten müssen?
Mein Beispiel:

Code: Alles auswählen

$input = Array aus Contenido Klasse
$level = 2;
function dingens($array, $lev) {
	$level = $lev;
	if( !isset($result)) $result= array();
	foreach($array as $subarray) {
		if($subarray[level] <= $level){
			echo "<br>id ".$subarray[idcat]." level ".$subarray[level];
			$result[] = $subarray;
		}

		if (!empty($subarray[subs])) {
			$result[] = dingens($subcat[subs],$level);
		}
	}
	return $result;
}
$filteredArr = dingens($input,$level);
Das liefert mir im $filteredArr nicht nur alles ab Level 2, 3 oder 4, sondern auch Level 1.
Das zeigt sich auch beim echo, wo auch Level 1 mit angezeigt wird.

Ein Problem bei rekursiven Funktionen ist ja, dass ich nicht einfach das return Array als $result= array(); definieren kann, weil es sonst bei der Rekursion wieder neu initialisiert wird, daher mein Workarround.
Würde ich nur $result[] ohne das verwenden, würde PHP 7.2 wieder meckern.
Und ein Hauptproblem ist das return.
Wohin setzte ich das bei diesem Funktionsaufbau?
Der oben gezeigte scheint mir am ehesten zu funktionieren, denn andere Varianten brachten gar kein Ergebnis oder eben nur den letzten Teil des input Arrays.
Ja, mit array_merge() hatte ich es auch probiert, noch schlimmer. :(

Re: Rekursive Funktion mit Return

Verfasst: Sa 4. Mai 2019, 16:26
von bodil
Hi Faar,
ich verstehe ehrlich nicht so ganz, was du vorhast. Trotzdem zwei Gedanken:
1. Definiere dein $result außerhalb der Funktion ehe du sie das erste mal aufrufst und binde die Variable mit

Code: Alles auswählen

global $result;
ein.
2. Kannst du das Level nicht einfach abfragen, ehe du die Rekursion in der Funktion aufrufst?
Grüße!
Bodil

Re: Rekursive Funktion mit Return

Verfasst: Sa 4. Mai 2019, 17:18
von Faar
bodil hat geschrieben:
Sa 4. Mai 2019, 16:26
Hi Faar,
ich verstehe ehrlich nicht so ganz, was du vorhast.
Darum geht es mir: viewtopic.php?f=117&t=43571
Ich möchte die Kategorien für ein Menü ab einem Level auslesen lassen können, aber generell.
Und ich möchte nicht den ganzen Rattenschwanz an zusätzliche Informationen dran hängen haben, wie Datenbank-Zugangsdaten im Reintext.
Trotzdem zwei Gedanken:
1. Definiere dein $result außerhalb der Funktion ehe du sie das erste mal aufrufst und binde die Variable mit

Code: Alles auswählen

global $result;
ein.
Daran dachte ich auch schon, hab es aber noch nicht ausprobiert. Die Funktion wird ja rekursiv benützt, also ruft sich selbst auf, folglich bindet sie auch dann die Variable wieder ein. Ist sie dann noch mit den ersten Ergebnissen befüllt oder wieder leer?
Da das Array gigantisch ist (siehe Info-Daten-Bockmist oben), fehlt mir buchstäblich der Überblick, ob ich die richtigen Daten habe oder falsche dabei.
Erst wenn keine oder nur ein Datensatz dabei ist, kann man das überschauen.
Du musst dir vorstellen, du willst ja nur paar Kategorien haben und bekommst dann mehrere LKW Ladungen Daten ausgekippt.
So sieht das Array aus.
2. Kannst du das Level nicht einfach abfragen, ehe du die Rekursion in der Funktion aufrufst?
Genau das fehlt in der cCategoryHelper() Klasse, das kann man nicht.
Ich muss also erst gigantische Mengen Daten bekommen und da die simple cat_ID heraus fischen und zu jeder dieser ID einzeln nachfragen, welcher Level das ist. Da widerstrebt mir extrem, weil ich lieber datensparsam programmiere.
In dem verlinkten Artikel frage ich gerade nach einer Möglichkeit, die Klasse zu erweitern, dass man den Level bei der Abfrage gleich mitgeben könnte.
Es liegt in der Datenstruktur der Tabellen vorborgen und ist nicht offensichtlich abfragbar.
Aus Kompatibilität kann man vermutlich die Tabellen nicht anpassen. :?
Vielleicht aber doch... :shock:

Re: Rekursive Funktion mit Return

Verfasst: So 5. Mai 2019, 14:23
von Oldperl
Servus,

dir ist aber schon aufgefallen das

Code: Alles auswählen

if( !isset($result)) $result= array();
dein Ergebnis bezüglich einer Rekursion fälscht. Es wird dort eigentlich nur der 1. Durchgang, ohne die ganze Rekursion, im Return-Array zurück gegeben.

Gruß aus Franken

Ortwin

Re: Rekursive Funktion mit Return

Verfasst: So 5. Mai 2019, 18:53
von Faar
Oldperl hat geschrieben:
So 5. Mai 2019, 14:23
dir ist aber schon aufgefallen das

Code: Alles auswählen

if( !isset($result)) $result= array();
dein Ergebnis bezüglich einer Rekursion fälscht.
Wenn mir was aufgefallen wäre, hätte ich es hier nicht gepostet. :|

Re: Rekursive Funktion mit Return

Verfasst: Di 7. Mai 2019, 07:37
von bodil
Hi Faar!
Sinn einer Variable, die du außerhalb der Funktion festlegst, ist ja, dass du darin die Daten sammeln kannst, die du in der Funktion gewinnst.
Die Level für die einzelnen Kategorien kannst du dir direkt aus der Datenbank holen, auch wenn das nicht wirklich elegant ist. Aber wenn du dir zunächst zu jeder Kategorie das Level in ein Array schreibst, kannst du das ja in deiner Funktion einfach auslesen (vorausgesetzt, du bindest das Array mit global ein.) Die Level stehen in der Tabelle con_cat_tree.
Viel Erfolg!
Bodil

Re: Rekursive Funktion mit Return

Verfasst: Mi 8. Mai 2019, 08:34
von Faar
Hallo Bodil,
eigentlich hänge ich schon am nächsten Problem, weil es nur einen Kategorieast anzeigt aber auf der nächsten Seite mit Subcats schon gar nicht mehr funktioniert. Ich habe den Verdacht, dass da noch etwas anderes nicht stimmt.
Dort geht es auch nicht mehr, dass ich News generell in der Vorlage voreinstelle, sondern ich müsste in jede Seite gehen und alle News extra einstellen.
Und nun erscheint es mir, als ob die "nächste Seite" gar nicht registriert, dass ich in der Vorlage dieses Menümodul drinne habe.
Es ist ja ein Update aus einer ehemaligen 4.6, wie es aus sieht und da kann es durchaus noch Unterschiede zu einer neuen 4.10 Installation geben.
Ich muss das noch weiter testen.
Nur leider drängeln sich jetzt andere Arbeiten dazwischen, so dass ich nicht ständig dran bleiben kann.

Re: Rekursive Funktion mit Return

Verfasst: Mi 15. Mai 2019, 14:51
von Faar
Also, ich habe herausgefunden, dass in dem Artikel auf den Weitergeleitet wurde, weder $idart noch $idcat einen Inhalt haben, sie sind einfach leer.
Folglich kann das Modul auch nicht funktionieren, wenn es die idcat braucht, um auf die rootidcat zu kommen.

Im Artikelbaum im Backend aber wird bei Mouseouver idcat und idart angezeigt, nur für das Modul ist es dann nicht da.
echo $idcat ergibt nichts.
Wo geht das verloren?

Re: Rekursive Funktion mit Return

Verfasst: Do 16. Mai 2019, 10:20
von Faar
Fehler gefunden:
Das Modul content_article_Include überschreibt die globalen Variablen $idcat und $idart mit leerem Inhalt in den Zeilen 202, 203, 258, 259.
Nachfolgende Module haben dann Pech gehabt, weil die globalen $idcat und $idart niemals neu definiert werden dürfen.
Man nimmt immer eine Zwischenvariable, damit genau sowas nicht passiert.

Re: Rekursive Funktion mit Return

Verfasst: Sa 18. Mai 2019, 16:27
von bodil
Genau! Außerdem sollte man

Code: Alles auswählen

cRegistry::getArticleId()
und

Code: Alles auswählen

cRegistry::getCategoryId()
benutzen. :wink:

Re: Rekursive Funktion mit Return

Verfasst: Sa 18. Mai 2019, 18:08
von homtata
....weil die globalen $idcat und $idart niemals neu definiert werden dürfen.
Man nimmt immer eine Zwischenvariable, damit genau sowas nicht passiert.
Nun ist es halt so, dass für die eingesetzten Funktionen rund um eval/ob_get_content die $idart und $idcat usw. für die auszulesende Zielseite als genau diese Variable vorliegen müssen. Daher müssen die Originalwerte zwischen- und zurückgespeichert werden. Es geht nicht anders. Allerdings erfolgt - wie in einem anderen Thread vermerkt - das Zurückschreiben an der falschen Stelle.

Re: Rekursive Funktion mit Return

Verfasst: So 19. Mai 2019, 19:38
von Faar
bodil hat geschrieben:
Sa 18. Mai 2019, 16:27
Genau! Außerdem sollte man

Code: Alles auswählen

cRegistry::getArticleId()
und

Code: Alles auswählen

cRegistry::getCategoryId()
benutzen. :wink:
:?
Hast Du schon mal geschaut, wo die cRegistry diese Daten her holt?

Re: Rekursive Funktion mit Return

Verfasst: Mo 20. Mai 2019, 08:52
von bodil
Hi Faar!
Äh ... nö. Ich hatte da einen Text im Kopf, in dem sinngemäß steht: die Masse an globalen Variablen, die Contenido zur Verfügung stellt, könnte in späteren PHP-Versionen zu Problemen führen, weshalb das Objekt cRegistry erfunden wurde. Bitte benutzen, die globalen Variablen werden mittel- oder langfristig abgeschafft. Wenn cRegistry bisher selbst nur auf globale Variablen zugreift, hilft dir das natürlich nicht.
Da content_article_Include zum Lieferumfang von Contenido gehört, wäre es jetzt vielleicht sinnvoll, deine Erkenntnisse als Bug zu melden, oder? Das Bugfixng hast du ja auch schon ...
Grüße!
Bodil

Re: Rekursive Funktion mit Return

Verfasst: Mo 20. Mai 2019, 12:49
von Faar
Da content_article_Include zum Lieferumfang von Contenido gehört, wäre es jetzt vielleicht sinnvoll, deine Erkenntnisse als Bug zu melden, oder?
Das habe ich schon gemacht und in der nächsten Version könnte es bereinigt sein.
Wir streiten uns noch, ob position:absolute im Modul-Template richtig ist, bei Berechnung mittels offset().
Weil wenn man den Abstand mittels jquery offset() berechnet, und dann mittels "absolute" positioniert, könnte das absolute auf einen anderen Ankerpunkt zugreifen, als auf das Dokument.
Je nachdem, wie das HTML der Webseite aufgebaut ist.
https://www.w3schools.com/css/css_positioning.asp
Denn bei mir schiebt sich das Popup des Moduls ganz nach rechts außerhalb des Bildschirms, weil der Ankerpunkt nicht am linken Rand des Viewports liegt. Irgendwo in dem HTML muss ich also noch ein Position befinden, auf das sich das absolute des Modultemplates bezieht.