Autor Zpráva
TomasJ
Profil
Zdravím vás. Jsem začátečním s OOP (od včerejška) a tak zkouším... Na jednom webu jsem našel dobré vysvětlení pro začátek, a poté jsem našel i jak se tvoří přes class třeba připojení k MySQL, ale psali tam že je použití tím uvedeným způsobem v praxi nevhodné. Udělal jsem podle toho svůj vlastní "plugin" a po vás odbornících bych chtěl zkontrolovat jestli můj kód je vhodný použít v praxi (na svém webu). Samozřejmě tam mám zatím definované jen základní funkce MySQL... Zde je kód, předem díky za názory, připomínky.

<?php
class MySQL{
  private $host,
            $user,
            $pass,
            $conn,
            $db;

  private   $connected,
            $opened,
            $query;
          
  public function __construct($h,$u,$p,$d){
    $this->host = $h;
    $this->user = $u;
    $this->pass = $p;
    $this->db   = $d;
  }
  public function Connect(){
    if($this->connected){
      echo "MySQL spojeni je jiz navazano!<br>";
      return 0;
    }
    $this->conn = mysql_connect($this->host,$this->user,$this->pass);
    if(!$this->conn){
      echo "Nelze se pripojit k serveru!<br>";
      return 0;
    }
    $this->connected = true;
    return 1;
  }
  public function OpenDB(){
    if($this->opened){
      echo "Databaze je jiz otevrena!<br>";
      return 0;
    }
    if(!mysql_select_db($this->db,$this->conn)){
      echo "Nelze otevrit databazi!<br>";
      return 0;
    }
    $this->opened = true;
    return 1;
  }
  public function Query($q){
    if(!$this->connected){
      echo "MySQL pripojeni neni navazano!<br>";
      return 0;
    }
    if(!$this->opened){
      echo "Zadna databaze neni otevrena!<br>";
      return 0;
    }
    $this->query = mysql_query($q,$this->conn);
    return $this->query;
  }
  public function Result($q=0,$r=0){
    if(!$q) $q = $this->query;
    return mysql_result($q,$r);
  }
  public function Close(){
    if(!$this->connected){
      echo "MySQL pripojeni neni navazano!<br>";
      return 0;
    }
    mysql_close($this->conn);
  }
}

$mysql = new MySQL("localhost","user","","test"); //Vytvori instanci (volani funkce)
$mysql->Connect(); //Pripoji k serveru
$mysql->OpenDB(); //Vybere databazi
$q = $mysql->Query("SELECT Author FROM news"); //Zavola mysql dotaz
$mysql->Query("SELECT Title FROM news"); //Zavola dalsi mysql dotaz
echo $mysql->Result($q); //Vrati vysledek dotazu $q (prvni dotaz)
echo $mysql->Result(); //Vrati vysledek posledniho dotazu
$mysql->Close(); //Zavre spojeni
?>
Darkry
Profil
Tak z hlediska OOP je to navrhnuto poměrně dobře, každá metoda se stará o jednu věc a nenašel jsem nic co by mi nějak vadilo.

Horší už je to, ale s možností použití a funkčností. Je to asi jen můj názor, ale po zadání query bych rovnou vracel nějaké hezké pole s výsledkem (nech to ve dvou metodách, ale přímo v metodě query bych volal $thís->result($q);. Tím bude zbytečný ten atribut $query, který se podle mě chová dost magicky.

A poslední věcí je, že místo chyb pomocí echo bych vyhazoval výjimky (exceptions - to si dohledáš).
TomasJ
Profil
Jojo, jak říkám dělám s tím od včerejška, tak jsem jen chtěl vědět jestli jsem s tím začínám správně.
No ten atribut query jsem dal proto, že pak třeba budu chtít dodělat metodu, která vrací pole (z mysql_fetch_array), no tak abych nemusel volat znovu dotaz na databázi, jednoduše ho nechám uložený v atributu. Nebo to je špatně?
Děkuji.
Darkry
Profil
TomasJ:
Já psal, že by byl zbytečný v souvislosti s tím, že bys tu metodu result volal přímo z metody query. Pokud to chceš dělat tak, že nejdřív vyhodnotíš nějaký dotaz (metoda query) a pak teprve něj zavoláš nějaký výsledek (mysql_fetch_neco :-)) tak bych to asi stejně spíš dělal přes návratovou hodnotu a parametr.
TomasJ
Profil
No, to se ještě doučím. Díky :-)
Ugo
Profil
mohl bych být puritán a říci že se nestará o jednu věc, že by mělo být connection, query jenž by dostávalo connection a pak result jenž by dostával výsledek query (respektive query by vracelo instanci výsledku), už i já jsem se této implementaci přiblížil, ale jestli jde čistě o užitnou hodnotu, tak jí nedoporučuji.

