Autor Zpráva
Pinqui
Profil
Dobrý den pokusil jsem se napsat třídu na tvoření elementů 'samozřejmě že v ní nejde vytvořit vše jako odkaz a obrázek např), ale zajímalo by mě zda ta třída pomůže, jestli je dobře napsaná, nebo jak ji napsat lépe, prostě hlavně všeobecné názory. OOP se snažím pochopit tak zkouším na příkladech děkuji.

<?php
class Element {

  # vlozeni noveho elementu
  function add($element, $id = false, $clas = false, $text = false, $close = false) {
      $this->element[] = $element;
      $this->id[] = $id;
      $this->clas[] = $clas;
      $this->text[] = $text;
      $this->close[] = $close;
  }

  # zobrazeni polozky
  function showElement($x) {
                               print "<{$this->element[$x]}"; 
    if($this->id[$x]!=false)  {print " id=\"{$this->id[$x]}\"";} 
    if($this->clas[$x]!=false){print " class=\"{$this->clas[$x]}\"";}
                               print ">\n{$this->text[$x]}";
    if($this->close[$x]==true){print "</{$this->element[$x]}>\n";}
  }
  function closeElement($x){
  print "</{$x}>";
  }
  # vypsani elementu na stranku
  function show() {
    for ($x = 0; $x < count($this->element); $x++) {
      $this->showElement($x);
    }
  }
}

$el = new Element;
$el->add('div', 'testid');
$el->add('span', false, 'testclass', false, true);
$el->show(); 
$el->closeElement('div');
?>
Mastodont
Profil
$el->add('span', false, 'testclass', false, true);

Osobně bych u funkcí s větším množstvím nepovinných parametrů použil předávání formou pole a mergnul předané hodnoty s výchozími. Stačí pak zadat jen ty hodnoty, které chci změnit vůči výchozím.

