Jak na to v PHP
Transkript
X36 WWW OOP v PHP5 Martin Klíma OOP v PHP 5 Změny oproti PHP 4 – objekty předávány odkazem, nikoli hodnotou – přepsaný OOP model – nové funkce Reference Odkazem – předává se jen ukazatel do paměti Ohodnotou – kopíruje se hodnota dat. struktury <?php class A { var $x = 1; // pricte hodnotu function add($val) { $this->x += $val; } } function zmen_instanci($objekt) { $objekt->add(1); } $instance = new A(); zmen_instanci($instance); echo $a->x . "<br />"; // PHP4: 10 PHP5: 100 ?> oop5/reference.php oop v PHP5 - klonování objektů v php 4 není, klonují se předáváním hodnotou v php 5 speciální metoda Klonování v praxi <?php class A { var $x = 1; } $instance1 = new A(); $instance1->x = 10; $instance2 = clone $instance1; $instance2->x = 20; echo $instance1->x; // 10; echo $instance2->x; // 20; ?> kuk oop5/cloning.php Klonování Zpětná kompatibilita <?php if (version_compare(phpversion(), '5.0') < 0) { eval(' function clone($object) { return $object; } '); } ?> kuk oop5/cloning2.php Klonování Můžeme definovat methodu __clone(), která bude volána při klonování Například můžeme sledovat, zda daný objekt je klon Klonování <?php class A { var $x = 1; var $is_clone = false; function __clone() { $this->is_clone = true; } } $instance1 = new A(); $instance2 = clone $instance1; echo $instance1->is_clone?"inst1 je klon":"inst1 neni klon"; echo $instance2->is_clone?"inst2 je klon":"inst2 neni klon"; ?> kuk oop5/cloning2.php Konstruktor / destruktor V PHP4 má konstruktor stejné jméno jako třída V PHP5 existuje speciální metoda se jménem __costruct() a __destruct() Nicméně PHP5 je zpětně kompatibilní, takže podporuje obojí konstrutor/destruktor <?php // php 4 class A { var $x; function A($hodnota) // konstrutor podle PHP4 { $this->x = $hodnota;} } //php 5 class B { var $x; function __construct($hodnota) // konstrutor podle PHP5 { $this->$hodnota = $hodnota;} } ?> kuk oop5/const_dest.php Konstruktor / destruktor Odvozená třída by měla zavolat konstruktor původní třídy <?php class A { var $x; function A($hodnota) { $this->x = $hodnota; } } class B extends A { function __construct($hodnota) { parrent::__construct($hodnota); } } ?> kuk oop5/const_dest2.php Public, Private, Protected Modifikátory viditelnosti Public – kdokoli může vidět a modifikovat Private – je vidět jen uvnitř třídy Protected – jako private a také z rozšiřujících tříd Vztahuje se na proměnné i metody U proměnných se už nepoužívá klíč. slovo var Ukázka PPP class A { public $x = 1; private $y = 2; protected $z = 3; public function p1() {echo $this->x.$this->y.$this->z;} } class B extends function p2 } $a = new A(); $b = new B(); $a->p1(); $b->p1(); $b->p2(); // ale pozor $b->y = "Y"; // $b->p2(); $a->y = "Y"; // A { () { echo $this->x.$this->y.$this->z;} // y není vidět toto je programatorska chyba toto je chyba kuk oop5/ppp1.php Statické proměnné a metody Klíčové slovo static Bude vyrobena jen jednou pro všechny instance dané třídy Metody nesmí být závislé na proměnných instance Dají se volat přes název třídy trida::metoda(); Statické proměnné a metody <?php class A { protected static $pocitadlo = 0; public static function stavPocitadla() { echo self::$pocitadlo; // self nas oprostuje od $this, tj od instance } public function __construct() { self::$pocitadlo++;} } $a = new A(); $b = new A(); A::stavPocitadla(); // volani staticke metody ?> kuk oop5/static.php Final Třídy a metody mohou být final Třída final nemůže být rozšířena Metoda final nemůže být přetížena v potomkovi Final <?php final class A { function delejNeco() {} } class B extends A {} // fatal error class C { final function foo() {} function bar() {} } class D extends C { function bar() {} } // pretizeni metody bar je OK class E extends A { function foo() {} } // chyba!!! ?> kuk oop5/final.php Konstanty tříd Konstanty spojené s danou třídou …konečně <?php class A { const HOST = "localhost"; const USER = "Franta"; } class B { const HOST = "faraon.felk.cvut.cz"; const USER = "xklima"; } echo A::HOST; echo B::HOST; ?> Nepřímé reference V PHP4 se nedala přímo referencovat metoda nebo proměnná objektu, který byl výsledkem nějakého volání. V PHP5 to jde. Referencing class foo { public $bar = 3; function baz() { echo $this->bar; } } class bar { public $o; function __construct() { $this->o = new foo(); } } $a = new bar(); $a->o->baz(); // 3 echo $a->o->bar; // 3 /* takto postupne musime v PHP4 */ $tmp =& $a->o; $tmp->baz(); echo $tmp->bar; kuk oop5/referencing.php Autoload Jestliže nebude nalezena definice dané třídy, bude jako zavolána funkce __autoload(). Zde se můžeme situaci zachránit. Autoload Soubor definiceA.php <?php class A { public $x = 1; } ?> kuk oop5/definiceA.php Nějaký skript <?php function __autoload($classname) { $classes = array('A' => 'definiceA.php'); include_once($classes[$classname]); } // definici tridy A zatim neni, proto bude zavolana funkce __autoload. $a = new A(); echo $a->x; ?> kuk oop5/autoload.php Dynamické metody Můžeme řešit volání neexistujících metod pomocí metody __call() Této metodě je předáno jmeno a pole argumentů Dynamické metody <?php class math { function __call($name, $args) { switch ($name) { case 'add': return array_sum($args); case 'divide': $val = array_shift($args); foreach ($args as $v) $val /= $v; return $val; } } } $m = new math(); echo $m->add(1,2); // 3 echo $m->divide(8,2); // ?> 4 kuk oop5/dynamic.php Abstraktní třídy a metody Abstraktní metoda definuje jméno a parametry, žádnou implementaci Třída, která má alespoň jednu abstraktní metodu je také abstraktní Hodí se tehdy, když chci skoro všechno udělat za koncového uživatele, jenom nějakou maličkost nechat na něm. Abstraktní metody a třídy Například udělám nákupní košík, který bude umět skoro vše, ale bude nezávislý na použité DB. GenericBasket – add – remove – abstract save – abstract load Definice abstraktní třídy abstract class AbstractBasket { protected $obsah = array(); public function add ($zbozi) { $this->obsah[] = $zbozi; } public function remove ($zbozi) { foreach ($this->obsah as $klic => $polozka) { if ($polozka == $zbozi) unset($this->zboz[$klic]); } } public abstract function load(); public abstract function save(); } Implementace abstraktní třídy class FileBasket extends AbstractBasket { public function load(){ $file = fopen("kosik.txt","r"); $this->obsah = array(); while ($radek = fgets($file)) { $this->obsah[] = $radek; } fclose($file); } public function save() { $file = fopen("kosik.txt","w"); foreach ($this->obsah as $polozka) { fputs($file, $polozka."\r\n"); } fclose($file); } } Použití $kosik0 = new AbstractBasket(); // toto nelze!!! chyba $kosik = new FileBasket(); $kosik->add("Brambory"); $kosik->add("Jablka"); $kosik->save(); $kosik2 = new FileBasket(); $kosik2->load(); var_dump($kosik2); kuk oop5/abstract_basket.php Zpracování chyb v PHP4 a 5 error_reporting() set_error_handler() kuk chyby_4.php <? error_reporting(E_ALL); function my_error_handler ($severity, $msg, $filename, $line_num) { // dostanu info o chybe a muzu si s ni delat co chci echo "Zavaznost: $severity <br>Hlaska: $msg <br> Soubor: $filename <br> Cislo radku: $line_num <br>"; } set_error_handler("my_error_handler"); echo $xxx; ?> Vyjímky v PHP5 Je zde zaveden lepší způsob ošetřování vyjímek. Podobnost s Javou. Jestliže je vygenerována vyjímka (chyba), je vyroben nový objekt. Každá vyjímka je rozšířením třídy Exception. Odvozením nové třídy lze vyrábět vlastní vyjímky. Vyjímky class DevZeroException extends Exception {} class NegativValueException extends Exception {} function deleni ($a, $b) { try { if ($b == 0) throw new DevZeroException(); if ($a<0 || $b<0) throw new NegativValueException(); return $a/$b; } catch (Exception $e) { echo "doslo k nejake vyjimce!!!!"; return false; } // catch (DevZeroException $e) { echo "nulou nelze delit"; // return false;} // catch (NegativValueException $e2) {echo "negative value odchyceno v ramci funkce"; return false;} } deleni(1,2); deleni(1,0); deleni(-1,5); Objekty a Stringy Objekty lze snadno převádět na Stringy Metoda __toString() <?php class foo { public $vals = array('foo', 'bar', 'baz'); function __toString() { return implode(' ', $this->vals); } } $a = new foo(); echo $a; // vytisknw "foo bar baz" ?> Lepší podpora pro XML XML je nutné pro SOAP, SimpleXML, XSL, DOM $xml = '<articles> <article id="1"> <title>Something Happened</title> <author>Random Person</author> </article> <article id="2"> <title>Something Else Happened</title> <author>Different Person</author> </article> </articles>'; /* load & parse XML string */ $art = simplexml_load_string($xml); foreach ($art as $article) { echo 'Id: ' . $article['id']."<br>"; echo 'Title: ' . $article->title."<br>"; echo 'Author: ' . $article->author."<br>"; } kuk oop5/simplexml.php XML – Document Object Model (DOM) $dom = new domDocument('1.0'); $root = $dom->createElement('root'); // vyrobime element foreach (array('foo', 'bar', 'baz') as $v) { $node = $dom->createElement($v); // vyrobime dalsi element $node->appendChild($dom->createTextNode($v)); // vyrobime uzel typu text $root->appendChild($node); // novy element pridame ke koreni } $dom->appendChild($root); // koren priradime k dokumentu $xml = $dom->saveXML(); // vystup XML echo nl2br(htmlspecialchars(str_replace('><', ">\n<", $xml))); <?xml version="1.0"?> <root> <foo>foo</foo> <bar>bar</bar> <baz>baz</baz> </root> Výstup kuk oop5/xmldom.php SQLite – relační databáze V PHP máme k dispozici ralční db Nemusíme jí instalovat, prostě tu je OO rozhraní /* otevri spojeni do databaze v pameti */ $db = new SQLiteDatabase(":memory:"); /* proved dotazy */ $db->query("CREATE TABLE test(a,b)"); $db->query("INSERT INTO test VALUES('1','2')"); /* nacti data */ $r = $db->unbufferedQuery("SELECT * FROM test", SQLITE_ASSOC); echo '<pre>'; /* iteruj vysledek a vytiskni ho */ foreach ($r as $row) { print_r($row); } echo '</pre>'; kuk sqlite/sqlite1.php OBJEKTOVÉ PROGRAMOVACÍ VZORY OOP = změna v myšlení E-shop – uživatel si může přidávat zboží do košíku – chceme mít přehled o množství zboží, celkové ceně, výrobci, názvu, … Implementace bez OOP => kuk (kosik_procedural.php) Implementace pomocí OOP => kuk (kosik_objektovy1.php) Výhody objektového přístupu Mohu mít více košíků, ty si nepřekážejí Jednoduše rozšiřitelné (dědičnost) Kód je mnohem bezpečnější – zapouzdřenost – typová kontrola pomocí Hint Program je mnohem flexibilnější – mohu přidávat různé typy zboží – tisk obsahu košíku (kosik_objektovy1.1.php) = úkol pro Vás Problém: jak vyrobit nový typ zboží Dědičnost – Přidání jenom těch vlastností, které jsou nové – Ostatní je zděděno – Volání konstruktoru mateřské třídy parrent::__construct(….) Polymorfismus – Dvě různé třídy implementují stejné metody s jinou funkcí (metoda display) Statické třídní proměnné a metody Static = patří k celé třídě, nikoli k instanci Co z toho plyne: – Existuje jenom jedna (proměnná || metoda) v systému – Metody nesmí používat standardní proměnné třídy – Metody mohou pracovat používat jen parametricky zadané informace – Klíčové slovo self místo this • this ukazuje na instanci, self ukazuje na třídu Příklad použití statické proměnné Úkol: – kolik bylo v systému vytvořeno instancí košíků? – kuk (kosik_objektovy1.3.php) class BetterBasket extends Basket { protected static $num_of_baskets = 0; public function __construct() { parent::__construct(); self::$num_of_baskets++; } public static function getNumBaskets() { return self::$num_of_baskets; } } Statické metody Dají se volat bez nutnosti vyrobit instanci objektu Vše, co potřebují k životu jsou vstupní parametry kuk (matematika.php) Jen jeden košík v systému? Vzor singleton kuk kosik_objektovy1.4.php class SingletonBasket { private static $single_basket_instance = null; private function __construct() { } public static function getInstance() { if (self::$single_basket_instance == null) { self::$single_basket_instance = new Basket(); } return self::$single_basket_instance; } } Různé typy zboží v košíku Řekněme, že máme 2 zcela různé typy zboží – Knihy – Parní lokomotivy Tyto typu spolu nemají nic společného a proto nemá smysl zavádět dědičnost Řešení? – Zavedeme rozhraní (interface) – Rozhraní je způsob, jak vytvořit vícenásobnou dědičnost Rozhraní (interface) Řekněme, že máme 2 zcela různé typy zboží Knihy Parní lokomotivy Tyto typu spolu nemají nic společného a proto nemá smysl zavádět dědičnost Řešení? Zavedeme rozhraní (interface) Rozhraní je způsob, jak vytvořit vícenásobnou dědičnost Interface pouze předepisuje povinnost implementovat metodu, neimplementuje je sám Myšlenka rozhraní Implements Zboží Kniha Lokomotiva •getID( ) •getPrice( ) •getName( ) •display( ) •getAuthor( ) •getIssueYear( ) •getISBN( ) •getWeight( ) •getWidth( ) •getColor( ) Extends LepsiKniha •getNumPages( ) kuk kosik_objektovy1.5.php Interface Definice rozhraní interface Goods { public function public function public function public function } getID(); getPrice(); getName(); display(); Interface – implementace Book class Book implements Goods { …. zde je nějaká implementace // implementace rozhraní public function getID() { return $this->ID; } public function getName() { return $this->name; } public function getPrice() { return $this->price; } public function display() { echo "ID=".$this->ID.", Název: ".$this->name. ", Cena: ".$this->price.", Autor: ". $this->author.", Rok: ".$this->issue_year; } } Interface – implementace Engine class Engine implements Goods { …. zde je nějaká implementace // implementace rozhraní public function getID() { return $this->ID; } public function getName() { return $this->name; } public function getPrice() { return $this->price; } public function display() { echo "ID=".$this->ID.", Název: ".$this->name. ", Cena: ".$this->price.", Hmotnost: ". $this->weight.", Sirka: ".$this->width.", Barva: ". $this->color; } } Vzor Factory Používá se tehdy, když chceme získat instanci nějakého objektu, ale nechceme se starat o to, jak tento objekt vytvořit Příklad: – chceme přistupovat k databázi – databází je ale mnoho různých druhů (mysql, oracle, …) – všechny db implementují stejné rozhraní Vzor Factory DBLayer •connect($param) •query($sql) Implements PGDBLayer MYSQLDBLayer •connect($param) •query($sql) •connect($param) •query($sql) kuk kosik_objektovy1.5.php Vzor Factory Imp 1 interface DBLayer { public function connect($param); public function query($sql); } class MySQLDBLayer implements DBLayer { public function connect($params) { // mysql_connect(....) } public function query($sql) { // mysql_query(...) } } class PGDBLayer implements DBLayer { public function connect($params) { //pg_connect(....) } public function query($sql) { // pg_query(...) } } Vzor Factory Imp 2 // vzor factory = tovarna na objekty class DBFactory { // zde to prijde! // vim, ze vratim rozhrani typu DBLayer public static function getDBLayer($type){ switch ($type) { case "MySQL": return new MySQLDBLayer(); break; case "PG": return new PGDBLayer(); break; default: return new MySQLDBLayer(); } } } Kombinace factory a singleton? 3. 4. factory.php Každý DB objekt daného typu potřebujeme právě jednou. Nechceme se zabývat tím, jak ho vyrobit. Add 1: signleton Add 2: factory Šablony Martin Klíma Čtryřvrstvá architektura Server Klient Prezentační logika Aplikační Logika Databáze Výhody Jednotlivé vrstvy jsou nezávislé Lze je samostatně spravovat Možnost distribuovaného vývoje Jednodušší design Jak na to v PHP Použití šablon (template) Co šablony dělají Oddělují aplikační kód a prezentační kód Neoddělují jakýkoli kód a html, pouze se snaží tyto dvě logiky separovat. Výhody a nevýhody Výhody – Jednodušší vývoj – Možnost dělby práce – Průhledný a dobře spravovatelný kód – Může být značně rychlé (cache) Nevýhody – Složitý projekt, nutno integrovat více souborů – Aditivní výpočetní výkon – Nutnost parsovat šablony – Nutnost naučit se další skriptovací jazyk Existující enginy Smarty FastTemplate PHPLib ... Můj vlastní? Schopností rychle parsovat Schopností provádět vlastní skriptovací kód Cache Náš dnešní favorit: Smarty Jak to vypadá PHP Skript Aplikační logika POUZE ZDE vlož šablonovací engine vytvož šablonový objekt Template <html> ... <body> <h1>{$nadpis}</h1> uživatelovo jméno: {$jmeno} přiřaď parametry do objektu nahraj a zobraz template (šablonu) </body> </html> Jak to funguje 1. 2. 3. 4. Proveď PHP skript – aplikační logika Vytvoř se Templatovací objekt Tomuto objektu se přiřaď datové struktury z ap. logiky Zavolej metodu display 1. je zapnuta cache? ano-jdi na bod 8 2. ne – existuje přeložená šablona? ano – jdi na bod 5 3. proveď lexikální analýzu šablony 4. expanduj příkazy pseudoskriptu do podoby PHP kódu 5. přeloženou šablonu ulož 6. proveď příkazy pseudoskriptu 7. výsledek ulož do cache (pokud je zapnuta) 8. výsledek zobraz na standardní výstup První úkol: zobraz seznam klientů Předpoklad je, že máme databázi uživatelů. Zobraz jenom jejich seznam Aplikační logika – vytvoří datovou strukturu – pole uživatelů – vytvoří templatovací objekt – přiřadí pole – nechá zobrazit Prezentační logika – definuje, jak toto pole zobrazit Příklad použití SMARTY – příprava <? require('Smarty.class.php'); class T_Template extends Smarty { function T_Template() { $prefix = ''; $this->Smarty(); $this->template_dir = $prefix.'templates/'; $this->compile_dir = $prefix.'templates_c/'; $this->config_dir = $prefix.'configs/'; $this->cache_dir = $prefix.'cache/'; $this->caching = false; $this->assign('app_name','Test'); } Jak vypadá funkce pro načtení pole define("UZIVATEL","session_uzivatel"); define("DB_HOST", "localhost"); define("DB_UZIVATEL", "root"); define("DB_HESLO", “mysql”; define("DB_JMENO", "test"); // vraci vysledek sql dotazu nad db function dotaz ($sql) { mysql_connect(DB_HOST, DB_UZIVATEL,DB_HESLO); mysql_select_db(DB_JMENO); $vysledek = mysql_query($sql); function poleUzivatelu () { $vysledek = array(); // sestav dotaz $dotaz = "SELECT * FROM uzivatel"; // nacti vysledek $sql_vysledek = dotaz($dotaz); // osetreni chyby pri komunikaci s db if (!$sql_vysledek) die("Nepodarilo se spojit s databazi"); // iteruj radky v db while ($radek = mysql_fetch_assoc($sql_vysledek)) { $vysledek[] = $radek; } // vrat pole radku return $vysledek; } ?> Načtem e tabu MySQ l L data ku z báze return $vysledek; } Jak vypadá aplikační logika <? require_once("funkce.inc"); require_once("init_smarty.php"); načtení pole z DB // nacti pole uzivatelu $pole_uzivatelu = poleUzivatelu(); // vytvor sablonu $templatovaci_objekt = & new T_Template(); nový objekt Smarty //prirad data do sablony přiřazení datových $templatovaci_objekt->assign_by_ref("uzivatele", $pole_uzivatelu); struktur // nech to zobrazit $templatovaci_objekt->display('index.tpl'); ?> spuštění procesu zobrazení Jak vypadá template <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1250"> <title>Pokusna sablona</title> </head> <body> <table summary="Seznam uzivatelu db"> {section name=i loop=$uzivatele} <tr> <td>{$uzivatele[i].Jmeno}</td> <td>{$uzivatele[i].Prijmeni}</td> </tr> {/section} </table> </body> Chyba!!! Jak vypadá template - správně <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1250"> <title>Pokusna sablona</title> </head> <body> <table summary="Seznam uzivatelu db"> {section name=i loop=$uzivatele} <tr> <td>{$uzivatele[i].Jmeno|escape:"htmlall"}</td> <td>{$uzivatele[i].Prijmeni|escape:"htmlall"}</td> </tr> {/section} </table> </body> </html> Ochrana proti HTML neplatnému výstupu Nový požadavek – text ve dvou sloupcích PHP kód zůstává beze změny Prezentační logika se mění Modifikovaná prezentační logika Lichá položka? Ano: vlož značku <tr> <table summary="Seznam uzivatelu db"> {section name=i loop=$uzivatele} {if ($smarty.section.i.iteration mod 2) == 1} <tr> {/if} <td>{$uzivatele[i].Jmeno|escape:"htmlall"}</td> <td>{$uzivatele[i].Prijmeni|escape:"htmlall"}</td> Sudá položka? Ano: ukonči značku {if ($smarty.section.i.iteration mod 2) == 0} </tr> </tr> {/if} {/section} Co se stane, když je {if $smarty.section.i.rownum mod 2 == 1} lichý počet položek <td> --- </td> <td> --- </td> </tr> {/if} </table> Výsledek Další požadavek: střídání řádků Řešení: opět čistě jen prezentační logika Prezentační logika – střídání řádků <table summary="Seznam uzivatelu db"> {section name=i loop=$uzivatele} {if ($smarty.section.i.iteration mod 2) == 1} <tr class="{cycle values="lichy, sudy"}"> {/if} <td>{$uzivatele[i].Jmeno|escape:"htmlall"}</td> <td>{$uzivatele[i].Prijmeni|escape:"htmlall"}</td> {if ($smarty.section.i.iteration mod 2) == 0} </tr> {/if} {/section} {if $smarty.section.i.rownum mod 2 == 1} <td> --- </td> <td> --- </td> </tr> {/if} </table> Cyklicky střídá parametry oddělené čárkou Střídání řádků – vložení CSS stylu <title>Pokusny formular</title> <style type="text/css"> tr.lichy { background-color: grey; } tr.sudy { background-color: white; } </style> </head> <table summary="Seznam uzivatelu db"> {section name=i loop=$uzivatele} {if ($smarty.section.i.iteration mod 2) == 1} <tr class="{cycle values="lichy, sudy"}"> {/if} <td>{$uzivatele[i].Jmeno|escape:"htmlall"}</td> <td>{$uzivatele[i].Prijmeni|escape:"htmlall"}</td> {if ($smarty.section.i.iteration mod 2) == 0} </tr> {/if} {/section} {if $smarty.section.i.rownum mod 2 == 1} <td> --- </td> <td> --- </td> </tr> Pozor! Konflikt značek { a } Smarty parser interpretuje tyto značky Střídání řádků – vložení CSS stylu <title>Pokusny formular</title> {literal} <style type="text/css"> tr.lichy { background-color: grey; } tr.sudy { background-color: white; } </style> {/literal} </head> <table summary="Seznam uzivatelu db"> {section name=i loop=$uzivatele} {if ($smarty.section.i.iteration mod 2) == 1} <tr class="{cycle values="lichy, sudy"}"> {/if} <td>{$uzivatele[i].Jmeno|escape:"htmlall"}</td> <td>{$uzivatele[i].Prijmeni|escape:"htmlall"}</td> {if ($smarty.section.i.iteration mod 2) == 0} </tr> {/if} {/section} {if $smarty.section.i.rownum mod 2 == 1} <td> --- </td> <td> --- </td> </tr> Neinterpretuj jako Smarty kód Pozor! Konflikt značek { a } Smarty parser interpretuje tyto značky Vkládání šablon Šablony lze libovolně vnořovat Výhoda: – Řešení elementárních problémů – Elegance – Znovupoužitelnost Nevýhoda: – Více souborů – Problém s cache (může být výhoda) Příklad Vytvořte seznam uživatelů Seznam bude obecný Každá položka v seznamu bude zobrazovat detail uživatele Řešení: aplikační logika zůstává <? require_once("funkce.inc"); require_once("init_smarty.php"); // nacti pole uzivatelu $pole_uzivatelu = poleUzivatelu(); // vytvor sablonu $templatovaci_objekt = & new T_Template(); //prirad data do sablony $templatovaci_objekt->assign_by_ref("uzivatele", $pole_uzivatelu); // nech to zobrazit $templatovaci_objekt->display('index2.tpl'); ?> KUK /smarty2/index2.php Šablona první úrovně – rozložení seznamu <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> Iteruj přes pole <meta http-equiv="content-type" content="text/html; charset=windows-1250"> $uzivatele <title>Pokusny formular</title> aktualni položku prirad do promenne </head> $aktualni_uzivatel <body> {foreach from=$uzivatele item=aktualni_uzivatel} Vlož definici detailu {include file="detail_uzivatele.tpl"} {/foreach} </body> </html> Šablona druhé úrovně – detail Smarty komentář. Je odstraněn při překladu šablony {* v teto sablone predpokladam, ze informace o uzivateli jsou v poli v promenne $aktualni uzivatel*} <hr> <div>Jméno: {$aktualni_uzivatel.Jmeno}</div> <div>Příjmení: {$aktualni_uzivatel.Prijmeni}</div> <div>Logovací jméno: {$aktualni_uzivatel.LogovaciJmeno}</div> Vložená šablona dědí definované proměnné Šablona druhé úrovně – detail {* v teto sablone predpokladam, ze informace o uzivateli jsou Smarty komentář. Je v poli v promenne $aktualni uzivatel*} odstraněn při <hr> překladu šablony <div>Jméno: {$aktualni_uzivatel.Jmeno| escape:"htmlall"}</div> <div>Příjmení: {$aktualni_uzivatel.Prijmeni| escape:"htmlall"}</div> <div>Logovací jméno: {$aktualni_uzivatel.LogovaciJmeno| escape:"htmlall"}</div> Vložená šablona dědí definované proměnné Výsledek Cache Jednou vygenerovaný výsledek může být uložen a použit znovu Výhoda: – Výrazné zrychlení odezvy – Méně dotazů do db Nevýhoda: – Zabírá prostor na disku – Aditivní kód – Uživatel nedostává aktuální data – Delší zpracování stránek, které nejsou v cache Příklad – jen aplikační logika <? require_once("funkce.inc"); require_once("init_smarty.php"); // nacti pole uzivatelu $pole_uzivatelu = poleUzivatelu(); // vytvor sablonu $templatovaci_objekt = & new T_Template(); $templatovaci_objekt->caching = true; Zapni cache Zde NEšetříme čas //prirad data do sablony $templatovaci_objekt->assign_by_ref("uzivatele", $pole_uzivatelu); // nech to zobrazit Zde šetříme čas $templatovaci_objekt->display('index.tpl'); ?> kuk smarty3-caching/index.php Příklad – cache - oprava require_once("funkce.inc"); require_once("init_smarty.php"); // nacti pole uzivatelu $pole_uzivatelu = poleUzivatelu(); // vytvor sablonu $templatovaci_objekt = & new T_Template(); $templatovaci_objekt->caching = true; Zapni cache if ( ! $templatovaci_objekt->is_cached("index.tpl")) { Zde šetříme čas //prirad data do sablony když to lze $templatovaci_objekt->assign_by_ref("uzivatele", $pole_uzivatelu); } // nech to zobrazit $templatovaci_objekt->display('index.tpl'); ?> Zde šetříme čas kuk smarty3-caching/index2.php Debug - ladění Umožňuje zobrazit parametry přiřazené k template objektu. Do těla template stačí napsat značku {debug} Výsledek Filtry Životní cyklus šablony – Prochází řadou filtrů – Před překladem – Po překladu – Po vykonání Prefilter Kompilace Postfilter Display Output filter Prefilter Textový filter, kterým je prohnán template ještě předtím, než je zkompilován Hodí se k odstranění uživatelských komentářů, preprocessing obecně Prefilter Kompilace Postfilter Display Output filter Postfilter Textový filter, kterým je prohnán template poté, co byl zkompilován Hodí se např. k přidání nějaké spec. informace Prefilter Kompilace Postfilter Display Output filter Output filter Textový filter, kterým je prohnán template poté, co byl zkompilován Pracuje tedy nad kompletním výstupem Hodí se např. k zvýraznění některých slov, jejich potlačení, ochrana před vulgaritami atd. Prefilter Kompilace Postfilter Display (fetch) Output filter Jak se filtry používají <? require_once("funkce.inc"); require_once("init_smarty.php"); function muj_output_filter($tpl_output, &$smarty) { // provede nejakou textovou manipulaci a vrati tento modifikovany text // budeme nahrazovat tyto vyrazy $vzor[0] = '/Trabant/'; $vzor[1] = '/Tatra 613/'; $vzor[2] = '/Lada/'; $nahrazeni[2] = 'splašený vysavač'; $nahrazeni[1] = 'papalášfáro'; $nahrazeni[0] = 'Žigulík'; // proved nahrazeni a vrat vysledek return preg_replace($vzor, $nahrazeni, $tpl_output); } // vytvor sablonu $templatovaci_objekt = & new T_Template(); // registrace výstupní funkce kuk smarty_forms/smarty_filter1.php $templatovaci_objekt->register_outputfilter("muj_output_filter"); Jak se filtry používají – pokr. <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1250"> <title>Pokus s filtrem</title> </head> <body> <h1>Filtr</h1> <p>Na této stránce se dějí zajímavé věci s filtry.</p> <p>Franta říkal, že nejlepší auto je Trabant.</p> <p>Pepa ale říkal, že on si koupí jedině Tatra 613.</p> <p>Já si ale myslím, že nejlepší je Lada.</a> </body> </html> Výsledek <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows-1250"> <title>Pokus s filtrem</title> </head> <body> <h1>Filtr</h1> <p>Na této stránce se dějí zajímavé věci s filtry.</p> <p>Franta říkal, že nejlepší auto je splašený vysavač.</p> <p>Pepa ale říkal, že on si koupí jedině papalášfáro.</p> <p>Já si ale myslím, že nejlepší je Žigulík.</a> </body> </html> Pear = Hruška Martin Klíma Pear - hruška Systém pro implementaci a distribuci znovupoužitelných komponent (v PHP) Strukturovaná knihovna open-source (PHP) skriptů Systém pro distribuci skriptů a jejich správu Definuje standard, jak psát PHP kód Další podpůrné prostředky – Web stránky – Mailing listy – Bug report – ... – ... Co to umí Spousta dobře napsaných kódů Objektově orientované Dokumentované Umí se to samo nainstalovat Kde to je http://pear.php.net Instalace Pear je součástí standardní distribuce PHP od verze 4.3.0 Instalace jednotlivých komponent pear install <package> př. pear install HTTP_Upload seznam dostupných balíčků: pear remote-list instalace z lokálního souboru pear install soubor.tgz QuickForm HTML_QucickForm Sada tříd pro obsluhu formulářů Validace – Server – Klient (JavaScript) Read-only Snadno konfigurovatelné Podpora pro Smarty ... Ukázka – jednoduchý formulář PHP QuickForm Vložení potřebné knihovny <? require_once('HTML/QuickForm.php'); $form = new HTML_QuickForm('frmTest', 'POST'); $form->addElement('header', 'MyHeader', 'Test QuickForm'); $form->addElement('text', 'MyTextBox', 'Jak se jmenujete?'); $form->addElement('reset', 'btnClear', 'Smazat'); $form->addElement('submit', 'btnSubmit', 'Odeslat'); $form->addRule('MyTextBox', 'Jméno je povinné', 'required'); if ($form->validate()) { $form->process('process_data', false); # If the form validates then freeze the data $form->freeze(); } $form->display(); function process_data ($values) { echo "<pre>"; var_dump($values); echo "</pre>"; } ?> Založení formuláře Element textové pole Tlačítka Jméno je povinné Dopadla validace dobře? Ano: výsledek bude zobrazen jako prostý text Zavolá se po úspěšném ověření formuláře kuk quickform/example1.php PHP QuickForm Vytvářet elementy lze několika způsoby pomocí metody addElement(typ,jméno, hodnota,další parametry) pomocí metody HTML_QuickForm::createElement(typ) přímo pomocí konstruktoru elemntu daného typu např new HTML_QuickForm_text(‘tb1’, ‘Text box x'); Ukázka <? require_once('HTML/QuickForm.php'); $form = new HTML_QuickForm('frmTest', 'POST'); $form->addElement('header', 'MyHeader', 'Test QuickForm'); // metoda 1 $form->addElement('text', 'MyTextBox', 'Jak se jmenujete?'); //metoda 2 $novy_element = & $form->createElement('text'); $novy_element->setName('MyTextBox2'); $novy_element->setLabel('Vaše příjmení?'); $form->addElement($novy_element); //metoda 3 include_once('HTML/QuickForm/text.php'); $dalsi_element = new HTML_QuickForm_text('MyTextBox3', 'Číslo konta?'); $form->addElement($dalsi_element); kuk quickform/example2.php $form->display(); Pravidla - rules Pravidla jsou aplikována při validaci formuláře – Existující pravidla – Vlastní pravidla $form->addElement('text', 'MyTextBox', 'Jak se jmenujete?'); $form->addRule('MyTextBox', 'Jméno je povinné', 'required'); Rule Name Argument Rule Description maxlength $length The input can be at most $length characters. minlength $length The input must be at least $length characters. rangelength $min,$max The input must be between $min and $max characters (inclusive). regex $rx The input must match the regular expression $rx. email The input must be a likely syntactically valid e-mail address.* emailorblank The input must be blank or satisfy the email rule. lettersonly The input must contain only alphabetic characters. alphanumeric The input must contain only letters and numbers. The input must contain a valid positive or negative integer or decimal number. nopunctuation The input must not contain any of these characters: ( ) . / * ^ ? # ! @ $ % + = , " ' > < ~ [ ] { }. nonzero The input must not begin with zero. uploadedfile The element must contain a successfully uploaded file. maxfilesize $size The uploaded file must be no more than $size bytes. $mime The uploaded file must have a MIME type of $mime. If $mime is an array of MIME types, the uploaded file must have a MIME type equal to one of the elements in $mime. $file_rx The uploaded file must have a filename that matches the regular expression $file_rx. Seznam pravidel required zabudovaných Some input is required in the field. numeric mimetype filename Příklad <? require_once('HTML/QuickForm.php'); $form = new HTML_QuickForm('frmTest', 'POST'); $form->addElement('text','subject','Subjekt: '); // nejmene 5 znaku $form->addRule('subject','Enter a valid subject','minlength',5); if ($form->validate()) { $form->freeze(); } kuk quickform/example3.php $form->display(); ?> Vlastní validační pravidla Lze vytváře vlastní pravidla pomocí metody registerRule() Vlastní pravidlo jsou dvou typů – Regulární – Callback Ukázka callback pravidla <? function zacinaSpravne($value) { if (empty($value)) { return false; } if (strlen($value) < 2) return false; if (substr($value,0,2) == "Ma") return true; else return false; } require_once('HTML/QuickForm.php'); $form = new HTML_QuickForm('frmTest', 'POST'); $form->registerRule('zacina_spravne','callback','zacinaSpravne'); $form->addElement('text','subject','Subjekt: '); $form->addElement('submit','send','Odeslat'); $form->addRule('subject','Subjekt musi zacina na Ma','zacina_spravne'); if ($form->validate()) { kuk quickform/example4_vlastni_pravidla.php Ukázka pravidla pomocí regulárního výrazu <? require_once('HTML/QuickForm.php'); $form = new HTML_QuickForm('frmTest', 'POST'); $form->addElement('text','subject','Subjekt: '); $form->addElement('submit','send','Odeslat'); $form->registerRule('zacina_spravne_reg','regex','/^Ma*/'); $form->addRule('subject','Subjekt musi zacina na Ma','zacina_spravne_reg', null, ‘client’); if ($form->validate()) { $form->freeze(); } $form->display(); ?> Přidání validace i na klientskou stranu (javascript) kuk quickform/example4_vlastni_pravidla_regular.php Group rule Pravidla lze sdružovat a aplikovat na celou skupinu formulářových polí příklad: jméno se sestává ze 3 částí, každá musí mít alespoň 2 znaky Group rule - ukázka <? require_once('HTML/QuickForm.php'); $form = new HTML_QuickForm('frmTest', 'POST'); $group[] =& HTML_QuickForm::createElement('text','jmeno'); $group[] =& HTML_QuickForm::createElement('text','prijmeni'); $group[] =& HTML_QuickForm::createElement('text','titul'); $form->addGroup($group,'jmeno','Vase jmeno:'); $form->addGroupRule('jmeno','Vlozte jmeno, min 2 znaky','minlength',2); $form->addElement('submit','send','Odeslat'); if ($form->validate()) { $form->freeze(); } kuk quickform/example4_vlastni_pravidla_group_rule.php $form->display(); ?> Propojení se Smarty Jak se vlastně určuje rozložení formuláře? Bylo by možné toto rozložení ovlivnit? Když ovlivnit, tak jak pomocí Smarty? Renderers Existuje řada „rendererů“ Na základě objektového stromu formuláře tvoří datové struktury Default: HTML_QuickForm_Renderer_Default Můžeme: – Použít jiný renderer – Implementovat vlastní HTML_QuickForm_Renderer_ArraySmarty – renderer speciálně pro Smarty – datová struktura je pole HTML_QuickForm_Renderer_ArraySmarty Myšlenka: Vytvořit pole, které se zarigistruje ve Smarty objektu. Toto pole bude obsahovat veškeré informace potřebné k vykreslení V rámci smarty šablony se pak budou zobrazovat jednotlivé prvky pole Struktura pole array ( ['frozen'] => 'whether the complete form is frozen', ['javascript'] => 'javascript for client-side validation', ['attributes'] => 'attributes for <form> tag', ['hidden'] => 'html of all hidden elements', ['requirednote'] => 'note about the required elements', ['errors'] => Array ( ['1st_element_name'] => 'Error for the 1st element', ... ['nth_element_name'] => 'Error for the nth element', ), ['header'] => Array ( ['1st_header_name'] => 'Header text for the 1st header', ... ['nth_header_name'] => 'Header text for the nth header' ), ['1st_element_name'] => 'Array for the 1st element', Struktura pole - elementy array( ['name'] => 'element name', ['value'] => 'element value', ['type'] => 'type of the element', ['frozen'] => 'whether element is frozen', ['label'] => 'label for the element', ['required'] => 'whether element is required', // if element is not a group: ['html'] => 'HTML for the element', // if element is a group: ['separator'] => 'separator for group elements', ['1st_gitem_name'] => 'Array for the 1st element in group', ... ['nth_gitem_name'] => 'Array for the nth element in group' ); Jak se to použije - PHP <? require_once("funkce.inc"); require_once("init_smarty.php"); require_once('HTML/QuickForm.php'); require_once 'HTML/QuickForm/Renderer/ArraySmarty.php'; $form = new HTML_QuickForm('frmTest', 'POST'); $form->addElement('text','subject','Subjekt: '); $form->addElement('submit','send','Odeslat'); $templatovaci_objekt = & new T_Template(); $renderer =& new HTML_QuickForm_Renderer_ArraySmarty($templatovaci_objekt, true); $form->accept($renderer); // assign array with form data $templatovaci_objekt->assign('form', $renderer->toArray()); // nech to zobrazit $templatovaci_objekt->display('index.tpl'); Jak se to použije - šablona <!doctype html public "-//w3c//dtd html 4.0 transitional//en"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=windows1250"> <title>Pokusny formular</title> <body> <form {$form.attributes}> {$form.hidden} <div>toto je label: {$form.subject.label}</div> <div>toto je formularove pole: {$form.subject.html}</div> </form> </body> </html> Další pear balíčky (packages) Databáze Mail Autorizace Databáze PHP podporuje nejrůznější databáze – MySQL – PosgreSQL – Oracle – Sybase – ..... Při přístupu k databázi je třeba používat db-specific funkcí Obtížná migrace na jiný typ databáze Jak to obejít Udělat jednotné databázové rozhraní Abstraktní vrstva pro všechny databáze Aplikační logika DB abstraktní vrstva MySQL PosgreSQL Oracle Sybase .... Pear DB package OO API jednoduchý přechod na jiný typ databáze používá standardní DSN(data source name) pro specifikaci parametrů DB vrací objekt s výsledkem každého dotazu přenositelné chybové hlášky sekvenční a nesekvenční načítání řádků a hromadné načítání načtený řádek může být vrácen jako asociativní pole, pole s číselnými indexy nebo objekt podpora pro omezení počtu řádků podpora transakcí informace o tabulkách ... DB package DB staví na existujících PHP rozšířeních (kompilovaných) Tyto databáze procházejí testy: fbsql, ibase, informix, msql, mssql, mysql, mysqli, oci8, odbc, pgsql, sqlite, sybase. DB je kompatibilní s PHP 4 a PHP 5 DSN - data source name Před připojením k DB je třeba vytvořit platný DSN obecný tvar: phptype(dbsyntax)://jmeno:heslo@protokol+host/databázee?volba=hodnota příklady Připojení k db přes soket mysql://user@unix(/path/to/socket)/pear Připojení k db na nestandardním portu pgsql://user:pass@tcp(localhost:5555)/pear Připojení k SQLite na Unixu s použitím voleb sqlite:////full/unix/path/to/file.db?mode=0666 Připojení k SQLite na Unixu s použitím voleb sqlite:///c:/full/windows/path/to/file.db?mode=0666 Připojení k MySQLi přes SSL mysqli://user:pass@localhost/pear?key=client-key.pem&cert=client-cert.pem Připojení k MS Access někdy vyžaduje admin jako uživatelské jméno odbc(access)://admin@/datasourcename Metody connect, disconnect Připojuje (odpojuje) se k databázi. Používá DSN a další parametry. Někomu je milejší specifikovat DSN jako pole Metoda query Odesílá dotaz do db a vrací výsledek Může být parametrizována Proveď dotaz a vrať ho do proměnné $res Proveď parametrizovan dotaz a vrať ho do proměnné $res Načítání výsledků Tři typy datových struktur – DB_FETCHMODE_ORDERED (default) Array ( [0] => 28 [1] => hi ) – DB_FETCHMODE_ASSOC Array ( [a] => 28 [b] => hi ) – DB_FETCHMODE_OBJECT stdClass Object ( [a] => 28 [b] => hi ) Příklad načtení výsledků Hlavní metody – prepare, execute prepare, execute Problém rozdílné syntaxe u různých databází. Příklad: db1: INSERT INTO tbl_name (col1, col2) VALUES (expr1, expr2) db2: INSERT INTO tbl_name SET col1=expr1, col2=expr2 <?php $statement['db1']['INSERT_PERSON'] = 'INSERT INTO person (surname, name, age) VALUES (?, ?, ?)'; $statement['db2']['INSERT_PERSON'] = 'INSERT INTO person SET surname=?, name=?, age=?'; ?> Metody prepare, execute Před vykonáním dotazu je tento nejprve zpracován metodou prepare. INSERT INTO numbers VALUES (1, ‘one’, ‘en’) Metoda executeMultiple Zbytečná práce Metody autoPrepare, autoExecute Snaha oprostit se od psaní UPDATE a INSERT dotazů Jejich syntaxe se navíc liší pro různé databáze Nechme tyto dotazy vygenerovat automaticky Chci postupovat stejným parametrickým způsobem jako pro prepare, execute Metoda autoPrepare INSERT INTO table (id, name, country) VALUES (?, ?, ?) Vytvoř INSERT dotaz s těmito parametry. Dotaz je vytvořen pro konkrétní DB (instance v proměnné $db Metody autoPrepare UPDATE table SET id=?, name=?, country=? WHERE ... Vytvoř UPDATE dotaz s těmito parametry. Dotaz je vytvořen pro konkrétní DB (instance v proměnné $db Metoda autoExecute Ještě větší zjednodušení. Kombinuje metody autoPrepare a execute Vše v jednom, vytvoří dotaz a provede ho Mail Opět chceme „něco“, co nevíme jak funguje, ale funguje to dobře Pro posílání mailu existuje několik protokolů a klientů. Chceme od toho být oproštěni. => ABSTRAKCE Aplikační logika Mail abstraktní vrstva SMTP PHP Mail Sendmail Mail Použití je velice prosté Vytvoř mailovací objekt Pomocí metody send posílej co potřebuješ Podporuje tři metody posílání mailu Mail integrovaný v PHP SMTP Sendmail (Linux) Použití Získej ukazatel na instanci mailovcího objektu Odešli zprávu s těmito parametry Autorizace Chceme se „nestarat“ o pozadí autorizace ABSTRAKCE Aplikační logika Autorizační abstraktní vrstva DB Soubor SMB Imap LDAP Pop3 Radius Soap .... Autorizace Zavolá se když uživatel není autorizován Parametry specifikují databázi, jméno tabulky a jejích sloupců Autorizace pomocí DB Musíme mít tu správnou tabulku: CREATE TABLE auth ( username VARCHAR(50) default '' NOT NULL, password VARCHAR(32) default '' NOT NULL, PRIMARY KEY (username), KEY (password) ) vložíme data do tabulky INSERT INTO `auth` (`username`,`password`) VALUES ('xklima',md5('xxxx')) Ajax - xajax Martin Klíma Co to je ajax? Ajax = Asynchronous JavaScript Technologie asynchronního načítání webové stránky resp. jejích komponent Jak to funguje – Klient vznáší dotaz na server – Ten odpovídá Děkujeme za pozornost
Podobné dokumenty
Příklad
Tabulka uspořádaná do haldy – standardní, při přidávání dat je použito
první volné místo v segmentu, do něhož se data vejdou, po odstranění je
toto místo opět k dispozici pro opětovné vložení či ak...
Italští mistři Program kurzu Gemar Link Balloons™ Dekorační
možnost obohatit své znalosti o použití balónků, začátečníkům pak skvělou šanci
rozvíjet vlastní uměleckou tvořivost.
Umění “Balloon Art” má široké využití v rámci mnoha forem dekorativního
vyjádře...
výsledky
nůžkový skus, úplný chrup, výborný krk, kohoutek, záď, tělo a hrudník, VD hřbet a bedra,
výborné úhlení předních končetin, VD rovnost, tlapy, lokty, lopatky, výborné úhlení zadních
končetin, VD rov...
Bakalářská práce - bezztrátové komprimační algoritmy
mechanikami. Téma kompresních algoritmů mne již dlouhou dobu lákalo a jako téma své
bakalářské práce jsem si kompresní algoritmy vybral i z důvodu akademičnosti problému –
chtěl jsem něco prozkouma...