Seite 1 von 1

PHP: forech vs. Function oder eine andere Lösung?

Verfasst: 17.07.2015, 15:24
von Coffein
Ich hab eine frage bezüglich der php Performance.

Ich habe eine XML Datei mit etwa 40 Produkten und Produktdetails:

Code: Alles auswählen

<Produkt id="1234">
<Detail_1>abc</Detail_1>
...
<Detail_13>abc</Detail_13>
</Produkt>

...

<Produkt id="2345">
<Detail_1>abc</Detail_1>
...
<Detail_13>abc</Detail_13>
</Produkt>
Nun greife ich die Produktdaten in einer Zentralen php Datei mit foreach ab und speichere diese in einer Variable:

Code: Alles auswählen

foreach&#40; $xml->xpath&#40;"product&#91;@id='1234'&#93;"&#41; as $t &#41; &#123;
$produktname_detail_1 = $t->productdetails->Detail_1;&#125;
...
foreach&#40; $xml->xpath&#40;"product&#91;@id='2345'&#93;"&#41; as $t &#41; &#123;
$produktname_detail_13 = $t->productdetails->Detail_13;&#125;
Per require-once greife ich auf die Variablen zu.

Problem: Es werden sehr viele foreach (ca. 50 - 80) in der Zentralen php Datei erzeugt!
Wie wirkt sich das auf die Leistung aus?
Wird bei jedem Zugriff jede schleife durchlaufen?
Sollte ich lieber Funktionen einsetzten?
Oder führt hier kein weg an einer Datenbank vorbei?

Verfasst:
von

Verfasst: 17.07.2015, 16:01
von Melegrian
Variante A bestünde im Weglassen der Foreach, denn das sollte sich mit XPath auch so ansprechen lassen.
Variante B, eine Function, in der eine Foreach enthalten ist und nur die Funktion aufrufen.
Variant C, Foreach weglassen, dafür XPath in einer Funktion.

ABC ausprobieren, denn beim Testen lernt man es am besten. Ich wüsste es auf Anhieb auch nicht. Was ich aber weiß, dass man mit XPath jeden gewünschten Knoten auch ohne Foreach erreicht. Würde deshalb mit C beginnen.

Verfasst: 17.07.2015, 20:27
von Coffein
Danke für die Antwort :)

Ich habe jetzt folgendes:

Code: Alles auswählen

$xml = simplexml_load_file&#40;dirname&#40;__FILE__&#41;.'/daten.xml'&#41;;

$var = $xml->xpath&#40;"produkt&#91;@id='1234'&#93;->Detail_1"&#41;;
$var hat leider keinen Wert.

Mit foreach funktioniert es.

Verfasst: 17.07.2015, 20:32
von Melegrian
Hier zwei Funktionen, die zweite gefällt mir noch nicht wirklich, doch ich brauche die ja nicht.

Die XML:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8" ?>
<produkte>
  <produkt id="1234">
    <detail_1>abc112</detail_1>
    <detail_2>abc212</detail_2>
    <detail_3>abc312</detail_3>
    <detail_4>abc412</detail_4>
    <detail_5>abc512</detail_5>
  </produkt>
  <produkt id="2345">
    <detail_1>abc123</detail_1>
    <detail_2>abc223</detail_2>
    <detail_3>abc323</detail_3>
    <detail_4>abc423</detail_4>
    <detail_5>abc523</detail_5>
  </produkt>
</produkte>
Werte einzeln ausgeben:

Code: Alles auswählen

<?php
if &#40;file_exists&#40;"a.xml"&#41;&#41; $xml = simplexml_load_file&#40;"a.xml"&#41;;

function leseEinzelDaten&#40;$produkt, $detail&#41; &#123;
    global $xml;
    $res&#91;0&#93; = "";

    $res = $xml->xpath&#40;"//produkt&#91;@id=".$produkt."&#93;/".$detail&#41;;
    return $res&#91;0&#93;;
&#125;

// Einzelnen Wert ausgeben
echo htmlspecialchars&#40;leseEinzelDaten&#40;"1234", "detail_3"&#41;, ENT_QUOTES&#41;;
?>
Alle Werte von einer ID ausgeben:

Code: Alles auswählen

<?php
if &#40;file_exists&#40;"a.xml"&#41;&#41; $xml = simplexml_load_file&#40;"a.xml"&#41;;

function leseProduktDaten&#40;$produkt&#41; &#123;
    global $xml;
    $data = "";

    foreach&#40;$xml->xpath&#40;"//produkt&#91;@id=".$produkt."&#93;"&#41; as $detail&#41; &#123;
        $data .= $detail->detail_1;
        $data .= $detail->detail_2;
        $data .= $detail->detail_3;
        $data .= $detail->detail_4;
        $data .= $detail->detail_5;
    &#125;
    return $data;
&#125;

// Alle Werte von einer ID ausgeben
echo htmlspecialchars&#40;leseProduktDaten&#40;"2345"&#41;, ENT_QUOTES&#41;;
?>

Verfasst: 17.07.2015, 21:11
von Melegrian
Wenn Du eine Schleife benutzen möchtest, ist es eventuell besser, die Ausgabe gleich in der Funktion vorzubereiten.

Code: Alles auswählen

<?php
if &#40;file_exists&#40;"a.xml"&#41;&#41; $xml = simplexml_load_file&#40;"a.xml"&#41;;