function add($element, $options) {
   $defaults = Array ( 'id' => 0, 'class' => 0, 'text' => 0, 'close' = 0);
   ...
   $this->options = array_merge($defaults, $options);
}
...
$el->add('span', Array('class' => 'testclass');
Pinqui
Profil
A bude to mít nějaký efekt ve větším projektu použít třídu k tvoření elementů? Nějakou výhodu, aby třeba nebylo spíše na obtíž uživat třídu pro tvorbu elementů, aby to nespomalovalo práci s kódama.?? Díky
Mastodont
Profil
No to si musíš vyřešit sám, jak chceš vytvářet HTML ... možností je spousta.
fuckin
Profil
mezi dobre zvyky patri pouzivat viditelnost u vseho napr : public function ahoj(), to same plati i u promennych napr protected $promenna atd.

Dale kdyz nepouzijes konstruktor tak bys ho mel vynulovat
public function __construct() {}

Jestli nasels navody pro php 4 tak je rovnou zahod, php 5 mnohonasobne vylepsilo oop tak nepouzivej stare zpusoby.
Pinqui
Profil
Mastodont
Nějak nevím, když jsem to změnil, jak změnit zbytek ködu aby mi to fungovalo.. Nechce se mi to totiž vypsat :-(

// po změně ty add funkce jak jsi psal
joe
Profil
Můj názor: takovéhle programování fakt "miluju". Proč sakra píše někdo něco takovýho, když musí dopředu vědět, že to je naprosto nepoužitelný a zbytečný? Není jednodušší napsat echo "<div class='trida'>"; ?

Ke kódu:
Nezdá se mi moc tvé pojmenování proměnných
element[] bych nazval spíše elements[], protože jich je více, ale to je každého věc
class se píše s dvěma s
ukončovací element - máš pocit, že ukončovací element může být jiný než otevírací (když beru v úvahu jen párové elementy)
u showElement() nemáš oveření, jestli element vůbec existuje

A když to mám celkově zhodnotit, tak mi přijde, že si spíš přiděláváš víc práce, než naopak - zbytečně ztracený čas a čas jsou peníze ;)
Pinqui
Profil
joe
close - uzavření (to jsem ěml, kdybych chtěl do toho elementu vkládat další věci.
Jinak tuto třídu nemám v úmyslu použít, jen se na ní zkouším naučit, jak to pracuje. Nějak mě nenapadl jiný nápad zrovna.
clas jsem psal jednou když jsem napsal $this->class tak to class sčernalo a asi by to mohlo dělat nepořádek.
jak případně ověřím, jestli element existuje?
DoubleThink
Profil *
zajímalo by mě zda ta třída pomůže
Moc ne, v tomto případě je jednodušší napsat tag přímo. A žádné další výhody třída nepřináší.

mezi dobre zvyky patri pouzivat viditelnost u vseho napr : public function ahoj()
public je implicitní hodnota, nemusí být explicitně definována.

Dale kdyz nepouzijes konstruktor tak bys ho mel vynulovat
Zbytečné. Neuvedený konstruktor rovná se prázdný konstruktor.
Jan Tvrdík
Profil
DoubleThink:
public je implicitní hodnota, nemusí být explicitně definována.
To ano, přesto někteří programátoři (joe, …) považují za chybu, když se ten modifikátor neuvede.

Pinqui:
zajímalo by mě, zda ta třída pomůže
Vzhledem k tomu, jak je napsaná, tak ti práci nijak neusnadní. Pokud se ale podobná třída napíše dobře, tak dokáže usnadnit spoustu práce.
DoubleThink
Profil *
To ano, přesto někteří programátoři (joe, Já…) považují za chybu, když se ten modifikátor neuvede.
A někteří lidé si zase padesátkrát denně umývají ruce, co naděláš.

Já identifikátor viditelnosti přidávám vždycky, ale jenom proto, že to za mě dělá editor. Netrápí mě, když není definován.
Jack06
Profil
Použil jsem kód na připojení a práci s mysqli, ale ne uplně z příkladu.. upraveno je připojení k databázi, problém $this->mysqli prosím o radu díky

<?php 

header('Content-Type: text/html; charset=utf-8');

/* ================================= USE MySQLi ============================= */
class MyDB extends MySQLi {
  protected $mysqli;
  protected $showerror = TRUE;   // nastavte FALSE, pokud nechcete zobrazovat chybová hlášení
  protected $showsql   = FALSE;  // nastavte TRUE, pokud chcete kvůli ladění zobrazovat všechny dotazy SQL
  protected $sqlcounter = 0;     // počítadlo příkazů SQL
  protected $rowcounter = 0;     // počítadlo vrácených řádků SELECT
  protected $dbtime     = 0;     // počítadlo času potřebného pro vykonání dotazů
  protected $starttime;
  private static $_instance = null;

  const SERVER = 'localhost';
  const USERNAME = 'root';
  const PASSWORD = 'xxx';
  const DBNAME = 'xxx';
  
  private function __construct() {
   $this->mysqli = parent::__construct(self::SERVER, self::USERNAME, self::PASSWORD, self::DBNAME);
  }
  public static function _() {
    if(self::$_instance === null) {
      self::$_instance = new self();
    }
    //$this->starttime = $this->microtime_float();
    return self::$_instance;
  }

  // dodatečné uzavření
  public function close() {
    if($this->mysqli)
       $this->mysqli->close();
       $this->mysqli = FALSE;
  }

  public function getMysqli() {
    return $this->mysqli; }

  // vykonání dotazu SELECT, vrací se pole
  public function queryObjectArray($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result) {
      if($result->num_rows) {
        while($row = $result->fetch_object())
          $result_array[] = $row;
        $this->rowcounter += sizeof($result_array);
        return $result_array; }
      else
        return FALSE;
    } else {
      $this->printerror($this->mysqli->error);
      return FALSE;
    }
  }

  // vykonání dotazu SELECT, vrací se pole
  public function queryArray($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result) {
      if($result->num_rows) {
        while($row = $result->fetch_array())
          $result_array[] = $row;
        $this->rowcounter += sizeof($result_array);
        return $result_array; }
      else
        return FALSE;
    } else {
      $this->printerror($this->mysqli->error);
      return FALSE;
    }
  }


  // vykonání dotazu SELECT, který vrací pouze jednu položku
  // (tj. SELECT COUNT(*) FROM table); vrací
  // tuto položku
  // pozor: tato metoda při chybě vrací hodnotu -1 (a nikoliv 0)!
  public function querySingleItem($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result) {
      if ($row=$result->fetch_array()) {
        $result->close();
        $this->rowcounter++;
        return $row[0];
      } else {
        // dotaz nevrátil žádná data
        return -1;
      }
    } else {
      $this->printerror($this->mysqli->error);
      return -1;
    }
  }

  // vykonání příkazu SQL bez výsledků (žádný dotaz)
  public function execute($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->real_query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result)
      return TRUE;
    else {
      $this->printerror($this->mysqli->error);
      return FALSE;
    }
  }

  // použití insert_id za příkazem INSERT 
  public function insertId() {
    return $this->mysqli->insert_id; }

  // vložení \ před ', " atd.
  public function escape($txt) {
    return trim($this->mysqli->escape_string($txt)); }

  // vrací hodnotu 'NULL' nebo '<quoted string>'
  public function sql_string($txt) {
    if(!$txt || trim($txt)=="")
      return 'NULL';
    else
      return "'" . $this->escape(trim($txt)) . "'";  }

  public function error() {
    return $this->mysqli->error; }

  private function printsql($sql) {
    if($this->showsql)
      printf("<p><font color=\"#0000ff\">%s</font></p>\n",
        htmlentities($sql));    }

  private function printerror($txt) {
    if($this->showerror)
      printf("<p><font color=\"#ff0000\">%s</font></p>\n",
        htmlentities($txt));  }

  public function showStatistics() {
    $totalTime = $this->microtime_float() - $this->starttime;
    printf("<p><font color=\"#0000ff\">Příkazy SQL: %d\n",
      $this->sqlcounter);
    printf("<br />Součet vracených řádků: %d\n",
      $this->rowcounter);
    printf("<br />Čas vykonávání dotazů (MySQL): %f\n",
      $this->dbtime);
    printf("<br />Doba zpracování (PHP): %f\n",
      $totalTime - $this->dbtime);
    printf("<br />Celkový čas od vytvoření MyDB / poslední reset: %f</font></p>\n",
      $totalTime);    }

  public function resetStatistics() {
    $this->sqlcounter = 0;
    $this->rowcounter = 0;
    $this->dbtime     = 0;
    $this->starttime = $this->microtime_float();  }

  private function microtime_float() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec); }

}
?>



