Lazy Loading
Lazy Loading je postup, kdy data nenahráváme ihned, ale až když jsou potřeba. Jak tento postup využít u jednoduchého ORM? V PHP stačí správně využít přetěžování:
<?php class ORM { protected $id; protected $table; protected $data = array(); function __construct($table, $id = null) { $this->table = $table; $this->id = $id; } function __get($name) { $this->load(); return $this->data[$name]; } function __isset($name) { $this->load(); return isset($this->data[$name]); } function __set($name, $value) { $this->data[$name] = $value; } function __unset($name) { unset($this->data[$name]); } protected function load() { if ($this->data) { return false; } if (isset($this->id)) { $this->data = mysql_fetch_assoc(mysql_query(" SELECT * FROM $this->table WHERE id = " . intval($this->id) . " ")); } else { $result = mysql_query("EXPLAIN $this->table"); while ($row = mysql_fetch_assoc($result)) { $this->data[$row["Field"]] = $row["Default"]; } mysql_free_result($result); } } function save() { $set = array(); foreach ($this->data as $key => $val) { $set[] = "$key = " . (isset($val) ? "'" . mysql_real_escape_string($val) . "'" : "NULL"); } if (isset($this->id)) { if (!$set) { return 0; } mysql_query(" UPDATE $this->table SET " . implode(", ", $set) . " WHERE id = " . intval($this->id) . " "); } else { mysql_query("INSERT INTO $this->table " . ($set ? "SET " . implode(", ", $set) : "() VALUES ()" )); $this->id = mysql_insert_id(); $this->data["id"] = $this->id; } return mysql_affected_rows(); } function delete() { if (isset($this->id)) { mysql_query("DELETE FROM $this->table WHERE id = " . intval($this->id)); $this->id = null; return mysql_affected_rows(); } return 0; } } ?>
Kód není myšlen jako kompletní ORM, ale jen jako ukázka toho, že data není nutné načítat dříve, než je to nezbytně nutné. SQL příkazy předpokládají, že v tabulce bude existovat Auto Increment sloupec s názvem id
. Tomuto záměru je kód podřízen, takže např. o neexistenci záznamu se dozvíme až v momentě, kdy se z něj pokusíme načíst hodnotu (a ne hned při vytvoření objektu) – je to kvůli aktualizacím, při kterých není potřeba původní záznam načítat. Ukázka použití:
<?php // vytvoření uživatele $uzivatel = new ORM("uzivatel"); $uzivatel->jmeno = "Jakub"; $uzivatel->save(); // načtení stávajícího uživatele $uzivatel = new ORM("uzivatel", 1); echo $uzivatel->jmeno; $uzivatel->jmeno = "Franta"; $uzivatel->save(); ?>
Diskuse
Mr.Vain:
Az nato, ze v tom druhom bloku malo byt load. A na druhej strane je to dost blbost. ;)
Jakub Vrána
:
Zjevně jsi článek vůbec nepochopil. Metoda load() se volá automaticky, když je to potřeba. Zvenku objektu zavolat ani nejde.


paranoiq:
lazy loading je samozřejmě dobrá věc, ale je třeba zvážit, kde má jeho využití rozumný konecmě se třeba vůbec nelíbí představa, že vytvářím objekt za účelem updatu, který reprezentuje NEEXISTUJÍCÍ řádek v databázi, aby při prvním pokusu s jeho obsahem cokoliv udělat selhal - měl selhat už v konstuktoru!
// načtení stávajícího uživatele
$uzivatel = new ORM("uzivatel", 1);
pokud uživatel s id=1 neexistuje, vede to k situaci, která je absurdní. není to čisté řešení a je mi jedno, kolik výkonu bych tím ušetřil. pokud načítám řádek z databáze a konstruuji z něj objekt, musím ověřit alespoň jeho existenci
Jakub Vrána
:
Ano, v článku je uvedeno, že lazy loadingu je kód podřízen. Také vidím stejný potenciální problém, nicméně ve většině případů nemusí být nijak zásadní, protože o neexistenci záznamu se dozvím při prvním přístupu k vlastnosti. Naopak to dovoluje dělat rychlé UPDATE bez potřeby načítat data.
Ve svém projektu bych ale takhle extrémní lazy loading asi taky nepoužil.


v6ak:
Jo a je tu vlastně možnost zjistit při update, že ten řádek neexistuje? Nepočítám nějaký hack s nastavením a_number = -a_number, které by (pokud by bylo nenulové) zajistilo updatování vždy.

Jakub Vrána
:
V PHP bohužel jedině parsováním mysql_info().


v6ak:
Hmm, v dibi asi ne, že?

Jakub Vrána
:
Ale jo, dělá to metoda getInfo().


Vojta:
Tohle Tvé řešení se mi líbí, ještě jsem nic podobného nezkoušel a myslím, že jsem si trochu rozšířil obzory :). Já používám "modely" - malé třídy, které neumí nic jiného než si pamatovat pár definovaných hodnot se "settery", "gettery" a vlastní validací. Tyto třídy pak načítám a ukládám do DB pomocé "handlerů", což jsou třídy s přístupem do databáze. Ten Tvůj jednoduchý ORM by bylo potřeba rozšířit v případě použití cizích klíčů - nabízí se tedy například vytvoření nějaké hiearchie ORM tříd (ani by nemusely být specifické pro každý projekt, stačilo by nějak chytře reprezentovat případy 1:1, 1:N a N:N).
Diskuse je zrušena z důvodu spamu.