function leseProduktDaten&#40;$produkt&#41; &#123;
    global $xml;
    $data = "";

    foreach&#40;$xml->xpath&#40;"//produkt&#91;@id=".$produkt."&#93;"&#41; as $detail&#41; &#123;

        $data .= htmlspecialchars&#40;$detail->detail_1, ENT_QUOTES&#41;."<br>\n";
        $data .= htmlspecialchars&#40;$detail->detail_2, ENT_QUOTES&#41;."<br>\n";
        $data .= htmlspecialchars&#40;$detail->detail_3, ENT_QUOTES&#41;."<br>\n";
        $data .= htmlspecialchars&#40;$detail->detail_4, ENT_QUOTES&#41;."<br>\n";
        $data .= htmlspecialchars&#40;$detail->detail_5, ENT_QUOTES&#41;."<br>\n";
    &#125;
    echo $data;
&#125;

// Funktion aufrufen für 1234
leseProduktDaten&#40;"1234"&#41;;

// Funktion aufrufen für 2345
leseProduktDaten&#40;"2345"&#41;;

?>

Verfasst: 17.07.2015, 21:28
von Coffein
Danke. Das sieht stark nach der perfekten Lösung aus.
Ich werde mich gleich mal dran setzen und berichten :)

Verfasst: 17.07.2015, 21:56
von Melegrian
Langsam gefällt es mir besser mit den Varianten:

Code: Alles auswählen

<?php
if &#40;file_exists&#40;"a.xml"&#41;&#41; $xml = simplexml_load_file&#40;"a.xml"&#41;;

class ProduktDaten &#123;

    public  $xml;
    private $data;

    public function leseDaten&#40;$produkt&#41; &#123;
        $this->data = "<ul>\n";

        foreach&#40;$this->xml->xpath&#40;"//produkt&#91;@id=".$produkt."&#93;"&#41; as $detail&#41; &#123;

            $this->data .= "\t<li>".htmlspecialchars&#40;$detail->detail_1, ENT_QUOTES&#41;."</li>\n".
                           "\t<li>".htmlspecialchars&#40;$detail->detail_2, ENT_QUOTES&#41;."</li>\n".
                           "\t<li>".htmlspecialchars&#40;$detail->detail_3, ENT_QUOTES&#41;."</li>\n".
                           "\t<li>".htmlspecialchars&#40;$detail->detail_4, ENT_QUOTES&#41;."</li>\n".
                           "\t<li>".htmlspecialchars&#40;$detail->detail_5, ENT_QUOTES&#41;."</li>\n";
        &#125;
        $this->data .= "</ul>\n";
        echo $this->data;
    &#125;
&#125;

$ausgabe = new ProduktDaten&#40;&#41;;
$ausgabe->xml = $xml; 

// Ausgabe für 1234
$ausgabe->leseDaten&#40;"1234"&#41;;

// Ausgabe für 2345
$ausgabe->leseDaten&#40;"2345"&#41;;
?>

Verfasst: 17.07.2015, 22:00
von Coffein
Muss am Server etwas für globale Variablen zugelassen werden?

Folgendes funktioniert tadellos:

Code: Alles auswählen

foreach&#40; $xml->xpath&#40;"product&#91;@id='1493'&#93;"&#41; as $t &#41; &#123;
$var = $t->productdetails->kind_productdetails;&#125;

echo '$var';
Das ausgeben der $var erfolgt in einer anderen Datei per require_once().

Das klappt nicht:

Code: Alles auswählen

function preisMin&#40;$id&#41; &#123; 
     global $xml;
     $data = "";
foreach&#40;$xml->xpath&#40;"product&#91;@id='.$id.'&#93;"&#41; as $t&#41; &#123;
$data = $t->productdetails->kind_productdetails;&#125;
     echo $data;
&#125;
Die Datei in der sich die Funktion befindet wird per require_once() von einer anderen Datei wie folgt aufgerufen:

Code: Alles auswählen

<?php preisMin&#40;"1234"&#41;; ?>

Verfasst: 17.07.2015, 23:01
von Coffein
Perfekt.

Die Funktion in der Klasse klappt wunderbar. Und elegant ist es auch noch :)

1000000000000 mal Danke

Verfasst: 18.07.2015, 00:02
von Coffein
Es funktioniert und ich freu mich ein Kind.
Nur noch ne verständnissFrage zu dem Code den ich jetzt nutze.

Code: Alles auswählen

$ausgabe = new ProduktDaten&#40;&#41;; // hier wird die ObjektKlasse initiiert. Verstanden!
Wie nennt sich das folgende bzw. was ist das? Wo kann ich darüber etwas lesen?

Code: Alles auswählen

$ausgabe->xml = $xml;

Verfasst: 18.07.2015, 11:03
von Melegrian
Coffein hat geschrieben:Wie nennt sich das folgende bzw. was ist das? Wo kann ich darüber etwas lesen?

Code: Alles auswählen

$xml = simplexml_load_file ...
Unabhängig von der restlichen Schreibweise ladest Du die XML-File als Objekt, welches nun in der Variablen $xml gespeichert ist.
Dann weist Du den in der Variablen $xml gespeicherten Wert (also der Wert ist das Objekt) der öffentlichen (public) Eigenschaft $xml von der Klasse zu (bzw. dieser Instanz der Klasse zu).

Code: Alles auswählen

$ausgabe->xml = $xml; 
Ob require oder include, beim Pfad sollte vom Arbeitsverzeichnis ausgegangen werden, sonst stimmt zuweilen selbst dirname(__FILE__) oder eine einfache Pfadangabe nicht mehr. So lange die einzubindende Datei sich im selben Verzeichnis oder in einem Unterverzeichnis davon befindet, gibt es kaum Probleme, die könnten aber entstehen, wenn beide Dateien ab Root in unterschiedlichen Verzeichnissen liegen. Arbeitsverzeichnis ist halt immer das, welches zuerst aufgerufen wird und die anderen Dateien einbindet. Schreibe das letzte nur, weil ich mir nicht sicher bin, ob bei der Funktion $xml trotz global leer blieb.