IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Efektivita - Šablonovací systém

Aktivity
Avatar
Jakub Hýža
Člen
Avatar
Jakub Hýža:13.6.2019 18:22

Zdravím,
Nějak mě přestalo bavit míchat dohromady PHP a HTML, tak jsem si vytvořil jednoduchý šablonovací systém. Stránka je skládaná z malých kousků HTML kódu, které mohou být do sebe vnořené a proměnné se píší ve tvaru {{nazev_promene}}, poté stačí při generování stránky do funkce předat pole s proměnnými. Jediné, čeho se bojím je, zda když na něm postavím webovou stránku, zda nebude způsobovat zpomalení načítání nebo příliš zatěžovat RAM. Můžete prosím posoudit efektivitu mého kódu ? Děkuji.

<?php

function Prototype($prototype,$param = [])
{
        foreach ($param as $key => $value)
        {
                        if (!is_object($value) && !is_array($value))
                                $value = htmlspecialchars($value);
                        $param['{{'.$key.'}}'] = $value;
                        unset($param[$key]);
        }



        if (file_exists('app/prototype/'.$prototype.'.html'))
        {
                $data = file_get_contents('app/prototype/'.$prototype.'.html');
                $data = strtr($data,$param);

                preg_match_all("/\[\[(.*)\]\]/",$data,$matches);
                $sub = [];
                for ($i=0; $i < count($matches[0]); $i++)
                {
                        $args = explode(',',$matches[1][$i]);
                        if (!isset($args[1]))
                                $args[1] = [];
                        else
                                $args[1] = $param['{{'.$args[1].'}}'];

                        if (isset($args[0]))
                                $sub[$matches[0][$i]] = Prototype($args[0],$args[1]);
                }
                $data = strtr($data,$sub);
                return $data;
        }
        else
        {
                Error('Prototype "'.htmlspecialchars($prototype).'" does not exist');
        }
}

function PrototypeArray($prototype,$param = [])
{
        $data = '';
        foreach ($param as $value)
        {
                $data .= Prototype($prototype,$value);
        }
        return $data;
}

function Error($text)
{
        throw new Exception('[CHYBA] -----> '.$text.' <-----');
}
Odpovědět
13.6.2019 18:22
Sleep(); Eat();. Code(); Repeat();
Avatar
Odpovídá na Jakub Hýža
Martin Konečný (pavelco1998):14.6.2019 0:52

Ahoj, jak to pak používáš v praxi? Ta funkce Prototype() při každém zavolání otevírá nějaký soubor a prochází ho regulárním výrazem. A to dělá ještě několikrát v tom for uvnitř. Zdá se mi, že se tam něco děje zbytečně mockrát.

Nebylo by lepší použít již nějaký existující šablonovací systém, jako třeba Smarty nebo Latte?

Nahoru Odpovědět
14.6.2019 0:52
Aktuálně připravuji browser RPG, FB stránka - https://www.facebook.com/AlteiraCZ
Avatar
Jakub Hýža
Člen
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Jakub Hýža:14.6.2019 6:36

Děje se tak neboť jak už jsem psal, šablona se skládá z malých kousků html, které můžou být do sebe vnořené. Funkce prototype načte kus šablony, výplní proměnné, potom vyhledá reference na ostatní kusy html a rekurzivně je doplní.

Díval jsem se na ty šablonování systémy co jsi poslal a Latte vypadá celkem dobře, případně bych ho použil ale i tak bych chtěl prvně zkusit optimalizovat ten svůj.

Nahoru Odpovědět
14.6.2019 6:36
Sleep(); Eat();. Code(); Repeat();
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:14.6.2019 7:37
function pageRender($tpl='', $row = array())
        {
        if (gettype($tpl)==="string" && gettype($row)==="array" && count($row)>0)
                {
                $out  = '';
                $keys = array_keys($row);
                foreach($keys as $key=>$value)
                        {
                        $keys[$key] = "{".$value."}";
                        }
                        $out = str_replace($keys, $row, $tpl);
                return $out;
                }
        return $tpl;
        }

$tpl = "xxx{aaa}yyy"
$arr = array('xxx' => 'neco', 'bbb' => 'necojineho', );
$str = pageRender($tpl, $arr);
var_dump($str);
 
Nahoru Odpovědět
14.6.2019 7:37
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:14.6.2019 7:43