Co se mi z hlediska používání moc nelíbí tak je absence destruktoru který by ukončil spojení, metoda connect bez parametru. Víc by se mi líbilo kdyby konstruktor rozdělil práci mezi connect() a OpenDB(), odpadly by 2 řádky při připojení a přibyla možnost měnit připojení za pochodu (tady bych asi zasloužil kamením, protože hezčí by bylo vytvořit novou instanci ... já jen nemám rád když mi něco brání abych udělal to co chci)

Spojení funkcí Query a Result je skutečně neintuitivní, ale né matoucí, takže v tom problém nevidím. Chybí tam kontrola spousty chybových stavů, to ale taky nevidim jako chybu, stejně tak absenci vyjímek, echo a return zde poslouží líp podle mě.
TomasJ
Profil
Ugo:
Myslel jsi to tak, že v konstruktoru bych provedl připojení a otevření databáze, ale metody Connect a OpenDB bych nechal?
Ugo
Profil
TomasJ:
přesně, asi takto

public function __construct($h,$u,$p,$d){
  $this->connect($h,$u,$p);
  $this->OpenDB($d);
}
public function connect($h,$u,$p);
public function OpenDB($d);

nevím zda je to nejhezčí ohledně pravidel, ale mě by se to mnohem líp používalo a mohl bych si měnit parametry připojení za běhu (čili nic by mě neomezovalo, i když bych to asi neudělal)
TomasJ
Profil
Aha, tím by odpadly atributy host, user, pass, db že?

EDIT:
Mám takový dotaz... Není místo return 0; někde vhodnější použít exit;? Tím bych v případě chyby ukončil následující kód a zabránil vypsání varování atd...
Darkry
Profil
TomasJ:
Přesně tak.
TomasJ
Profil
No returny jsem nahradil exitama (u chyb) a spojil jak psal Ugo. Exception je podle mě zdlouhavější když musím ještě použít try{} catch{}. Takto vypadá kód teď:
<?php
class MySQL{
  private   $query,
            $conn;
          
  public function __construct($h,$u,$p,$d){
    $this->Connect($h,$u,$p);
    $this->OpenDB($d);
  }
  public function Connect($h,$u,$p){
    if(($this->conn = mysql_connect($h,$u,$p))===false){
      echo "Nelze se pripojit k serveru! Zamitnuto pro '$u'@'$h' (vyplnene heslo: ".($p?"ANO":"NE").")<br>";
      exit;
    }
    return 1;
  }
  public function OpenDB($db){
    if(!mysql_select_db($db)){
      echo "Nelze otevrit databazi!<br>";
      exit;
    }
    return 1;
  }
  public function Query($q){
    if(!$this->conn){
      echo "MySQL pripojeni neni navazano!<br>";
      exit;
    }
    if(($this->query = mysql_query($q,$this->conn))===false){
      echo "Chybny SQL dotaz '<code>$q</code>'!<br>";
      exit;
    }
    return $this->query;
  }
  public function Result($q=0,$r=0){
    if(!$q) $q = $this->query;
    return mysql_result($q,$r);
  }
  public function __destruct(){
    if($this->conn){
      mysql_close($this->conn);
    }
  }
}

