Geek tričko zdarma Geek tričko zdarma
Tričko zdarma! Stačí před dobitím bodů použít kód TRIKO15. Více informací zde
Avatar
Jakub Hýža
Redaktor
Avatar
Jakub Hýža:13. června 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. června 18:22
Sleep(); Eat();. Code(); Repeat();
Avatar
Odpovídá na Jakub Hýža
Martin Konečný (pavelco1998):14. června 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. června 0:52
Aktuálně připravuji browser RPG, FB stránka - https://www.facebook.com/AlteiraCZ
Avatar
Jakub Hýža
Redaktor
Avatar
Odpovídá na Martin Konečný (pavelco1998)
Jakub Hýža:14. června 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. června 6:36
Sleep(); Eat();. Code(); Repeat();
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:14. června 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. června 7:37
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:14. června 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. června 7:43
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:14. června 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. června 7:54
 
Nahoru Odpovědět 14. června 7:51
Avatar
Jakub Hýža
Redaktor
Avatar
Odpovídá na Peter Mlich
Jakub Hýža:14. června 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. června 15:13
Sleep(); Eat();. Code(); Repeat();
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. června 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. června 7:54
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. června 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. června 8:00
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. června 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. června 10:02
 
Nahoru Odpovědět 17. června 10:00
Tento výukový obsah pomáhají rozvíjet následující firmy, které dost možná hledají právě tebe!
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. června 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. června 10:20
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. června 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. června 12:20
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. června 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í
+1 bodů
Řešení problému
 
Nahoru Odpovědět 17. června 12:44
Avatar
Jakub Hýža
Redaktor
Avatar
Odpovídá na Peter Mlich
Jakub Hýža:17. června 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. června 15:24
Sleep(); Eat();. Code(); Repeat();
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:18. června 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. června 7:52
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:16. července 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. července 15:25
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:17. července 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. července 9:52
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:19. července 9:14

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

 
Nahoru Odpovědět 19. července 9:14
Avatar
Peter Mlich
Člen
Avatar
Peter Mlich:19. července 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. července 9:50
Avatar
Jindřich Máca
Tým ITnetwork
Avatar
Odpovídá na Peter Mlich
Jindřich Máca:19. července 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. července 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.