Je fakt, ze to array keys tam neni treba, kdyz tam mam pak nakonec stejne ten cyklus. A zapomenute stredniky a pod si nevsimej.

public function fileLoad ($path='')
        {
        if (file_exists($path))
                {
                return file_get_contents($path);
                }
        return false;
        }

Ale na tom, zda existuje nebo ne, vicemene nezalezi. V podstate, by misto false mohl vratit nejakou error hlasku jako sablonu. A do ni se pak stejne nic nevyrendruje.

 
Nahoru Odpovědět
14.6.2019 7:43
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:14.6.2019 7:51

Ok, tak verze 2, tohle by mohlo byt lepcejsi. Hlavne, ja to treba pouzivam na prepisovani sablon pro inputy, optiony a pod. Takze mi takova jednoducha verze celkem vyhovuje.

function pageRender($tpl='', $row = array())
        {
        if (!(gettype($tpl)==="string" && gettype($items)==="array" && count($items)>0))
                {
                return $tpl;
                }
        $keys = array();
        foreach($items as $key => $value)
                {
                $keys[] = "{".$key."}";
                }
        return str_replace($keys, $items, $tpl);
        }
$tpl = "xxx{aaa}yyy";
$arr = array('xxx' => 'neco', 'bbb' => 'necojineho');
$str = pageRender($tpl, $arr);
var_dump($str);
Editováno 14.6.2019 7:54
 
Nahoru Odpovědět
14.6.2019 7:51
Avatar
Jakub Hýža
Člen
Avatar
Odpovídá na Peter Mlich
Jakub Hýža:14.6.2019 15:13

Děkuji za kód, jen se chci zeptat zda je to opravdu efektivnější než to moje. Jediná výrazná změna co tam vidím oproti mému je použití str_replace místo strtr.

Nahoru Odpovědět
14.6.2019 15:13
Sleep(); Eat();. Code(); Repeat();
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.6.2019 7:54

Souhlasim. Vyzkousej. Pouzij microtime pred a po a nech ho vygenerovat cyklem stovku neceho.
Jenom jsem chtel dat kod, ktery pouzivam ja. Rychlejsi by to mohlo byt spis s regularnimi vyrazy, ale str_replace vyuziva array a to se mi skvele hodilo a nechtelo drbat s kodem.
Samozrejme, kdyz si vysledky stranek nakesujes do nejake slozky jako html a pres .htaccess, kdyz stranka neexistuje, zavolas php, aby ji vytvoril ze systemu, tak zobrazovani bude brnkacka. Ostatne, obvykle editujes stranku pouze pri editaci a pak ji treba 1000x zobrazujes. Takze, pokazde ji generovat pres php neni uplne optimalni reseni, at uz pouzijes rychly kod, jaky chces.

https://php.net/microtime

 
Nahoru Odpovědět
17.6.2019 7:54
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.6.2019 8:00

Prototype($pro­totype,$param = [])
Mimochodem, daval bych promenym realne nazvy. $prototype je vlastne $file_name v te funkci uvnitr, ale ve vnejsi to muze byt jako $prototype_name.
$param se mi take moc nelibi, moc obecne a jako slovo je mi to neprijemne. Ale nenapada mne ted nic vhodneho a obcas to take pouzivam. V podstate by tam mel byt seznam promenych, policek templatu pro vyplneni ($cols? sloupce tabulky db, $opt options v pripade templatu inputu, $fields, $data - data se mi take moc nelibi, moc obecne). Zkratka nevim :) Cili, moje $row je divne a uz nevim, co mne k tomu vedlo, tehdy.

 
Nahoru Odpovědět
17.6.2019 8:00
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.6.2019 10:00

Podle tohoto testu by melo byt strtr rychlejsi. Moc se mi to nezda, ze az 10%. Zkusim nejake vlastni testy, pak mozna napisu.
https://micro-optimization.com/…replace.html

... ten test je uplne naprd. dava mi to pokazde jine vysledky, jak je zrovna zatizene cpu. V podstate je rychlost pro normal string stejna. Jeste zkusim array.

$time = array();

$start = microtime(true);
f1();
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f2();
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f1();
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f2();
$stop = microtime(true);
$time[] = $stop - $start;

array (size=4)
  0 => float 0.25885105133057
  1 => float 0.24769592285156
  2 => float 0.24956798553467
  3 => float 0.24835395812988

array (size=4)
  0 => float 2.4566030502319
  1 => float 2.3781869411469
  2 => float 2.4769570827484
  3 => float 2.3749079704285