$mysql = new MySQL("localhost","user","password","database");
$mysql->Query("SELECT Sloupec FROM Table");
echo $mysql->Result();
?>
Tori
Profil
TomasJ:
returny jsem nahradil exitama (u chyb) a spojil jak psal Ugo. Exception je podle mě zdlouhavější když musím ještě použít try{} catch{}
Přidám taky jeden subjektivní pohled: nechtěla bych, aby DB vrstva měla pravomoc kdykoli natvrdo ukončit aplikaci. Výjimky se mi líbí víc - chyby, s nimiž počítám, zachycuji v modelu, nečekané chyby v kontroleru, a pro jistotu je i nejvyšší úroveň (includy, nastavení, spuštění aplikace) v bloku try-catch. Někdy se třeba ani nečte celý web z DB - v případě nedostupnosti databáze tak můžu zachytit příslušnou výjimku a napsat uživateli, že dočasně jsou dostupné jen nějaké 4 statické stránky.
TomasJ
Profil
Tori:
Díky za názor, nicméně ho pochopím až v budoucnu, zatím s tím začínám a dost věcí ještě nechápu. Ale díky. :-)
Bertram
Profil
TomasJ:
Ahoj, já bych raději zvolil mysqli než mysql.
A pokusil se vytvořit kód, který by potom umožnil něco jako:
$this->connect->query("SELECT ...")->feth_All();
Darkry
Profil
TomasJ:
Mě se pořád nelíbí jak si metoda Result bere to poslední provedené query, je to hrozně magické chování. Představ si, že vykonáš nějaký query vlastní a to ti z nějakého důvodu vrátí NULL. Pak provedeš další query a to se uloží do toho posledního. A pak chceš získat výsledek z toho prvního a místo toho, aby ti to hodilo chybu tak si to samo načte to druhý query a ty nic nepoznáš a najít pak chybu je jako hledat jehlu v kupce sena :-).

Fakt bych radši tuhle rádoby užitečnou funkci zrušil.
TomasJ
Profil
Darkry:
No koukni se jak to tam je...
$mysql = new MySQL("localhost","user","password","database");
$q1 = $mysql->Query("SELECT Sloupec FROM Table1");
$q2 = $mysql->Query("SELECT Sloupec FROM Table2");
$mysql->Query("SELECT Sloupec FROM Table3");
echo $mysql->Result($q1); //Vrati mysql_result na dotaz $q1
echo $mysql->Result($q2); //Vrati mysql_result na dotaz $q2
echo $mysql->Result(); //Nezadam-li zadny parametr, vrati mysql_result posledniho dotazu.
To znamená, že pokud budu chtít výsledek jiného dotazu, jednoduše ho uložím do proměnné, kterou pak doplním jako parametr do metody Result ($mysql->Result($parametr)). Koukni se jak mám v celém kódu tu metodu vytvořenou :-).

Bertram:
Díky, ale zůstanu prozatím u toho co už relativně umím (MySQL) :-)
Tori
Profil
TomasJ:
Díky za názor, nicméně ...
Když to ukážu na příkladu: představte si, že je nějaká firma, úspěšná, s dlouhou tradicí, a ta má archiv dokumentů. Úředník pošle vzkaz archivářovi, že potřebuje nahlédnout do účetní knihy z r. 1953. Archivář ale zjistí, že ztratil klíče od archivu. Může na to reagovat různými způsoby:
* okamžitě vyhlásit bankrot celé firmy, protože bez klíčů od archivu prostě nemůže dál fungovat (= echo "chyba" + exit),
* poslat vzkaz zpátky úředníkovi a vyhlásit místním rozhlasem, co se strašného stalo (= echo "chyba" + return), anebo
* poslat vzkaz úředníkovi a nechat to na něm. Úředník buď řekne, že to nevadí, anebo se obrátí na nadřízeného, který rozhodne další postup (= výjimky).

databázová vrstva = archivář, volající funkce = úředník, atd. Lepší? ;)
TomasJ
Profil
Tori:
Díky za vysvětlení. :-)
No ale mám tu takový problém. A sice strukturu. Vím kam hodit throw new Exception("Chyba XXX");
ale přesně moc nevím, kam je vhodné hodit try-catch...

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: