Pętla foreach w szablonie

Próbuje stworzyć własny, bardzo prosty system szablonów w PHP (głównie żeby czegoś się nauczyć). Zamiana prostych zmiennych działa, ale mam problem ze stworzeniem pętli foreach. Szablon miałby wyglądać tak:

{FOREACH users as user}

{user.name} <br />
{user.surname} <br />

{/FOREACH users}

Teraz mam w mojej klasie funkcję do zamiany tego na coś bardziej czytelnego:

public function replace_loop()
    {
        // Szukanie pętli
        preg_match(
        '#\{FOREACH\s+(\w+)\s+as\s+(\w+)\}(.*)\{\/FOREACH\s+\1}#ms',
        $this->template, $loop);

        /*
        $loop[0] // cały blok do nadpisania
        $loop[1] // nazwa pętli
        $loop[2] // alias zmiennych pętli
        $loop[3] // część środkowa do zamiany
        */

        if ($loop === null)
            return false;

        $result = '';

        foreach($this->variables[$loop[1]] as $$loop[2])
        {
            if(is_object($$loop[2]))
                $replacement = preg_replace('#\{(\w+)(.)(\w+)\}#', '$\1->\3', $loop[3]);

            elseif(is_array($$loop[2]))
                $replacement = preg_replace('#\{(\w+)(.)(\w+)\}#', '$\1[\'\3\']', $loop[3]);

            $result .= "$replacement";

        }
        return $result;

        //Zamiana dalsza
    }

W pętli foreach następuje zamiana zmiennych szablonowych na phpowe. String $replacement wygląda tak:

$user->name <br />
$user->surname <br />

Teraz chciałbym, aby w tym stringu nastąpiło przypisanie wartości obiektu $$loop[2] i dodanie go do wyniku końcowego $result. Ma to robić linijka

 $result .= "$replacement";

czego jednak nie czyni, bo zwracany wynik to:

$user->name <br />
$user->surname <br />    

$user->name <br />
$user->surname <br />

Czy da się to jakoś zrobić, żeby działało tak jakbym chciał, czy raczej należało by to napisać od nowa, bo z tym kodem nie ma szans?

1 rok, 8 miesięcy temu | edytowane przez: Manveru 4224121

  • Możesz wykonać to w prostszy sposób. Podczas parsowania zamień wszystkie tagi {FOREACH} i odwołania do wartości zmiennych na kod stricte PHP. Kilka prostych regexpów i wynikowo mogło by to wyglądać jak poniżej:

    {FOREACH users as user}
    {user.name} <br />
    {user.surname} <br />
    {/FOREACH users}
    

    na: variables['users'] as $user ): ?> name; ?>
    surname; ?>

    Scenariusz wywołania szablonu może wyglądać tak: 1. Wywołujesz w parserze metodę "parseTemplate( $name )". 2. W tej metodzie wyszukujesz pobierasz treść pliku przykładowo "tpls/$name.php". 3. Następnie za pomocą wyrażeń regularnych tagi i konwertujesz je do kodu PHP. 3. Wynikowy kod zapisujesz do pliku, np. "cache/$name.php". 4. Następnie załączasz go funkcją "include" dzięki czemu załączony kod będzie miał dostęp do zmiennej obiektu szablonu "$this" i tym samym do atrybutu "variables".

    Katalog cache pomoże Ci pominąć parsowanie kodu szablonu przy każdym wywołaniu, wystarczy sprawdzić czy plik istnieje.

    Nadmienię, że to najbardziej prosty i toporny sposób, w praktyce jedyne co oferuję Ci taki szablon to zamianę jednej konwencji (tu, "PHP" i jego "< ?php") na magiczne znaczki klamerek. Nie wiem czy jest sens na rozwiązywanie tego w ten sposób. Możes: 1. Popracować nad składnią, by skrócić czas pisania komend "foreach" i innych. 2. Wprowadzić kontekst pętli by nie pisać w niej odwołań "{user.name}", a po prostu "{name}".

    To na dobry początek. System szablonów przede wszystkim powinien rozdzielać warstwę prezentacji. Jednocześnie, gdy w praktyce sam budujesz własny język masz możliwość wprowadzenia instrukcji specyficznych dla kodowania szablonów, np. "{breadcrumbs}", "{list}", "{tree}" i inne, które przyśpieszą w przyszłości pracę nad kodowaniem szablonów. Przede wszystkim musisz w szablonie deklarować "co chcesz zrobić", a nie "jak".

  • Przyznam szczerze, że nie rozumiem, gdzie masz problem. Ale nie mam głowy się w to wgryzać teraz.

    Moja odpowiedź będzie dotyczyć twojego podejścia do szablonów. Realizacja tego zadania na preg_* z zapisanymi wyrażeniami regularnymi w taki sposób, jak to robisz w przykładzie, czyni twój projekt porażką wydajnościową. Nawet jeżeli to prawda, że PRCE w PHP cacheuje wyrażenia i nie rekompiluje ich za każdym razem, to i tak automat analizujący kod twoich szablonów, jest rozłożony i parsuje te same elementy wielokrotnie, co jest marnotrawstwem.

    Nie wiem, czy dla PHP istnieją takie narzędzia, ale twój szablon powinien być parsowany w jednym przebiegu, żeby taki patent funkcjonował wydajnie. Robienie tego w powyższy sposób, to nauka używania śrubokręta do wbijania gwoździ.

  • Ja proponuję Ci podejrzeć jak to jest robione w istniejących już systemach szablonów. Zamiast wyciągać z szablonu zmienne i instrukcje i parsować je za każdym wywołaniem, lepszym roziwiązaniem byłoby sprowadzenie Twojej wersji szablonu do szablonu w postaci czystego php (taka pseudo kompilacja) po czym wykonanie po prostu tego wygenerowanego skryptu. Zaletą takiego rozwiązania byłaby konieczność tylko jednokrotnej "kompilacji" szablonu do postaci czystego PHP, no chyba że Twój szablon uległby zmianie.

Zaloguj się, aby dodać swoją odpowiedź