Dobrý večer, rád bych poprosil přítomné o radu/nasměrování. Vím, že je tady toho o OOP v PHP napsáno spousta, nicméně nenašel jsem přesně to, co jsem hledal.
Snažím se přejít k objektovému myšlení - a k objektovému programování aplikací v PHP. Jsem z toho ale trochu bezradný - pročetl jsem několik seriálů o tomto na internetu, myslím si, že té základní logice a syntaxi rozumím, mám ale problém "napasovat" získané vědomosti na praxi.
Uvedu příklad, dejme tomu, že chci vytvořit klasický inzertní web (vkládání inzerátů do kategorií, poté jejich zobrazení, registrace uživatelů). Když nad tím přemýšlím, nevím si moc rady, jaké třídy vytvořit, napadá mě jednoduše dejme tomu Kategorie, Inzerat, Uzivatel, ale myslím, že tato cesta není správná, nevidím tam např. žádný prostor pro dědičnost, působí to na mě jen jako takové chlívečky pro funkce, jakým způsobem by se to dalo uchopit lépe?
Další věc, která mě zajímá, je dejme tomu výpis inzerátů z databáze - v tomto jsem také trochu bezradný. Řešil bych to nějak takto (zjednodušeně) - používám šablonovací systém Smarty, ale cítím, že je to takové zbastlené (jde vlastně jen o procedurální kód obalený do třídy a vlastně nevím, jak využít ty getry a setry, protože takhle nejsou potřeba) - jak toto, prosím, pojmout lépe?
index.php
třída inzerat.php
Vím, že pokud nejsem schopný dát toto sám dohromady, je možná zbytečná jakákoliv rada, a budu odkázan na studium tohoto a tohoto (ale i to ocením, pokud půjde o konkrétní podobný příklad), ale jak říkám, dělá mi problém to užití v praxi, chápu ty jednoduché příklady na OOP, kdy si vytvořím objekt třídy Ctverec($delka_strany), ale jsem bezradný, když mám třeba za užití OOP vypsat řádky z databáze. Proto prosím o alespoň malé nasměrování, věřím, že kdyby se našel někdo ochotný vyjádřit se k těmto 2 příkladům, hondě by mně to pomohlo.
Mockrát děkuji.
To jsem si myslel, že takhle jsem se cítil pouze já. Přesně takhle jsem se kdysi cítil i já, udělal jsem si script a považoval jsem ho za ne elegantní a celkově mi ten kod nebyl přitažlivý. Je to způsobeno tím, že jsi v něčem nový a nevíš přesně, jak to máš udělat a když pak něco uděláš, tak máš pocit, že to děláš špatně. Mně pomohlo najít si nějaké OOP aplikace a více méně se inspirovat, jak ten kod napsat. Třeba u téhle aplikace si můžeš udělat třídu inzerat, která bude obstarávat veškeré funkce a akce, které se týkají právě inzerátu, tedy akce jako smaž inzerát/uprav inzerát/vyber inzerát apod.Tady je pak nutno zmínit, že je třeba inspirovat se elegantním kodem, nebot pokud najdeš script od nějakého blba, tak si uděláš špatný návyky a těch se hodně špatně zbavuje.
osobně mám vždy jednu hlavní třídu pro celý web, která obsahuje všeobecné funkce pro web, potom mám klasické třídy pro jednotlivé prvky - uživatelé (zrovna ověřování přihlášení je v hlavní třídě), platby (ověřování a práce s platbami) atd - ještě se mi snad nestalo, že kvůli jedné funkci bych napojoval třídupro db používám pdo (config je v samostatné třídě) $vypisquery = $this->db->prepare("SELECT sloupec FROM db WHERE where = :where");$vypisquery->execute(array(':where'=>$where)); while($vypis = $vypisquery->fetch(PDO::FETCH_ASSOC))$data[] = $vypis;return $data;//nebo//if(isset($data)) return $data; edit: trochu blbě jsem editoval prepare a execute
To jsem si myslel, že takhle jsem se cítil pouze já. Přesně takhle jsem se kdysi cítil i já, udělal jsem si script a považoval jsem ho za ne elegantní a celkově mi ten kod nebyl přitažlivý. Je to způsobeno tím, že jsi v něčem nový a nevíš přesně, jak to máš udělat a když pak něco uděláš, tak máš pocit, že to děláš špatně. Mně pomohlo najít si nějaké OOP aplikace a více méně se inspirovat, jak ten kod napsat. Třeba u téhle aplikace si můžeš udělat třídu inzerat, která bude obstarávat veškeré funkce a akce, které se týkají právě inzerátu, tedy akce jako smaž inzerát/uprav inzerát/vyber inzerát apod.Tady je pak nutno zmínit, že je třeba inspirovat se elegantním kodem, nebot pokud najdeš script od nějakého blba, tak si uděláš špatný návyky a těch se hodně špatně zbavuje.
Nebyl jsi sám. :)Jenomže pro mě je problém i nalézt nějaké ty OOP aplikace vhodné pro učení se... Ohledně té třídy inzerat, ano v podstatě tak to mám, jenomže je to ve stylu:a to mně proste připadá jen jako procedurální kód obalený třídou. Z důvodu přehlednosti je to asi pořád lepší způsob než klasické procedurální programování (v index.php zavolám dejme tomu $i->nactiInzerat($_GET);), ale stále mně přijde, že nevyužívám zdaleka možnosti, které OOP nabízí.Nevidím žádný prostor pro dědičnost, třída inzerat vlastně nemá žádné proměnné (představoval bych si to nějak takhle, ale nevím, jestli to dává smysl a zkrátka potřebuju trochu nasměrovat a od něčeho se odrazit):A poté jednoduše pracovat s inzerátem jako objektem. Dává to smysl? Jak by se dal podobný princip napasovat na výpis inzerátů?Děkuji.
Nevidím žádný prostor pro dědičnost, třída inzerat vlastně nemá žádné proměnné (představoval bych si to nějak takhle, ale nevím, jestli to dává smysl a zkrátka potřebuju trochu nasměrovat a od něčeho se odrazit):
Predpokladam, ze maz tabulku inzeratov a v nej nejake stlpce.Tie stlpce by som dal ako property toho inzeratu. K dedicnosti. Zober si, ze by si mal inzerat na auta, na domy a podobne. Pre auta by si mal okrem toho vseobecneho zakladu ako text inzeratu, kedy bol vytvoreny, kedy mu ma skoncit platnost aj napr. znacku auta, objem motora, farba, rok vyroby.Takze vytvoril by si triedu inzeratauto, ktora by dedila z triedy inzerat a do triedy inzeratauto by si len ako property pridaval co je specificke pre inzerat na auto.Este ti trosku zamotam hlavu. Ja by som nacitanie z databazy dal samostatnej triedy a z nej by som vracal objekt inzerat. Ked by som chcel vratit vypis inzeratov, by som len pridal do tej samostatnej triedy proceduru, ktora by mi vracala pole objektov
Díváš se na to moc složitě, OOP je ve skutečnosti velmi podobné normálnímu myšlení.Takže chceš pracovat s inzerátama, tak si řekni1/ Co má ten inzerát obsahovat?Každý inzerát bude mít ID, Text, Kategorie a řekněme Email. A pak budou inzeráty v kategorii Televizory, ty budou navíc obsahovat vlastnost Uhlopricka a inzeráty v kategorii Psi a ty budou obsahovat vlastnost Rasa.2/ Co s tím inzerátem budu dělat?Budu ho vypisovat.A když se na to takhle podíváš, tak ti musí být jasné, že budeš mít nějakou základní třídu Inzerat (může být abstraktní). Ta bude obsahovat ID, Text, Email a Kategorii. A pak bude obsahovat metodu vypis(). A pak budou dvě konkrétní třídy, InzeratTelevizor a InzeratPes, obě budou rozšiřovat základní třídu Inzerat. o vlastnost Uhlopricka, případně Rasa.Tady je na čase zmínit, proč vlastně to OOP používáš a proč to nejsou jenom chlívečky pro funkce. Protože kdekoliv ty budeš chtít načíst inzerát vypsat na obrazovku, tak vždycky budeš volat stejnou metodu základní třídy Inzerat bez ohledu na to, jestli se jedná o psa, nebo o televizor. Čili napíšeš jenom $inzerat->vypis() a vypíše se ti detail inzerátu podle kategorie, včetně uhlopříčky, či rasy.Toho docíllíš zhruba takto:No nicméně pro inzertní server o hodně kategoriích tento způsob není moc použitelný, jenom to demostruje OOP.
Děkuji za reakce.Dejme tomu, že "šablona" inzerátu bude jednoduše stejná pro všechny typy inzerátu, tzn. že např. auta nebuou mít žádné parametry navíc oproti jiným inzerátům, tím pádem asi není potřeba to dědění od třídy Inzerat.Mohl by někdo být prosím tak laskavý a ukázat mně/alespoň nastínit,1. jak by vypadala metoda pro výpis inzerátů (tak, aby byly použity atributy té třídy inzerat, aby byly načítány jednotlivé instance třídy inzerát třeba do toho pole objektů, jak to tu popisoval qwertr)? Vyšlo by se nějakým způsobem/bylo by to podobné tomuto:?2. jaké další třídy by tedy byly použity? Je mimo ten můj původní návrh: Inzerat, Kategorie, Uzivatel?Mockrát díky.
Ano, učit se framework a nevědět jak funguje OOP, to je jako kdyby jsi chtěl napsat knihu ale neuměl číst.
Koukám že perlíte nesmysl za nesmyslem. K věci, koukám zde na rady ale většina z nich jsou nesmyslné poďme si vysvětlit jak a co a proč použít. A hlavně proč ihned začít s frameworkem.Takže. Začneme Interface budeme pokračovat k abstraktním třídám a budeme pokračovat rozdělením aplikace atd atd.. InterfaceInterface, je vlastně TEMPLATE pro třídu kde se urči co dané třídy které tento TEMPLATE implementují musí nezbytně obsahovat, udávají se zde, metody zdali mají být veřejné nebo chráněné, případně jaké parametry by měli obsahovat. Dobře popsáno třeba zde: http://www.devbook.cz/php-tutorial-oop-interface-rozhraniA co praxe ? V praxi vezměte si třeba že by jste programoval simulaci auta. Každé auto má stejnou funkci a to nastartování takže Interface třída by obsahovala, metodu nastartuj() která by byla veřejná takto:
interface Auto { public function nastartuj();}?>Implementace tohto interface, do tříd zaručí, že všechny třídy musí obsahovat definici této metody, jinak aplikace vyhodí hlášku. Abstraktní třídyAbstraktní třída se může jevit, podobná interface, zásadní rozdíl je však v tom že abstraktní třída nedefinuje co má třída kterou dědím obsahovat ale obecné funkce využívané, pro všechny třídy které dědi tuto abstraktní třídu a definici abstraktních metod které jsou potřeba implementovat, v těch třídách s parametrama pro správnou funkčnost obecných metod.Využití v praxi ?Máme interface auto, teď potřebujeme, obecné funkce které jsou společné pro všechny auta. Například, přidej plyn, zabrzdi, zmáčkni spojku. Vytvoříme tedy abstraktní třídu pro tyhle funkce:
abstract class Automobile { protected $druhMotoru; public function __construct($druhMotoru){ $this->druhMotoru = $druhMotoru; } abstract protected function uberPalivo(); public function pridejPlyn(){ $this->uberPalivo(); } public function zabrzdi(){ //kprovedeme zabrzdeni } public function zmackniSpojku(){ //zmackneme spojku }}?>Takže jak můžeš vidět, mámé zde 2 abstraktní metody nastartuj a uberPalivo. proč zrovna tyto dvě ? proč jsou ostatní obecné ? Protože, pridat plyn, zabrzdit a zmačknout obsahuje každé auto takže je nesmysl to znova psát. Ale nastartování se může u každého auta lyšit, např. žažehnutím nebo vytvořením jiskry svíčkama. Uber palivo protože každé auto může mít jinou spotřebu a jiný typ paliva, tak jej musíme určit pokaždé pro každý typ auta.Tak a teď k hlavní třídě.¨
Class Audi extends Automobile implements Auto { private $spotreba = 10; //10l na 100 KM private $palivo = 'benzin'; private $obsah = 2.8; private $obsahNadrze = 80; private $aktualniStavNadrze = 40;//40 litru public function nastartuj(){ //provedeme nastartovani nastavime vsechny potrebne parametry. napr motor bezi pro funkci pridej plyn } protected function uberPalivo(){ // provedeme vypocet dle parametru vozidla pro uber paliva a yapiseme do stavu nadrze. }}?>Zde můžeš vidět jak ty třídy vzájemně spolu spolupracují. Tak dále proč FW ihned ? Naučí tě jak správně psát aplikaci, vyřeší za tebe hromadu kódu který by jsi musel psát ( spojení s db, ošetření vstupu atd atd ). Je těžší s ním začít ale vyplatí se ti to protože vsoupíš okamžitě na vyšší level než když si to budeš bastlit sám. Navíc tám můžeš vidět, jak píšou jiný a učit se právě z toho.Rozdělení aplikace: Aplikaci je nejlépe mít rozdělenou na MVC ( Model View Controller )Kde: View: Představuje, vše co se má zobrazit ( výstup ), takže veškeré HTML a pouze nezbytně nutné PHP a to if, else, foreach, for, while případně pár pomocných promněnných pro nějaký prepopočet ale nic víc.Controller neboli Presenter:Tohle je něco jako router, nebo dispečer, dá se také považovat, za část prezenční, protože spracovává klientské požadavky. Které následně odevzdává ostatním objektům, např. modelu a view. Tzn. v procesu to vypadá takhle: Přijde klient a pomocí url si vyžádá seznam aut. Požadavek příjde na Controller AutaController , kde v metodě příjme parametry ( například z vyhledávácího filtru ) ty parametry předá Modelu, model parametry spracuje, skonstruuje např. dotaz do databáze vyhovujíci parametrum načte data a předá je o5 kontroleru, který načtené data vezme a předá je view který je následně zobrazí. To je celá práce kterou ma controller provádět nic víc. ModelModel představuje srdce aplikace, zde se ději všechny různé akce, načítání, mazáni, vytváření, editace. Ukládání obrázku atd atd atd vše co je nějaký konkrétní úkon, nebo spracování dat ( zde také využiješ nejvíce abstraktní třídy a interface třídy ). Tzn. model může byt např, pro komunikaci s databázi a konkrétní tabulkou, pro spracování obrázku nebo souborů, nebo načítání externího obsahu cokoli. Krom výše popisovaného. Dále zde máš pak různé další typy, ale ty ti již poskytne framework. Každopádně, použiti a učení práce s frameworkem, tě naučí právě tuto logiku. Doporučil bych ti začít s Nette, je český, a pro začátečníky přivětivý. Doufám, že ti to pomůže vstoupit do světa programování. :) Bod + za snahu potěší.
Díky za pomoc. 1. Mohl bych Vás poprosit ještě o alespoň stručnou odpověď na ten můj původní příspěvek (ten ze včerejška 23:21)? Rozumím tomu, co jste napsal zde, ale stále mně dělá trochu problém napasovat to na ten můj příklad z praxe.2. O frameworku jsem přemýšlel, ale myslel jsem si, stejně jako iTerminator, že by bylo vhodné napřed pochopit OOP v "čisté" formě. Jaký framework byste doporučil? Slyšel jsem, že pro začátečníka je vhodný CodeIgniter.
Díky za pomoc.
1. Mohl bych Vás poprosit ještě o alespoň stručnou odpověď na ten můj původní příspěvek (ten ze včerejška 23:21)? Rozumím tomu, co jste napsal zde, ale stále mně dělá trochu problém napasovat to na ten můj příklad z praxe.
2. O frameworku jsem přemýšlel, ale myslel jsem si, stejně jako iTerminator, že by bylo vhodné napřed pochopit OOP v "čisté" formě. Jaký framework byste doporučil? Slyšel jsem, že pro začátečníka je vhodný CodeIgniter.
Nechci nijak urážet iTerminator. Ale prozatím na mě ve všech diskuzích působil dojmem, že on sám má co zlepšovat. Takže jeho rady prozatím neposlouchejte.
Začněte s Nette, pomůže Vám tam i ta čeština a silná česká komunita.
---------- Příspěvek doplněn 23.03.2014 v 00:43 ----------
Napsal Martin Škoula;1070932
Děkuji za reakce.
Dejme tomu, že "šablona" inzerátu bude jednoduše stejná pro všechny typy inzerátu, tzn. že např. auta nebuou mít žádné parametry navíc oproti jiným inzerátům, tím pádem asi není potřeba to dědění od třídy Inzerat.
Mohl by někdo být prosím tak laskavý a ukázat mně/alespoň nastínit,
1. jak by vypadala metoda pro výpis inzerátů (tak, aby byly použity atributy té třídy inzerat, aby byly načítány jednotlivé instance třídy inzerát třeba do toho pole objektů, jak to tu popisoval qwertr)? Vyšlo by se nějakým způsobem/bylo by to podobné tomuto:
?
2. jaké další třídy by tedy byly použity? Je mimo ten můj původní návrh: Inzerat, Kategorie, Uzivatel?
Mockrát díky.
1. Metoda pro zápis by nevypadala nijak. Tu by obsahovala metoda abstraktní třídy. Přední model pro tabulku inzerátu by obsahoval například definici, sloupců které obsahuje, definici povolených filtrů a sortování a skutečné obecné metody. Uvedu příklad velice jednoduché abstraktní třídy a předělám Vaší inzertní.
abstract class ModelAbstract {
protected $_id;
protected $_data;
protected $_table;
public function __construct($id = null){
if($id)
{
$this->setId($id);
$this->loadById($id);
}
}
public function setId($id){
$this->_id = $id;
}
public function loadById($id){
$sql = 'select WHERE id = ?';
//naucime se vyuzivat PDO fw jej vzuzivaji
$db = Databaze::getDb();//navrati nam vytvorenou instanci PDO
$data = $db->getRow($sql,$id);
if($data)
{
$this->parseData($data);//nacteme data do objektu
}
}
public function parseData($data){
$this->_data = $data;
}
public function getData(){
return $this->_data;
}
public function save(){
if($this->getId()){
$this->update();
}
else {
$this->insert();
}
}
private function update(){
$sql = 'sql pro update WHERE id = :id';
$params = array(.......,":id" => $this->getId());
try {
$db = Databaze::getDb();
$prepare = $db->prepare($sql);
$prepare->execute($params);
}
catch(Exception $e){
throw $e;//zachyceni a vyhozeni vyjimky v pripade chyby
}
}
private function insert(){
$sql = 'sql pro insert';
$data= $this->getData();
$params = $this->dataToParams($data);
try {
$db = Databaze::getDb();
$prepare = $db->prepare($sql);
$prepare->execute($params);
}
catch(Exception $e){
throw $e;//zachyceni a vyhozeni vyjimky v pripade chyby
}
}
private function dataToParams(array $data){
$params = array();
foreach($data as $column => $value){
$params = $value;
}
return $params;
}
}
?>
Třída modelu tabulky inzercí.
class Inzeraty extends ModelAbstract {
protected $_table = 'inzeraty'; //definice nazvu tabulky ktery se bude pouzivat v SQLkach
public function setData(array $data){
if($this->validateData($data))
{
$this->_data = $data;
}
else {
//chyba data jsou nevalidni
}
}
private function validateData(array $data){
//yde provedete validaci vsech dat zdali jsou spravne a vyhjovuji
}
}
Třídy jsem psal z hlavy, takže mohou obsahovat chyby.
S frameworkem klidně začni hned. Něco z OOP už umíš a zbytek nasbíráš časem. S jakým FW začít je otázka. Někomu sedne na začátek Nette, ale já s ním hodně zápasil.Tak jsem začal s Codeigniterem. Podle mě je na naučení o dost lehčí než Nette. Za pár dní v něm dokážeš docela dobře pracovat. Až se rozkoukáš, klidně se pusť do Nette. Ono to má dost podobností pro základní práci. Nette má oproti CI dost vychytávek pro vyšší level programování, ale tyhle věci dokážou začátečníka dost zmást.
Každopádně pro nejlepší pochopení celého OOP je vysvětlení na realném životě a to: Budeme hovořit o Tobě, Tvojí mamce a tátovi, Dědovi a babičce a podstatě.Tzn. Ty představuješ model, tvůj táta je tvoje Abstrakce, Máma a táta mají abstraktní třídy, Děda a babička. A všichni máte Interface podstatu ( že jste lidé, metody jsou že máte ruce, mozek, nohy, oči atd.. interfacu )A to takto. Ty jsi získal vlastnosti od táty protože jsi po tátovi(např.), takže dědíš abstrakci táty a jeho vlastnosti povahu atd, tvůj táta je po dědovi tak dědí jeho vlastnosti atd.. a všichni implementujete podstatu viz nahoře. Tvůj táta ti předal následující vlastnosti ( příjmení ) a tyto schopnosti ( čtení, psaní, chození, mluvení, atd.. ) to jsou sdílené metody.Naprosto stejná logika, funguje v programování, obecné vlastnosti které se chovají v závislosti na abstraktních metodách které musí daný objekt implementovat. Vždy se snaž přemýšlet než začneš programovat, co jdeš programovat a kolik toho budeš programovat, zdali není možnost, definovat obecné chování a měnit jej na základě tříd které tyto obecné třídy dědí.