Vogelhaus Walter: Verwirrung um PHP Output Buffer

Hallo,

Ich habe eine Frage bezüglich des PHP Output Buffers:

Im php.net Manual findet sich unter ob_get_clean: Get current buffer contents and delete current output buffer

Im php.net Manual findet sich unter ob_clean: Clean (erase) the output buffer

Im php.net Manual findet sich unter ob_end_clean: Clean (erase) the output buffer and turn off output buffering

Wenn ich nach ob_get_clean ein ob_end_clean setze, bekomme ich die Meldung

// Notice: ob_end_clean(): Failed to delete buffer. No buffer to delete in D:\XAMPP\htdocs\php-templating-engine\home.php on line 14

Wie "drehe" ich nach ob_get_clean den Buffer also wieder "ab"?

Oder wird der Buffer mit ob_clean zwar gesäubert aber bleibt bestehen, während ob_get_clean den Buffer säubert UND vernichtet?

Geht also ob_get_clean tatsächlich weiter als ob_clean??

Dank euch recht! Der Vogl

  1. Hallo Vogl,

    die Output-Buffer in PHP bilden einen Stapel. Mit ob_start wird eine neue Schicht auf diesen Stapel draufgelegt, und zum Entfernen dieser Schicht gibt's ein paar Varianten.

    Eine Basisschicht ist immer da, die muss man nicht starten und die kann man auch nicht beenden. Das ist die „normale Ausgabe“, wo jeder echo direkt gesendet wird.

    Üblicherweise entfernst Du eine Schicht mit ob_end_flush(), damit wird das, was in der aktuellen Schicht zwischengespeichert wurde, in darunter liegende Schicht kopiert und dann aktuelle Schicht X entfernt.

    Aber das ist nicht unbedingt das, was Du willst. Deshalb gibt es Varianten, die sich darin unterscheiden, ob sie
    (A) Die aktive Pufferschicht entfernen (beinhaltet automatisch B)
    (B) Den aktuellen Inhalt des Puffers löschen
    (C) Den aktuellen Inhalt des Puffers an die darunterliegende Schicht senden
    (D) Den aktuellen Inhalt des Puffers als String zurückgeben

    ob_end_flush()
    Umfasst demnach C und A.
    ob_end_clean()
    A - entfernt einfach nur die oberste Schicht, ohne etwas auszugeben. Das machst Du dann, wenn Du „auf Verdacht“ etwas ausgegeben hast, weil Du nicht wusstest, ob Du überhaupt was ausgeben musst. Ich würde behaupten, dass man ob_end_clean jederzeit vermeiden kann, wenn man sein Programm etwas besser strukturiert.
    ob_clean()
    B - Entfernt die oberste Schicht nicht, aber leert ihren Inhalt. Das ist vermutlich die etwas fixere Alternative zu ob_end_clean(), direkt gefolgt von ob_start().
    ob_flush()
    C und B - Sendet den Pufferinhalt an die darunterliegende Schicht und löscht ihn dann. Der Puffer bleibt aktiv.
    ob_get_clean()
    D und A - Der Pufferinhalt wird Dir als String zurückgegeben und die aktuelle Pufferschicht entfernt.
    ob_get_contents()
    D - Du bekommst den aktuellen Pufferinhalt, aber der Puffer wird weder gelöscht noch entfernt.
    ob_get_flush()
    Hier bin ich nicht ganz sicher, aber es müsste D und C sein, gefolgt von A. Der Puffer wird ausgegeben und Du bekommst eine Kopie der Ausgabe als String. Danach wird der Puffer gelöscht.

    Wenn ich nach ob_get_clean ein ob_end_clean setze, bekomme ich die Meldung
    // Notice: ob_end_clean(): Failed to delete buffer. No buffer to delete

    Das sollte jetzt verständlich sein. Beide Funktionen entfernen den obersten Puffer, und wenn Du nur einen gestartet hast, kannst Du auch nur einen entfernen.

    Wie "drehe" ich nach ob_get_clean den Buffer also wieder "ab"?

    Gar nicht. Die Funktion hat ihn schon abgedreht.

    Rolf

    --
    sumpsi - posui - obstruxi
    1. Hello,

      die Output-Buffer in PHP bilden einen Stapel. Mit ob_start wird eine neue Schicht auf diesen Stapel draufgelegt, und zum Entfernen dieser Schicht gibt's ein paar Varianten.

      Eine Basisschicht ist immer da, die muss man nicht starten und die kann man auch nicht beenden. Das ist die „normale Ausgabe“, wo jeder echo direkt gesendet wird.

      Üblicherweise entfernst Du eine Schicht mit ob_end_flush(), damit wird das, was in der aktuellen Schicht zwischengespeichert wurde, in darunter liegende Schicht kopiert und dann aktuelle Schicht X entfernt.

      Aber das ist nicht unbedingt das, was Du willst. Deshalb gibt es Varianten, die sich darin unterscheiden, ob sie
      (A) Die aktive Pufferschicht entfernen (beinhaltet automatisch B)
      (B) Den aktuellen Inhalt des Puffers löschen
      (C) Den aktuellen Inhalt des Puffers an die darunterliegende Schicht senden
      (D) Den aktuellen Inhalt des Puffers als String zurückgeben

      ob_end_flush()
      Umfasst demnach C und A.
      ob_end_clean()
      A - entfernt einfach nur die oberste Schicht, ohne etwas auszugeben. Das machst Du dann, wenn Du „auf Verdacht“ etwas ausgegeben hast, weil Du nicht wusstest, ob Du überhaupt was ausgeben musst. Ich würde behaupten, dass man ob_end_clean jederzeit vermeiden kann, wenn man sein Programm etwas besser strukturiert.
      ob_clean()
      B - Entfernt die oberste Schicht nicht, aber leert ihren Inhalt. Das ist vermutlich die etwas fixere Alternative zu ob_end_clean(), direkt gefolgt von ob_start().
      ob_flush()
      C und B - Sendet den Pufferinhalt an die darunterliegende Schicht und löscht ihn dann. Der Puffer bleibt aktiv.
      ob_get_clean()
      D und A - Der Pufferinhalt wird Dir als String zurückgegeben und die aktuelle Pufferschicht entfernt.
      ob_get_contents()
      D - Du bekommst den aktuellen Pufferinhalt, aber der Puffer wird weder gelöscht noch entfernt.
      ob_get_flush()
      Hier bin ich nicht ganz sicher, aber es müsste D und C sein, gefolgt von A. Der Puffer wird ausgegeben und Du bekommst eine Kopie der Ausgabe als String. Danach wird der Puffer gelöscht.

      Wenn ich nach ob_get_clean ein ob_end_clean setze, bekomme ich die Meldung
      // Notice: ob_end_clean(): Failed to delete buffer. No buffer to delete

      Das sollte jetzt verständlich sein. Beide Funktionen entfernen den obersten Puffer, und wenn Du nur einen gestartet hast, kannst Du auch nur einen entfernen.

      Wie "drehe" ich nach ob_get_clean den Buffer also wieder "ab"?

      Gar nicht. Die Funktion hat ihn schon abgedreht.

      und mit ob_get_level() kann man vorher fragen, ob überhaupt noch eine Buffer-Schicht vorhanden ist.

      Irgendwann mal hat PHP per default das Output-Buffering eingeschaltet. Das hat zu Irritationen geführt.

      In meinen Ergänzungsskripten habe ich daher am Anfang immer eine Schleife eingebaut, wenn ich keinen Buffer wollte.

      
        while(ob_get_level() > 0)
        {
           ob_end_clean();
        }
      
      

      Glück Auf
      Tom vom Berg

      --
      Es gibt soviel Sonne, nutzen wir sie.
      www.Solar-Harz.de
      S☼nnige Grüße aus dem Oberharz
      1. Hallo Tom,

        Bitte verwende „ Antwort mit Zitat verfassen“ nur, wenn es nötig ist.

        Dass PHP das Buffering per Default einschaltet, ist schon ein böser breaking change. Das ist hoffentlich schon 20 Jahre her.

        Rolf

        --
        sumpsi - posui - obstruxi
        1. Hello,

          Bitte verwende „ Antwort mit Zitat verfassen“ nur, wenn es nötig ist.

          Ich wollte gerne, dass alles in einem Posting gesammelt steht. Dafür ist "Antort mit Zitat" ein probates Mittel :-)

          Dass PHP das Buffering per Default einschaltet, ist schon ein böser breaking change. Das ist hoffentlich schon 20 Jahre her.

          Müsste ich im Archiv mal nachschauen. Das hatte ich damals entdeckt, als immer wieder Leute gefragt haben, wie sie Ausgaben zeilenweise machen könnten, bzw. warum das nicht mehr geht.

          Zwanzig Jahre ist das bestimmt noch nicht her. Irgendwann bei einem frühen PHP-5-Release möchte ich raten.

          Glück Auf
          Tom vom Berg

          --
          Es gibt soviel Sonne, nutzen wir sie.
          www.Solar-Harz.de
          S☼nnige Grüße aus dem Oberharz
          1. Hallo TS,

            Ich wollte gerne, dass alles in einem Posting gesammelt steht. Dafür ist "Antort mit Zitat" ein probates Mittel :-)

            Und unerwünscht. Lies die Charta. Das Forum hat dafür die Threadverkettung.

            Rolf

            --
            sumpsi - posui - obstruxi
            1. Hello,

              dazu kann ich nichts finden. Hilfst Du mir bitte mal?

              Ich fand nur etwas über "bitte keine zu allgemeinen Antworten posten" und über "selbsternannte Forumspolizisten".

              Über Zitate und Quotes fand ich gar nichts.

              Und die Charta überhaupt zu finden, ist leider auch Detektivarbeit, zumindest, wenn man angemeldet ist.

              Glück Auf
              Tom vom Berg

              --
              Es gibt soviel Sonne, nutzen wir sie.
              www.Solar-Harz.de
              S☼nnige Grüße aus dem Oberharz
              1. n'Abend,

                dazu kann ich nichts finden. Hilfst Du mir bitte mal?

                ich bin mir ziemlich sicher, dass wir früher msl den Appell "Bitte keine Fullquotes" in der Charta hatten. Finde ich aber gerade auch nicht mehr. Keine Ahnung, wann oder warum dasd rausgefallen ist.

                Und die Charta überhaupt zu finden, ist leider auch Detektivarbeit, zumindest, wenn man angemeldet ist.

                Rechts oben auf "Hilfe", von da aus ist die Charta prominent verlinkt.

                Einen schönen Tag noch
                 Martin

                --
                Im Englischen hat eine Katze neun Leben. Im Deutschen vielleicht auch, aber nach Abzug der Steuern bleiben nur noch sieben übrig.
          2. Hello,

            Zwanzig Jahre ist das bestimmt noch nicht her. Irgendwann bei einem frühen PHP-5-Release möchte ich raten.

            Ich habe leider nichts offizielles dazu gefunden, aber im Web fingen vor ca. 12 Jahren und 4 Monaten die Meldungen zu den Irritationen an. Und ich erinnere mich daran, im Forum einen Dialog mit Dedlfix dazu gehabt zu haben, der mir nicht glauben wollte, weil im Manual leider eher das Gegenteil stand.

            Und es war nicht die Einstellung "output buffer ON", sondern unabhängig davon eben immer sofort eine Ebene Buffer eingeschaltet.

            Also war das ca. Ende 2010. Das wäre dann ungefähr der Umstieg auf PHP 5.2.x oder PHP 5.3.x.

            Wenn man es genauer wissen will bei den letzten produktiv laufenden Releases, würde ich es besser mal ausprobieren. Ich habe aber keine ganz aktuelle Version installiert. Müsste also bitte mal jemand anders machen.

            Glück Auf
            Tom vom Berg

            --
            Es gibt soviel Sonne, nutzen wir sie.
            www.Solar-Harz.de
            S☼nnige Grüße aus dem Oberharz
      2. Danke speziell an Rolf B. und TS für die Ausführungen, jetzt macht so einiges Sinn (finde da die offiziellen DOCs doch ein wenig kryptisch)!

        Was sind Usecases für das Anlegen mehrerer "Pufferschichten" / ob_starts?

        Wenn ich mit ob_get_clean die Inhalte in einer Variable speichere, kann ein und dieselbe die "Schicht" dann ja sozusagen sowieso wieder neu befüllt werden...?