zadám:
<?php
 $db = MyDB::_();
 $db->set_charset('utf8');
// zjitšění počtu sekcí
$sql = "SELECT COUNT(*) FROM test";
$n = $db->querySingleItem($sql);
echo "<p>Tabulka se sekcemi obsahuje $n položek.</p>\n";
?>


a hodí mi to chybu:
Fatal error: Call to a member function query() on a non-object in C:\Software\VertrigoServ\www\prace\sp new\class\MyDB.php on line 99

původní připojení k mysqli bylo:
  function __construct() {
    require_once('password.php');
    $this->mysqli = @new mysqli($mysqlhost, $mysqluser, $mysqlpasswd, $mysqldb);
    // je připojení v pořádku?
    if(mysqli_connect_errno()) {
      $this->printerror("Spojení nebylo navázáno! (" . mysqli_connect_error() . ")");
      $this->mysqli = FALSE;
      exit();
    }
    $this->starttime = $this->microtime_float();
  }

  // destruktor
  function __destruct() {
    $this->close();
   }


Díky
joe
Profil
Zkus si napsat třeba místo tohoto řádku (v querySingleItem())
$result = $this->mysqli->query($sql);

tohle
var_dump($this->mysqli);

Co ti to napsalo? Skutečně je v mysqli objekt?

