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.