Editováno 17.6.2019 10:02
 
Nahoru Odpovědět
17.6.2019 10:00
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.6.2019 10:20

Tak jo, strtr je rychlejsi.

<?php
/* How many times the code under test should run in each function */
define('LOOP', 100000);

$patt  = array (
        '{aaa}',
        '{bbb}',
        '{ccc}'
        );
$repl  = array (
        "Toto je nahrazeny text",
        "jiny",
        "Toto je super dlouhy nahrazeny text  Toto je super dlouhy nahrazeny textToto je super dlouhy nahrazeny text"
        );
$tran  = array(
        $patt[0] => $repl[0],
        $patt[1] => $repl[1],
        $patt[2] => $repl[2]
        );
$patt2 = array(
        '~'.preg_quote($patt[0]).'~',
        '~'.preg_quote($patt[1]).'~',
        '~'.preg_quote($patt[2]).'~'
        );
$tpl = "test{ccc}string_with{bbb}underscores{aaa}";

function f1($tpl, $tran) {
  for($i=0; $i<LOOP; ++$i) {
    $new_string = strtr($tpl, $tran);
  }
}
function f2($tpl, $patt, $repl) {
  for($i=0; $i<LOOP; ++$i) {
    $new_string = str_replace($patt, $repl, $tpl);
  }
}
function f3($tpl, $patt, $repl) {
  for($i=0; $i<LOOP; ++$i) {
    $new_string = preg_replace($patt, $repl, $tpl);
  }
}

$time = array();

$start = microtime(true);
f1($tpl, $tran);
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f2($tpl, $patt, $repl);
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f3($tpl, $patt2, $repl);
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f1($tpl, $tran);
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f2($tpl, $patt, $repl);
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f3($tpl, $patt2, $repl);
$stop = microtime(true);
$time[] = $stop - $start;

var_dump($time);

array (size=6)
  0 => float 2.6462559700012
  1 => float 3.0645799636841
  2 => float 3.4305038452148
  3 => float 2.6600260734558
  4 => float 3.1398329734802
  5 => float 3.4548649787903
 
Nahoru Odpovědět
17.6.2019 10:20
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.6.2019 12:20

Jeste jsem premyslel tak, ze sice strtr dokaze pracovat i s array, ale musis mu tu array pripravit. Coz obnasi vlastne tu array duplikovat nebo pres set unset modifikovat. A kdyz je value dlouhy text, tak zbytecne zahazujes z pameti ten text.

Asi s tim budu jeste chvili experimentovat.

 
Nahoru Odpovědět
17.6.2019 12:20
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.6.2019 12:44
//define('LOOP', 10000);
$tran3  = array(
        'aaa' => $repl[0],
        'bbb' => $repl[1],
        'ccc' => $repl[2]
        );

function f4($tpl, $items_in)
        {
  for($i=0; $i<LOOP; ++$i) {
        $items = $items_in;
        foreach($items as $key => $value)
                {
//              $keys[] = "{".$key."}";
                $items["{".$key."}"] = $value;
                unset($items[$key]);
                }
        $new_string = strtr($tpl, $items);
        }
        }

function f5($tpl_in, $items)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        foreach($items as $key => $value)
                {
                $new_string = strtr($new_string, "{".$key."}", $value);
                }
}
echo $new_string;
        }

//var_dump ($tran);

$start = microtime(true);
f1($tpl, $tran);
$stop = microtime(true);
$time[] = $stop - $start;


$start = microtime(true);
f4($tpl, $tran3);
$stop = microtime(true);
$time[] = $stop - $start;

$start = microtime(true);
f5($tpl, $tran3);
$stop = microtime(true);
$time[] = $stop - $start;

var_dump($time);

array (size=3)
  0 => float 0.02535605430603 // puvodni priklad strtr, ktery nemusi tesit pridavani znaku '{' '}'
  1 => float 0.05734395980835 // unset
  2 => float 0.09029483795166 // opakovane prochazeni
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
 
Nahoru Odpovědět
17.6.2019 12:44
Avatar
Jakub Hýža
Člen
Avatar
Odpovídá na Peter Mlich
Jakub Hýža:17.6.2019 15:24