Proč to konec konců nevoláš takhle
$db = new MyDB();
$db->set_charset('utf8');
// zjitšění počtu sekcí
$sql = "SELECT COUNT(*) FROM test";
$n = $db->querySingleItem($sql);
echo "<p>Tabulka se sekcemi obsahuje $n položek.</p>\n";


Nechápu využití metody _()

---

Jinak chápu, člověk se to musí někde naučit, jen doufám, že takové věci nehodláš používat :-)
S tím class/clas jsem si říkal, že tam asi bude problém.
Ověříš to tak, že otestuješ, jestli v poli je položka obsažená. Při zapnutí hlášení chyb by to vyvolalo Notice, kdyby v poli nebyla, takže
if(isset(element[$x])) { // existuje


Jan Tvrdík
přesto někteří programátoři (joe, Já…) považují za chybu
Tvrdil jsem to někde? :-) Možná jo - teď si nevzpomínám, ale teď to za chybu nepovažuju, jen mi přijde přehlednější to tam uvádět

Vzhledem k tomu, jak je napsaná, tak ti práci nijak neusnadní. Pokud se ale podobná třída napíše dobře, tak dokáže usnadnit spoustu práce.
Je možné, že třída je napsaná dobře, ale ulehčí ti fakt čas a psaní, tedy je k něčemu? S Nette jsem si chvíli hrál, tak o něm něco vím, ale přesto mi tahle třída přijde zbytečná a jednodušší je napsat vypis('<element attribute="value">...</element>'). Možná, že to má nějaké využití při AJAXu, to nevím, ale i tak, mi to přijde zbytečné psát místo jediného řádku pro výpis řádků 602 a pak se ještě s tím nějaký čas učit, jak že se to má vlastně napsat, aby to vypsalo to, co chci.
Aesir
Profil
joe:

Nechápu využití metody _()

Hledejte návrhový vzor singleton.


přesto mi tahle třída přijde zbytečná

většinou se podobné používají pro generování dynamických věcí (například formulářů) u nichž potřebujete dělat častěji změny společných věcí na jednom místě
joe
Profil
Aesir
singleton chápu, pravda, nevím u čeho jsem se zarazil.

většinou se podobné používají pro generování dynamických věcí (například formulářů) u nichž potřebujete dělat častěji změny společných věcí na jednom místě
Tam to asi využití má, ale postupoval bych jiným způsobem, pro mě lepším, "šablonami" v tomto případě.
Aesir
Profil
joe:
pro mě lepším, "šablonami" v tomto případě

I to je způsob, pokud vám nevadí míchání aplikační logiky do šablon.
Jack06
Profil
joe
Původní funkční kód je:
<?php

class MyDb {
  protected $mysqli;
  protected $showerror = TRUE;   // nastavte FALSE, pokud nechcete zobrazovat chybová hlášení
  protected $showsql   = FALSE;  // nastavte TRUE, pokud chcete kvůli ladění zobrazovat všechny dotazy SQL
  protected $sqlcounter = 0;     // počítadlo příkazů SQL
  protected $rowcounter = 0;     // počítadlo vrácených řádků SELECT
  protected $dbtime     = 0;     // počítadlo času potřebného pro vykonání dotazů
  protected $starttime;

  // konstruktor
  function __construct() {
    require_once('password.php');
    $this->mysqli = @new mysqli($mysqlhost, $mysqluser, $mysqlpasswd, $mysqldb);
    // je připojení v pořádku?
    if(mysqli_connect_errno()) {
      $this->printerror("Spojení nebylo navázáno! (" . mysqli_connect_error() . ")");
      // sem můľete přidat výstup pro kód HTML pro uzavření stránky
      // (</body></html> apod.)
      $this->mysqli = FALSE;
      exit();
    }
    $this->starttime = $this->microtime_float();
  }

