Diskuze: Efektivita - Šablonovací systém
V předchozím kvízu, Online test znalostí PHP, jsme si ověřili nabyté zkušenosti z kurzu.
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?
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.
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);
					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.
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);
					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.
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.
Prototype($prototype,$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.
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
					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
					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.
//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
					+20 Zkušeností
+2,50 Kč
						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ěď.
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 
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.
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
*/
					Hodne zajimava stranka, porovnani ruznych php zapisu ruznych funkci, co je
rychlejsi.
http://maettig.com/…nchmarks.php
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)
					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?… 
Zobrazeno 20 zpráv z 20.
				