Nakonec jsem v tom projektu, který dělám použil šablonovací systém Latte, který převede šablonu na PHP soubor a ten poté dále používá a na produkčním se dá vypnout přegenerování (což je velice zajímavý princip co bych mohl použít). Každopádně ten svůj systém bych chtěl dodělat a používat. Tobě Peter Mlich děkuji za tvůj čas a označím tě jako správnou odpověď.

Nahoru Odpovědět
17.6.2019 15:24
Sleep(); Eat();. Code(); Repeat();
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:18.6.2019 7:52

Jak chces. Nedelam to pro slavu, ale, protoze mne to bavi. A chtel jsi vedet totez, co zajimalo i mne. Svuj kod se str_replace jsem prepsal na strtr, aby byl rychlejsi a je to znat, protoze renderovani stranky tam pouzivam casto. Cili, dik i tobe :)

 
Nahoru Odpovědět
18.6.2019 7:52
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:16.7.2019 15:25

mimochodem, narazil jsem na jeden takovy, dalo by se rici, i bug strtr

$tpl    = '{content}';
$items2 = array(
'{content}'      => 'xx {content_list} yy',
'{content_list}' => 'test'
);
//if ($key=='content_list') var_dump($tpl, $items);
echo strtr($tpl, $items2);

On uz nekontroluje, zda ve vlozenem obsahu muze neco nahradit. Takze pro sablonovaci system, ac rychlejsi, tak nepouzitelne.

 
Nahoru Odpovědět
16.7.2019 15:25
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17.7.2019 9:52

Nove testy mi vychazeji vyhodnejsi pro str_replace, at uz jakekoliv reseni:

<?php

function f1($tpl_in, $tran) {
$new_string = $tpl_in;
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
    $new_string = strtr($new_string, $tran);    // pozor, pokud je $value dalsi sablona, cili {aaa} => '{bbb}', tak se neprepise!
  }
echo $new_string.'1<br>';
}

function f2($tpl_in, $patt, $repl) {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
    $new_string = str_replace($patt, $repl, $new_string);
  }
echo $new_string.'2<br>';
}

function f3($tpl_in, $patt, $repl) {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
    $new_string = preg_replace($patt, $repl, $new_string);
  }
echo $new_string.'3<br>';
}

function f4($tpl_in, $items_in)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        $items = $items_in;
        foreach($items as $key => $value)
                {
//              $keys[] = "{".$key."}";
                $items["{".$key."}"] = $value;
                unset($items[$key]);
                }
        $new_string = strtr($new_string, $items);
        }
echo $new_string.'4<br>';
        }

function f5_render($tpl_in, $items)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        foreach($items as $key => $value)
                {
                $new_string = strtr($new_string, "{".$key."}", $value);
                }
}
echo htmlspecialchars($new_string).'5 - single byte to other byte<br>';
        }

function f6_render($tpl_in, $items)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        foreach($items as $key => $value)
                {
                $new_string = str_replace("{".$key."}", $value, $new_string);
                }
}
echo $new_string.'6<br>';
        }

function f7_render($tpl_in, $items)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        $keys = array();
        foreach($items as $key => $value)
                {
                $keys[] = "{".$key."}";
                }
        $new_string = str_replace($keys, $items, $new_string);
}
echo $new_string.'7<br>';
        }


function f8_render($tpl_in, $items)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        $keys = array_keys($items);
        foreach($keys as $key => $value)
                {
                $keys[$key] = "{".$value."}";
                }
        $new_string = str_replace($keys, $items, $new_string);
}
echo $new_string.'8<br>';
        }

function f9_render($tpl_in, $repl)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        $patt = array();
        foreach($repl as $key => $value)
                {
                $patt[] = '~'.preg_quote("{".$key."}").'~';
                }
        $new_string = preg_replace($patt, $repl, $tpl_in);
}
echo $new_string.'9<br>';
        }

function f10_render($tpl_in, $items)
        {
  for($i=0; $i<LOOP; ++$i) {
$new_string = $tpl_in;
        foreach($items as $key => $value)
                {
                $arr = array("{".$key."}" => $value);
                $new_string = strtr($new_string, $arr);
                }
}
echo $new_string.'10<br>';
        }



$tpl = "test {ccc} string_with {bbb} underscores {aaa}";
$patt  = array (
        '{aaa}',
        '{bbb}',
        '{ccc}'
        );