  // destruktor
  function __destruct() {
    $this->close();
   }

  // dodatečné uzavření
  function close() {
    if($this->mysqli)
      $this->mysqli->close();
      $this->mysqli = FALSE;
  }

  function getMysqli() {
    return $this->mysqli; }

  // vykonání dotazu SELECT, vrací se pole
  function queryObjectArray($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result) {
      if($result->num_rows) {
        while($row = $result->fetch_object())
          $result_array[] = $row;
        $this->rowcounter += sizeof($result_array);
        return $result_array; }
      else
        return FALSE;
    } else {
      $this->printerror($this->mysqli->error);
      return FALSE;
    }
  }

  // vykonání dotazu SELECT, vrací se pole
  function queryArray($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result) {
      if($result->num_rows) {
        while($row = $result->fetch_array())
          $result_array[] = $row;
        $this->rowcounter += sizeof($result_array);
        return $result_array; }
      else
        return FALSE;
    } else {
      $this->printerror($this->mysqli->error);
      return FALSE;
    }
  }


  // vykonání dotazu SELECT, který vrací pouze jednu poloľku
  // (tj. SELECT COUNT(*) FROM table); vrací
  // tuto poloľku
  // pozor: tato metoda při chybě vrací hodnotu -1 (a nikoliv 0)!
  function querySingleItem($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result) {
      if ($row=$result->fetch_array()) {
        $result->close();
        $this->rowcounter++;
        return $row[0];
      } else {
        // dotaz nevrátil ľádná data
        return -1;
      }
    } else {
      $this->printerror($this->mysqli->error);
      return -1;
    }
  }

  // vykonání příkazu SQL bez výsledků (ľádný dotaz)
  function execute($sql) {
    $this->sqlcounter++;
    $this->printsql($sql);
    $time1  = $this->microtime_float();
    $result = $this->mysqli->real_query($sql);
    $time2  = $this->microtime_float();
    $this->dbtime += ($time2 - $time1);
    if($result)
      return TRUE;
    else {
      $this->printerror($this->mysqli->error);
      return FALSE;
    }
  }

  // pouľití insert_id za příkazem INSERT 
  function insertId() {
    return $this->mysqli->insert_id; }

  // vloľení \ před ', " atd.
  function escape($txt) {
    return trim($this->mysqli->escape_string($txt)); }

  // vrací hodnotu 'NULL' nebo '<quoted string>'
  function sql_string($txt) {
    if(!$txt || trim($txt)=="")
      return 'NULL';
    else
      return "'" . $this->escape(trim($txt)) . "'";  }

  function error() {
    return $this->mysqli->error; }

  private function printsql($sql) {
    if($this->showsql)
      printf("<p><font color=\"#0000ff\">%s</font></p>\n",
        htmlentities($sql));    }

  private function printerror($txt) {
    if($this->showerror)
      printf("<p><font color=\"#ff0000\">%s</font></p>\n",
        htmlentities($txt));  }

  function showStatistics() {
    $totalTime = $this->microtime_float() - $this->starttime;
    printf("<p><font color=\"#0000ff\">Příkazy SQL: %d\n",
      $this->sqlcounter);
    printf("<br />Součet vracených řádků: %d\n",
      $this->rowcounter);
    printf("<br />Čas vykonávání dotazů (MySQL): %f\n",
      $this->dbtime);
    printf("<br />Doba zpracování (PHP): %f\n",
      $totalTime - $this->dbtime);
    printf("<br />Celkový čas od vytvoření MyDB / poslední reset: %f</font></p>\n",
      $totalTime);    }

  function resetStatistics() {
    $this->sqlcounter = 0;
    $this->rowcounter = 0;
    $this->dbtime     = 0;
    $this->starttime = $this->microtime_float();  }

  private function microtime_float() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec); }

}

