EndEffekt: preg_replace - Suchmuster durch globale Variable ersetzen

Frohe Weihnachten,
ich hoffe hier ist trotzdem der ein oder andere hilfbereite Mensch anzutreffen.

Mein Problem sieht folgendermaßen aus:
Ich bastel mir grade etwas ähnliches, wie eine Template-Engine zusammen, dafür muss ich in einem String (, der HTML-Code enthält) nach so einem Gebilde suchen:

{variabler_variablenname}

und selbigen Ausdruck durch eine globale Variable, die diesen Namen trägt, ersetzen; in diesem Beispiel also durch:

$GLOBALS["variabler_variablenname"]

Hab ich mir gedacht, machse dat mir preg_replace()!
Klug wie ich bin, bastel ich mir also den Funktionsaufruf mit entsprechenden Parametern zusammen, der wie folgt aussieht:

$code = preg_replace("/{(.+)}/", $GLOBALS["$1"], $code);

Wär aber zu schön gewesen um auf Anhieb zu funktionieren.
Weiß jemand an dieser Stelle weiter?

(PS: Das Ganze geschieht in einer Funktion, daher muss ich mit $GLOBALS arbeiten)

Vielen Dankeschön schonmal für evtl. Hilfe

  1. Ich würde dir raten eine Callback-Funktion zu verwenden. Das erlaubt dir neben der Variablenschlüsselung sogar noch etwas Fehlerkorrektur: preg_replace_callback()

    1. Ich würde dir raten eine Callback-Funktion zu verwenden. Das erlaubt dir neben der Variablenschlüsselung sogar noch etwas Fehlerkorrektur: preg_replace_callback()

      Du bist göttlich - es funktioniert!!!

      Vielen vielen Dank =)

  2. (Hallo|Hi(ho)|Tag) EndEffekt,

    Frohe Weihnachten,
    ich hoffe hier ist trotzdem der ein oder andere hilfbereite Mensch anzutreffen.

    Ich hab das alljährliche Familien-Ritual schon hinter mir ...

    Mein Problem sieht folgendermaßen aus:
    Ich bastel mir grade etwas ähnliches, wie eine Template-Engine zusammen, dafür muss ich in einem String (, der HTML-Code enthält) nach so einem Gebilde suchen:

    {variabler_variablenname}

    und selbigen Ausdruck durch eine globale Variable, die diesen Namen trägt, ersetzen; in diesem Beispiel also durch:

    $GLOBALS["variabler_variablenname"]

    Hab ich mir gedacht, machse dat mir preg_replace()!
    Klug wie ich bin, bastel ich mir also den Funktionsaufruf mit entsprechenden Parametern zusammen, der wie folgt aussieht:

    $code = preg_replace("/{(.+)}/", $GLOBALS["$1"], $code);

    War nicht so klug ... ;-)
    Wenn du den Inhalt der globalen Variable als Ersetzen-Parameter benötigst, musst du den auch entsprechend einbauen:

      
    $neu = preg_replace('/\{(.+)\}/e', '$GLOBALS["$1"]', $alt);  
    
    

    Der PCRE-Modifikator '/e' sorgt dafür, dass der im Ersetzen-Parameter stehende String als PHP-Code ausgeführt wird (Besser als diese Methode ist hier aber oftmals der Aufruf von preg_replace_callback()).

    Allerdings baust du dir durch diese Vorgehensweise eine Menge Stolperstellen in dein Script ein.

    Was ist, wenn der in deinem Template auftauchende Bezeichner nicht im $GLOBALS-Array vorhanden ist? Diesen Fehler müsstest du abfangen. Und was ist, wenn irgendwer in dein Template "{fuer_dein_Script_ganz_wichtige_variable}" schreibt?

    (PS: Das Ganze geschieht in einer Funktion, daher muss ich mit $GLOBALS arbeiten)

    Hüh? Funktionen in PHP dürfen Parameter übergeben bekommen. Das tut denen gar nicht weh. Vielleicht solltest du dir lieber sowas bauen:

      
    function flat_template_bastelei(  
      $template_src,    // die Template-Datei (die mit den "{...}")  
      $template_array   // das Array, das die Ersetzungen beinhaltet  
    ) {  
      // wir definieren uns eine statische Variable  
      // deren Inhalt merkt sich die Funktion,  
      // sie bleibt also bei jedem Funktionsaufruf gleich  
      static $callback;  
      
      if ( empty($callback) ) {  
        // beim ersten Aufruf weisen wir der statischen Variablen  
        // eine so genannte "anonyme" oder "Lambda-Style"-Funktion  
        // zu  
        $callback = create_function(  
          '$matches // ein Array, das alle Treffer beinhaltet',  
          '  
            // $1 findet sich in $matches[1] ...  
      
            // gibts die Template-Variable überhaupt?  
            if ( !isset( $template_array[ $matches[1] ] ) ) {  
              return $matches[1];  
            }  
            return $template_array[ $matches[1] ]  
          '  
        );  
      }  
      
      return preg_replace_callback(  
        '/\{(.+)\}/',  // dein regulaerer Ausdruck  
        $callback,     // die anonyme Funktion, die aufgerufen wird, wenn  
                       // dein regulaerer Ausdruck "passt"  
        $template_src  
      );  
    }  
    
    

    Guckst du dazu auch ins PHP-Handbuch:

    Statische Variablen in Funktionen
    create_function()
    preg_replace_callback()

    MffG
    EisFuX

    1. (Hallo|Hi(ho)|Tag) EndEffekt,

      Frohe Weihnachten,
      ich hoffe hier ist trotzdem der ein oder andere hilfbereite Mensch anzutreffen.

      Ich hab das alljährliche Familien-Ritual schon hinter mir ...

      Mein Problem sieht folgendermaßen aus:
      Ich bastel mir grade etwas ähnliches, wie eine Template-Engine zusammen, dafür muss ich in einem String (, der HTML-Code enthält) nach so einem Gebilde suchen:

      {variabler_variablenname}

      und selbigen Ausdruck durch eine globale Variable, die diesen Namen trägt, ersetzen; in diesem Beispiel also durch:

      $GLOBALS["variabler_variablenname"]

      Hab ich mir gedacht, machse dat mir preg_replace()!
      Klug wie ich bin, bastel ich mir also den Funktionsaufruf mit entsprechenden Parametern zusammen, der wie folgt aussieht:

      $code = preg_replace("/{(.+)}/", $GLOBALS["$1"], $code);

      War nicht so klug ... ;-)
      Wenn du den Inhalt der globalen Variable als Ersetzen-Parameter benötigst, musst du den auch entsprechend einbauen:

      $neu = preg_replace('/{(.+)}/e', '$GLOBALS["$1"]', $alt);

      
      >   
      > Der PCRE-Modifikator '/e' sorgt dafür, dass der im Ersetzen-Parameter stehende String als PHP-Code ausgeführt wird (Besser als diese Methode ist hier aber oftmals der Aufruf von preg\_replace\_callback()).  
      >   
      > Allerdings baust du dir durch diese Vorgehensweise eine Menge Stolperstellen in dein Script ein.  
      >   
      > Was ist, wenn der in deinem Template auftauchende Bezeichner nicht im $GLOBALS-Array vorhanden ist? Diesen Fehler müsstest du abfangen. Und was ist, wenn irgendwer in dein Template "{fuer\_dein\_Script\_ganz\_wichtige\_variable}" schreibt?  
      >   
      > > (PS: Das Ganze geschieht in einer Funktion, daher muss ich mit $GLOBALS arbeiten)  
      > Hüh? Funktionen in PHP dürfen Parameter übergeben bekommen. Das tut denen gar nicht weh. Vielleicht solltest du dir lieber sowas bauen:  
      >   
      > ~~~php
        
      
      > function flat_template_bastelei(  
      >   $template_src,    // die Template-Datei (die mit den "{...}")  
      >   $template_array   // das Array, das die Ersetzungen beinhaltet  
      > ) {  
      >   // wir definieren uns eine statische Variable  
      >   // deren Inhalt merkt sich die Funktion,  
      >   // sie bleibt also bei jedem Funktionsaufruf gleich  
      >   static $callback;  
      >   
      >   if ( empty($callback) ) {  
      >     // beim ersten Aufruf weisen wir der statischen Variablen  
      >     // eine so genannte "anonyme" oder "Lambda-Style"-Funktion  
      >     // zu  
      >     $callback = create_function(  
      >       '$matches // ein Array, das alle Treffer beinhaltet',  
      >       '  
      >         // $1 findet sich in $matches[1] ...  
      >   
      >         // gibts die Template-Variable überhaupt?  
      >         if ( !isset( $template_array[ $matches[1] ] ) ) {  
      >           return $matches[1];  
      >         }  
      >         return $template_array[ $matches[1] ]  
      >       '  
      >     );  
      >   }  
      >   
      >   return preg_replace_callback(  
      >     '/\{(.+)\}/',  // dein regulaerer Ausdruck  
      >     $callback,     // die anonyme Funktion, die aufgerufen wird, wenn  
      >                    // dein regulaerer Ausdruck "passt"  
      >     $template_src  
      >   );  
      > }  
      > 
      
      

      Guckst du dazu auch ins PHP-Handbuch:

      Statische Variablen in Funktionen
      create_function()
      preg_replace_callback()

      MffG
      EisFuX

      Auch dir vielen Dank.
      Einige sehr nützliche Ratschläge, über die ich mir auch schon zumindestteilweise Gedanken gemacht habe.

      Das Ding soll ja keine vollwertige Template-Engine werden, sondern lediglich auf eine ganz simple Art und Weise HTML von PHP trennen (ich weiß nix anderes macht eine Template-Engine, aber ich will halt was schlichtes - ich erwarte nicht, dass das jetzt irgendwer versteht)

      Nadann mit preg_replace_callback klappts prima!

      Frohe Weihnachten nochmal.

      1. echo $begrüßung;

        Das Ding soll ja keine vollwertige Template-Engine werden, sondern lediglich auf eine ganz simple Art und Weise HTML von PHP trennen

        Das Prinzip sollte sein, die Arbeitsschritte zu trennen:

        EVA - Eingabe, Verarbeitung, Ausgabe

        PHP wurde als in HTML eingebetteter Code erfunden. Nach diesem Prinzip arbeitet es recht effektiv. Wenn du eine mehr oder weniger aufwendige Template-Engine verwenden willst, solltest du dir einen guten Grund überlegen. "Ich trenne das, weil ich mal irgendwo gelesen habe, dass das gut ist" ist kein guter Grund. "Ich trenne das, weil die Templates jemand anderes erstellen soll, der wenig Ahnung von PHP hat" ist schon besser, doch lohnt sich der Aufwand am Ende?

        (ich weiß nix anderes macht eine Template-Engine, aber ich will halt was schlichtes - ich erwarte nicht, dass das jetzt irgendwer versteht)

        Das Folgende ist schlicht und trennt die Verarbeitungsschritte. Nicht abgetrennt sind die zur Ausgabe notwendigen Programmschritte. Wenn du sich wiederholende Strukturen in der Ausgabe haben willst, kannst du schwer auf irgendwelchen Code verzichten, der z.B. ein foreach macht oder die Template-Engine eins ausführen lässt. HTML hat keine Wiederholungslogik. Wie löst du nun dieses Problem, wenn "HTML von PHP getrennt" sein soll? Fügst du statt PHP-Code Template-Engine-Code ein?

        beispiel.php
        ------------

        <?php  
          
        // bei feststehendem Wert kann der <title> natürlich gleich ins Template geschrieben werden.  
        $title = erzeuge_Title();  
          
        $values = Eingabedaten_verarbeiten();  
          
        include 'ausgabe_helfer.php';  
        ?>
        
        <!DOCTYPE ...>  
        <html>  
        <head>  
          <title><?php h($title) ?></title>  
        </head>  
          
        <body>  
          <h1>Überschrift</h1>  
          
          <p>Hier kommen die Daten:</p>  
          
          <?php foreach ($values as $value): ?>  
          <p><?php h($value) ?></p>  
          <?php endforeach ?>  
          
        </body>  
        </html>
        

        ausgabe_helfer.php
        ------------------

        <?php  
        // einige kleine Helferfunktionen für die Ausgabe (für das Beispiel nur eine)  
        function h($string) {  
          echo htmlspecialchars($string);  
        }
        

        echo "$verabschiedung $name";