Missä mene pieleen. Minulla on yhteydenmuodostusluokka sekä henkilötietoluokka. Yritän antaa henkilötietoluokalle, yhteydenmuodostusluokasta arvon $conn, siinä kuitenkaan onnistumatta.
<?php class Connection{ public function __construct(){ } // Tietokantayhteyden muodostaminen public function connect(){ try{ $conn = new PDO("mysql:host=localhost;dbname=jmo", "root", "", array( PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, )); }catch (PDOException $e){ die("ERROR: " . $e->getMessage()); } // Virheenkäsittely: virheet aiheuttavat poikkeuksen kyselyssä $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $conn; } } ?>
<?php include("connect.class.php"); class Persons extends Connection { public function __construct(){ } public function Customers(){ try{ $sql = $conn->prepare("SELECT CONCAT(snimi,' ',nimi') as henkilo FROM asiakkaat WHERE tyyppi = ?"); $sql->execute(array(0)); } catch(PDOException $e){ die("ERROR: " . $e->getMessage()); } foreach($conn->query($sql) as $r){ echo 'jee'; } } } ?>
lainaus:
Persons extends Connection
WTF?
lainaus:
Yritän antaa henkilötietoluokalle, yhteydenmuodostusluokasta arvon $conn
Luokan Connection funktio connect() kyllä palauttaa $conn -muuttujan arvon, mutta en näe että connect()-funktiota kutsuttaisiin missään.
<?php class Connection{ private static $connection; private function __construct(){ } // Tietokantayhteyden muodostaminen public static function pdo() { if(self::$connection instanceof PDO) { return self::$connection; } else { try{ self::$connection = new PDO("mysql:host=localhost;dbname=jmo", "root", "", array( PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true, )); // Virheenkäsittely: virheet aiheuttavat poikkeuksen kyselyssä self::$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return self::$connection; } catch (PDOException $e){ die("ERROR: " . $e->getMessage()); } } } } ?>
<?php include("connect.class.php"); class Persons { public function __construct(){ } public function Customers(){ try{ $conn = Connection::pdo(); $sql = $conn->prepare("SELECT CONCAT(snimi,' ',nimi') as henkilo FROM asiakkaat WHERE tyyppi = ?"); $sql->execute(array(0)); } catch(PDOException $e){ die("ERROR: " . $e->getMessage()); } foreach($conn->query($sql) as $r){ echo 'jee'; } } } ?>
Se, missä menee pahiten pieleen on skriptisi oliosuhteet. Ethän millään voi periyttää henkilöitä tietokantayhteydestä. Periytymistä kutsutaan "is a"-suhteeksi ja jos sanotaan, että "Persons are a Connection" eli "Henkilöt ovat Tietokantayhteys", niin eikö tämä kuulosta aivan päättömältä? Toisaalta myös ihmettelen, että mikä tuon Persons-luokan merkitys tässä systeemissä on? Onko sen tarkoituksena mallintaa henkilöjoukkoa vai yksittäistä henkilöä? Fiksumpaa olisi luoda yksittäisestä henkilöstä luokka nimeltään Person ja jokaista henkilöä varten luodaan oma Person-olio. Nämä taaseen voidaan lisätä vaikka taulukkoon tai jos tarvitaan jotain erityistä kontaineria, niin sitä varten voidaan luoda vaikka luokka nimeltään PersonContainer tms... Yleisesti ottaen luokkien nimet tulisi pitää yksikössä (tosin englanninkieli saattaa tehdä poikkeuksia). Myös jokin tuossa tietokantayhteyden antamisessa Persons-oliolle tuntuu oudolta...
Mikset muuten hyödynnä lainkaan konstruktoreita, vaikka kuitenkin kirjoitat ne koodiin?
Triton kirjoitti:
Se, missä menee pahiten pieleen on skriptisi oliosuhteet.
Kyllä! Tähän yhdyn täysin rinnoin,
Triton kirjoitti:
Toisaalta myös ihmettelen, että mikä tuon Persons-luokan merkitys tässä systeemissä on? Onko sen tarkoituksena mallintaa henkilöjoukkoa vai yksittäistä henkilöä?
Tätä ei kannata ihmetellä vaikka kyselystä WHERE ehto löytyykin. Tarkoitus todellakin on hakea useampi kuin yksi henkilö.
Triton kirjoitti:
Myös jokin tuossa tietokantayhteyden antamisessa Persons-oliolle tuntuu oudolta...
kerrotko minulle mikä siinä on outoa. Otan mielelläni tämän haittapuolet tietooni ennen kuin jatkan. Tämän vuoksi haluan mielelläni tietää onko siitä jotain haittaa. Kyselyn muodotamiseen tarvitsee jokatapauksessa tietokantayhteyden, enkä näe ongelmaa miksi se ei voisi tapahtua näin. Mutta valaiskaa ihmeessä jos siitä on haittaa. "Osaan" ohjelmoida, mutta haluan oppia ohjelmoimaan oikein.
Triton kirjoitti:
Mikset muuten hyödynnä lainkaan konstruktoreita, vaikka kuitenkin kirjoitat ne koodiin?
Tässä vaiheessa niitä en tarvitse, eikä konstruktorin valmiiksi kirjoittaminen ole haitannut minua. Se on makukysymys.
Mod. huom: Käytä lainaustageja ja lainaa järkevästi!
Oletko koskaan kuullut ORM:stä? Se auttaa varmasti jonkin verran hahmottamaan olioiden ja tietokannan käyttämistä. Yksinkertaistettuna sen ideana on muuttaa relaatiotietokannan tietueet olioiksi ja päinvastoin. Se, mikä tässä nyt on suurin ongelma on se, että kun periytät tuon tietokantayhteyden, niin nyt jokaisella oliolla tulee olemaan oma tietokantayhteys, joka taas turhaan kuluttaa resursseja. (Tuossa toteutuksessasi et itseasiassa edes pääse käsiksi koko tietokantayhteyteen, kun et ole tallettanut yhteysolion kahvaa minnekään). Oikeammin pitäisi tehdä niin, että yhteen tietokantaan käytetään vain yhtä yhteysresurssia eli tässä kontekstissa yhteysoliota. Eli instantoisit tuon yhteysolion tuon Persons-luokan ulkopuolella ja antaisit sen sille viiteparametrina konstruktorissa.
Kiitos! Juuri tälläistä tietota kaipasin.
Haluan vielä huomauttaa, että toki noiden tietokantayhteyksia luomista pystyttäisiin rajoittamaan luomalla tuonne Connection-luokkaa staattinen eli luokkakohtainen attribuutti, johon tuo yhteysolio tallennetaan ja sitten tarkistetaan aina konstruktorissa, että ollaanko jo muodostettu yhteys... Siitä huolimatta mielestäni näin ei tulisi toimia.
Triton kirjoitti:
Eli instantoisit tuon yhteysolion tuon Persons-luokan ulkopuolella ja antaisit sen sille viiteparametrina konstruktorissa.
Yleensä kylläkin sovelluksessa on vain yksi tietokantayhteys, jolloin on hyväksyttävää ja käytännöllistäkin tehdä siitä staattinen, kuten qeijo jo näyttikin. Tietokantayhteyden käyttäjä kirjoittaa aina siis esim. Connection::pdo(), eikä ylimääräisiä parametreja tarvita.
manninen kirjoitti:
Tarkoitus todellakin on hakea useampi kuin yksi henkilö.
Kuten jo todettiinkin, yhden luokan pitäisi lähtökohtaisesti vastata yhtä tietokantataulua ja yhden olion yhtä riviä taulussa. Luokan nimeksi sopisi siis Person, ja luokassa voisi olla staattinen funktio getCustomers, joka hakisin tietokannan person-taulusta ne henkilöt, joiden tyyppi on 'customer'.
manninen kirjoitti:
tyyppi = ?
– –$sql->execute(array(0));
Merkityksettömien numeroiden käyttöä kannattaa välttää. Tässä tapauksessa henkilön tyypin pitäisi olla tietokannassa enum, jos kaikki tyypit tiedetään etukäteen, tai viittaus erilliseen tauluun person_type, jos tyyppejä halutaan lisätä jälkikäteen. Ja olipa käytössä sitten luku 0
tai teksti 'customer'
, siitä kannattaa tehdä vakio, esim. Person::TYPE_CUSTOMER, jotta mahdolliset kirjoitusvirheet jäävät saman tien kiinni.
Ehkä haluat myös, että customer sisältää erilaista tietoa kuin tavallinen person, jolloin looginen ratkaisu olisi tehdä erillinen customer-taulu, jossa olisi sitten viittaus person-tauluun. Voisit silloin ohjelmassa kirjoittaa Customer::getAll() ja yksittäiselle customerille $customer->getPerson() henkilötietojen hakemiseksi. (Vielä tyylikkäämpää olisi ehkä periyttää Customer-luokka Person-luokasta, mutta tästä on jo enemmän vaivaa PHP:n puolella.)
Metabolix kirjoitti:
Triton kirjoitti:
Eli instantoisit tuon yhteysolion tuon Persons-luokan ulkopuolella ja antaisit sen sille viiteparametrina konstruktorissa.
Yleensä kylläkin sovelluksessa on vain yksi tietokantayhteys, jolloin on hyväksyttävää ja käytännöllistäkin tehdä siitä staattinen, kuten qeijo jo näyttikin. Tietokantayhteyden käyttäjä kirjoittaa aina siis esim. Connection::pdo(), eikä ylimääräisiä parametreja tarvita.
Kyllähän tuo ehdotuksenikin tähtäsi nimenomaan siihen, että käytetään vain yhtä tietokantayhteyttä per tietokanta. Tuo, miten tähän pyrkimykseen päästään on kuitenkin vain makuasia. Pääasia on kuitenkin se, että jollain tavalla päästään tuohon yhteysolion kahvaan käsiksi.
edit.
Metabolix kirjoitti:
Kuten jo todettiinkin, yhden luokan pitäisi lähtökohtaisesti vastata yhtä tietokantataulua ja yhden olion yhtä riviä taulussa. Luokan nimeksi sopisi siis Person, ja luokassa voisi olla staattinen funktio getCustomers, joka hakisin tietokannan person-taulusta ne henkilöt, joiden tyyppi on 'customer'.
Minusta olisi vielä loogisempaa tehdä tämä niin, että tuo Person-luokka toimisi ainostaan yhden Person-olion mallina eli tarjoaisi kyseiseen olioon liittyvät palvelut jne... Sitten erikseen luotaisiin oma luokka, joka mallintaisi tietokannan persons-taulua ja sen tehtävänä olisi juuri muuntaa Person-oliot tietueiksi ja päinvastoin sekä suorittaa tarpeelliset tietokantaoperaatiot eli aivan kuten ORM yleensäkin toimii.
Metabolix kirjoitti:
Triton kirjoitti:
Eli instantoisit tuon yhteysolion tuon Persons-luokan ulkopuolella ja antaisit sen sille viiteparametrina konstruktorissa.
Yleensä kylläkin sovelluksessa on vain yksi tietokantayhteys, jolloin on hyväksyttävää ja käytännöllistäkin tehdä siitä staattinen, kuten qeijo jo näyttikin. Tietokantayhteyden käyttäjä kirjoittaa aina siis esim. Connection::pdo(), eikä ylimääräisiä parametreja tarvita.
Dependency injection on kaunista, myös tässä tilanteessa.
Samoin yhteysparametrit kannattaisi antaa... aurinkolasit jne... parametreinä.
Aihe on jo aika vanha, joten et voi enää vastata siihen.