// připojení k MySQL
$db = new MyDb();

// zjitšění počtu sekcí
$sql = "SELECT COUNT(*) FROM categories";
$n = $db->querySingleItem($sql);
echo "<p>Tabulka se sekcemi obsahuje $n poloľek.</p>\n";
?>


A to funguje.

Proč to konec konců nevoláš takhle :... // private function __construct() // třídu MySQLi nemám nikde napsanou tu si to bere ani nevím odkud samo
Aesir
Profil
Jack06:

třídu MySQLi nemám nikde napsanou tu si to bere ani nevím odkud samo

Je to rozšíření PHP, což může být jedním z důvodů té chyby, která všeobecně znamená, že se snažíte volat metodu nad něčím, co není objektem. Dejte na radu v [#13]
Jack06
Profil
Kdybych chtěl aktuální připojení k mysql ošetřit taky aby se provedlo jen jednou tak to zapouzdřím stejně jako tu třídu co nefunguje
joe
Profil
Aesir
I to je způsob, pokud vám nevadí míchání aplikační logiky do šablon.

Ne, nezdá se mi, že bych tím míchal aplikační logiku do šablon. Šablona by zůstala šablonou, třeba pro zmíněný formulář by se v šabloně jen iterovalo (např.) a vypisovaly se nějaká data.
Naopak si myslím, že pokud se vytvoří třída pro generování některých elementů (viz Nette), tak se tím míchají šablony s aplikační logikou. Pro mě je tedy lepší když v šabloně hned vidím, co bude výsledkem a na nějaké místa si vypíšu data, než neurčitou dobu zkoumat, co mi z toho vlastně vyleze.

ad singleton. Už vím proč jsem to napsal, pokud se teď nepletu, jde to napsat i bez té metody, aby to byl singleton. Já si to tak podobně píšu.

Jack06
Tak teď tě nechápu, proč tedy nevyužiješ toho co funguje? :-) Je to kvůli tomu, aby se ti pokaždý nepřipojovalo k db nebo proč to chceš mít jinak než ten kód, který funguje?
Jack06
Profil
joe
Potřebuji, aby se instance připojení k mysqli vytvořila jen jednom aby byla menší zátěž na databázi. když budu refreshovat stránku s připojením k databázi dejme tomu často viz chatová místnost každých 5-20 vteřin, tak to bude pořád zatěžovat databázi není-li tak?? Vím že mi to třebas občas npsalo něco o překročení maximálního počtu připojení k databázi.. po vytvoření této instance k připojení jne jednou se mi již hláška nezobrazila
Pinqui
Profil
KOukám pěkně se tu rozvinula konverzace.
Mastodont
Prosimtě ten příklad co jsí napsal mi hází chybu:
Parse error: syntax error, unexpected '=', expecting ')' in C:\Software\VertrigoServ\tts\index.php on line 6
to je řádek:
$defaults = Array ( 'id' => 0, 'class' => 0, 'text' => 0, 'close' = 0);

NWM proč ...??
joe
Profil
'close' => 0
Pinqui
Profil
joe
ježiš ajo díky moc
joe
Profil
Jack06
S takovým dotazem jsi mě teď docela zaskočil :) sám nevím jak to pořádně funguje, ale řekl bych, že při každém načtení stránky se musí pokaždé připojit k databázi. Je třeba si uvědomit, že po žádosti se vykoná kód a ten pak skončí tím, že se zobrazí stránka (tj. tedy jako kdyby se spustil program, něco se provedlo a program se ukončil).
Vím, že existuje persistentní připojení k databázi, ale už nevím jak funguje, zda se připojení někam uloží a pak se znovu nepřipojuje při další žádosti (?) - nezkoumal jsem to.

Spíš si myslím, že problém byl, že jsi se připojoval k databázi vždycky, pokud jsi se na ni nějak dotazoval nebo ne?

Vaše odpověď


Prosím používejte diakritiku a interpunkci.

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