$repl  = array (
        "<span style='color:blue'>#Toto je nahrazeny text. <b>{bbb}</b></span>",
        "<span style='color:red'>#jiny text.</span>",
        "<span style='color:green'> <b>{aaa}</b>Toto je super dlouhy nahrazeny text. Toto je super dlouhy nahrazeny text. Toto je super dlouhy nahrazeny text.</span>"
        );
$tran  = array(
        $patt[0] => $repl[0],
        $patt[1] => $repl[1],
        $patt[2] => $repl[2]
        );
$patt2 = array(
        '~'.preg_quote($patt[0]).'~',
        '~'.preg_quote($patt[1]).'~',
        '~'.preg_quote($patt[2]).'~'
        );
$tran3  = array(
        'aaa' => $repl[0],
        'bbb' => $repl[1],
        'ccc' => $repl[2]
        );


define('LOOP', 10000);
$time = array();


$start = microtime(true);
f1($tpl, $tran);
$stop = microtime(true);
$time[1] = $stop - $start;

$start = microtime(true);
f2($tpl, $patt, $repl);
$stop = microtime(true);
$time[2] = $stop - $start;

$start = microtime(true);
f3($tpl, $patt2, $repl);
$stop = microtime(true);
$time[3] = $stop - $start;

$start = microtime(true);
f4($tpl, $tran3);
$stop = microtime(true);
$time[4] = $stop - $start;


$start = microtime(true);
f5_render($tpl, $tran3);
$stop = microtime(true);
$time[5] = $stop - $start;

$start = microtime(true);
f6_render($tpl, $tran3);
$stop = microtime(true);
$time[6] = $stop - $start;

$start = microtime(true);
f7_render($tpl, $tran3);
$stop = microtime(true);
$time[7] = $stop - $start;

$start = microtime(true);
f8_render($tpl, $tran3);
$stop = microtime(true);
$time[8] = $stop - $start;

$start = microtime(true);
f9_render($tpl, $tran3);
$stop = microtime(true);
$time[9] = $stop - $start;

$start = microtime(true);
f10_render($tpl, $tran3);
$stop = microtime(true);
$time[10] = $stop - $start;

foreach($time as $key=>$value)
        {
        $time[$key] = floor($value * 1000);
        }
var_dump($time);

/*
array (size=10)
  1 => float 29
  2 => float 37
  3 => float 42
  4 => float 61
  5 => float 87 // s upravou pro renderovani
  6 => float 90
  7 => float 60
  8 => float 78
  9 => float 127
  10 => float 100
*/
 
Nahoru Odpovědět
17.7.2019 9:52
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:19.7.2019 9:14

Hodne zajimava stranka, porovnani ruznych php zapisu ruznych funkci, co je rychlejsi.
http://maettig.com/…nchmarks.php

 
Nahoru Odpovědět
19.7.2019 9:14
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:19.7.2019 9:50

A zajimave je, ze mam rozdilne vysledky na serveru a jine na localhost. Je tam sice jine php, ale je to celkem zarazejici, ze str_replace je o tolik rychlejsi.

https://mlich.zam.slu.cz/…st_strtr.php
https://mlich.zam.slu.cz/…st_strtr.txt

localhost              server
array (size=10)        array(15) {
  1 => float 29          [1]=>  float(70)
  2 => float 37          [2]=>  float(10)
  3 => float 42          [3]=>  float(35)
  4 => float 61          [4]=>  float(76)
  5 => float 87          [5]=>  float(17)
  6 => float 90          [6]=>  float(17)
  7 => float 60          [11]=>  float(209)
  8 => float 78          [10]=>  float(43)
  9 => float 127         [7]=>  float(18)
  10 => float 100        [9]=>  float(46)
                         [8]=>  float(20)
                         [12]=>  float(75)
                         [13]=>  float(23)
                         [14]=>  float(221)
                         [15]=>  float(46)
 
Nahoru Odpovědět
19.7.2019 9:50
Avatar
Jindřich Máca
Tvůrce
Avatar
Odpovídá na Peter Mlich
Jindřich Máca:19.7.2019 10:18

To je docela pochopitelné, protože z verze 5 na 7 je obrovský rozdíl výkonu a mezi jednotlivými sedmičkovými verzemi (7.1, 7.2, 7.3) je také značný rozdíl, jelikož výkon a optimalizace byli jedny z hlavní cílů vývoje za poslední roky. Více ve videu od tvůrce PHP - https://www.youtube.com/watch?… ;)

 
Nahoru Odpovědět
19.7.2019 10:18
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 20 zpráv z 20.