8. Oliot 123. Kuinka luokkia luodaan ja olioita saadaan aikaan. Kuinka luodaan ja käsitellään ominaisuuksia ja metodeja

Samankaltaiset tiedostot
6. Funktiot 85. Kuinka funktioita määritellään ja kutsutaan. Kuinka funktioille viedään arvoja ja niistä palautetaan arvoja

7. Taulukot 105. Kuinka taulukoiden tietoa käsitellään ja lajitellaan

OPPITUNTI 5 Ohjelman kulku

15. Ohjelmoinnin tekniikkaa 15.1

Sisällys. 1. Omat operaatiot. Yleistä operaatioista. Yleistä operaatioista

Ohjelmoinnin perusteet Y Python

OPPITUNTI 3 Ensimmäinen skripti

1. Omat operaatiot 1.1

9. Periytyminen Javassa 9.1

Ohjelmoinnin perusteet Y Python

15. Ohjelmoinnin tekniikkaa 15.1

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

OPPITUNTI 11 DBM-funktioiden käyttö

Ohjelmoinnin perusteet Y Python

Harjoitus 5 (viikko 48)

Sisältö. 2. Taulukot. Yleistä. Yleistä

ITKP102 Ohjelmointi 1 (6 op)

Ohjelmointi 2 / 2010 Välikoe / 26.3

Taulukot. Jukka Harju, Jukka Juslin

3.1 Mitä tarkoittaan heredoc? Milloin sitä kannattaa käyttää? Kirjoita esimerkki sen käyttämisestä.

Pong-peli, vaihe Aliohjelman tekeminen. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 3/7. Tämän vaiheen aikana

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Osa. Listaus 2.1. HELLO.CPP esittelee C++ -ohjelman osat. 14: #include <iostream.h> 15: 16: int main() 17: {

Ohjelmoinnin perusteet Y Python

Ohjelmointikielet ja -paradigmat 5op. Markus Norrena

Sisältö. 22. Taulukot. Yleistä. Yleistä

Yleistä. Nyt käsitellään vain taulukko (array), joka on saman tyyppisten muuttujien eli alkioiden (element) kokoelma.

Harjoitustyö: virtuaalikone

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin jatkokurssi, kurssikoe

ITKP102 Ohjelmointi 1 (6 op)

9. Periytyminen Javassa 9.1

OPPITUNTI 16 Tiedon käsittely

Ohjelmoinnin perusteet Y Python

Written by Administrator Monday, 05 September :14 - Last Updated Thursday, 23 February :36

Sisällys. 9. Periytyminen Javassa. Periytymismekanismi Java-kielessä. Periytymismekanismi Java-kielessä

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

Javan perusteita. Janne Käki

ITKP102 Ohjelmointi 1 (6 op)

C-kielessä taulukko on joukko peräkkäisiä muistipaikkoja, jotka kaikki pystyvät tallettamaan samaa tyyppiä olevaa tietoa.

on ohjelmoijan itse tekemä tietotyyppi, joka kuvaa käsitettä

ITKP102 Ohjelmointi 1 (6 op)

Aalto Yliopisto T Informaatioverkostot: Studio 1. Oliot ja luokat Javaohjelmoinnissa

11. oppitunti III. Viittaukset. Osa. Mikä on viittaus?

Olio-ohjelmointi Javalla

ELM GROUP 04. Teemu Laakso Henrik Talarmo

Sisällys. JAVA-OHJELMOINTI Osa 7: Abstrakti luokka ja rajapinta. Abstraktin luokan idea. Abstrakti luokka ja metodi. Esimerkki

Harjoitus Olkoon olemassa luokat Lintu ja Pelikaani seuraavasti:

Metodit. Metodien määrittely. Metodin parametrit ja paluuarvo. Metodien suorittaminen eli kutsuminen. Metodien kuormittaminen

Ohjelmoinnin peruskurssi Y1

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Ohjelmoinnin perusteet Y Python

Opintojakso TT00AA11 Ohjelmoinnin jatko (Java): 3 op. Tietorakenneluokkia 2: HashMap, TreeMap

Operaattoreiden ylikuormitus. Operaattoreiden kuormitus. Operaattoreiden kuormitus. Operaattoreista. Kuormituksesta

Sokkelon sisältö säilötään linkitetyille listalle ja tekstitiedostoon. Työ tehdään itsenäisesti yhden hengen ryhmissä. Ideoita voi vaihtaa koodia ei.

Tietueet. Tietueiden määrittely

Ohjelmoinnin perusteet Y Python

Java-kielen perusteet

Osoitin ja viittaus C++:ssa

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Ohjelmoinnin peruskurssi Y1

Sisällys. JAVA-OHJELMOINTI Osa 6: Periytyminen ja näkyvyys. Luokkahierarkia. Periytyminen (inheritance)

Ohjelmoinnin perusteet Y Python

Ohjelmoinnin perusteet Y Python

12. Javan toistorakenteet 12.1

Ohjelmassa henkilön etunimi ja sukunimi luetaan kahteen muuttujaan seuraavasti:

Toinen harjoitustyö. ASCII-grafiikkaa 2017

Harjoitus 5 (viikko 41)

ASCII-taidetta. Intro: Python

Chapel. TIE Ryhmä 91. Joonas Eloranta Lari Valtonen

Java kahdessa tunnissa. Jyry Suvilehto

Esimerkkiprojekti. Mallivastauksen löydät Wroxin www-sivuilta. Kenttä Tyyppi Max.pituus Rajoitukset/Kommentit

Maastotietokannan torrent-jakelun shapefile-tiedostojen purkaminen zip-arkistoista Windows-komentojonoilla

JAVA-PERUSTEET. JAVA-OHJELMOINTI 3op A JAVAN PERUSTEET LYHYT KERTAUS JAVAN OMINAISUUKSISTA JAVAN OMINAISUUKSIA. Java vs. C++?

14. Poikkeukset 14.1

OSA II Kieli. Oppitunti. 4. Rakennuslohkot 5. Ohjelman kulku 6. Funktiot 7. Taulukot 8. Oliot

815338A Ohjelmointikielten periaatteet Harjoitus 5 Vastaukset

OPPITUNTI15 Päivämäärien käsittely

Sonera Viestintäpalvelu VIP VIP Laajennettu raportointi Ohje

System.out.printf("%d / %d = %.2f%n", ekaluku, tokaluku, osamaara);

19. Olio-ohjelmointia Javalla 19.1

Pong-peli, vaihe Koordinaatistosta. Muilla kielillä: English Suomi. Tämä on Pong-pelin tutoriaalin osa 2/7. Tämän vaiheen aikana

815338A Ohjelmointikielten periaatteet

Jypelin käyttöohjeet» Ruutukentän luominen

Tietorakenteet. JAVA-OHJELMOINTI Osa 5: Tietorakenteita. Sisällys. Merkkijonot (String) Luokka String. Metodeja (public)

7. Näytölle tulostaminen 7.1

Tietojen syöttäminen ohjelmalle. Tietojen syöttäminen ohjelmalle Scanner-luokan avulla

18. Abstraktit tietotyypit 18.1

Rajapinnasta ei voida muodostaa olioita. Voidaan käyttää tunnuksen tyyppinä. Rajapinta on kuitenkin abstraktia luokkaa selvästi abstraktimpi tyyppi.

812341A Olio-ohjelmointi Peruskäsitteet jatkoa

Ohjelmointitaito (ict1td002, 12 op) Kevät Java-ohjelmoinnin alkeita. Tietokoneohjelma. Raine Kauppinen

Harjoitus 2 (viikko 45)

Sisällys. 6. Metodit. Oliot viestivät metodeja kutsuen. Oliot viestivät metodeja kutsuen

Ohjelmoinnin perusteet Y Python

Ohjelmointi 1 / 2009 syksy Tentti / 18.12

Ruby. Tampere University of Technology Department of Pervasive Computing TIE Principles of Programming Languages

Luokka Murtoluku uudelleen. Kirjoitetaan luokka Murtoluku uudelleen niin, että murtolukujen sieventäminen on mahdollista.

Transkriptio:

8. Oliot 123 OPPITUNTI 8 Oliot Oliopohjainen ohjelmointi on vaarallista. Se muuttaa koodaamista koskevia ajatuksiasi ja kun uudet käsitteet ovat saaneet jalansijaa, ne eivät katoa mitenkään. PHP on Perlin lailla lisännyt oliopohjaisuutta syntaksiinsa ja rakenteeseensa vähitellen. PHP4 sallii oliopohjaisen koodin käyttämisen projektien pääaineksena. Tässä luvussa käsitellään PHP4:n oliopohjaisia piirteitä ja sovelletaan niitä todellisiin esimerkkeihin. Tämän tunnin aiheita ovat seuraavat: Mitä oliot ja luokat ovat Kuinka luokkia luodaan ja olioita saadaan aikaan Kuinka luodaan ja käsitellään ominaisuuksia ja metodeja Kuinka luodaan luokkia, jotka perivät toiminnallisuutensa muilta Joitakin syitä, miksi oliopohjainen ohjelmointi voi auttaa sinua organisoimaan projektejasi

124 8. Oliot Mikä olio on? Olio on joukko muuttujia ja funktioita, jotka on sijoitettu erikoislaatuiseen malliin nimeltä luokka. Oliot kätkevät suuren osan sisäisestä toiminnastaan koodiinsa, mutta tarjoavat sen sijaan helppoja liittymiä, joiden kautta oliolta voidaan pyytää palveluja ja ne voivat palauttaa tietoa. Nämä liittymät ovat erikoisfunktioita, joita nimitetään metodeiksi. Kaikilla olion metodeilla on pääsy erikoismuuttujiin, jotka ovat olion ominaisuuksia. Määrittelemällä luokan asetat joukon ominaisuuksia. Luomalla tuon tyyppisiä olioita saadaan ohjelmaan muuttujia, joilla on kaikki luokan ominaisuudet. Oliossa ominaisuuksille annetaan todelliset arvot. Ohjelmassa voidaan luoda esimerkiksi auto-luokka. Siinä voisi olla väriominaisuus. Kaikilla luotavilla autoilla olisi sitten tuo väriominaisuus ja ne voisivat sijoittaa siihen todelliset arvonsa, esimerkiksi sinisen, punaisen jne. Luokka on joukko erikoisfunktioita nimeltä metodit ja erikoismuuttujia nimeltä ominaisuudet. Voit esitellä luokan avainsanalla class. Tuo class-tietotyyppi on malli, jonka mukaisiksi oliot luodaan. Olio on muistissa eikä pelkästään koodina, joten sitä voi sanoa luokan ilmentymäksi tai esiintymäksi. Olio on siis luokan mukainen, toimiva muuttuja. Olio luodaan new-lauseella kertomalla luotavan olion malli, luokka. Kun olio on luotu, sen muuttujia ja metodeita voidaan käsitellä. Ehkä tärkein oliopohjaisen ohjelmoinnin etu on koodin uudelleenkäytettävyys. Koska luokat ovat kapselinsa sisällä, ne voidaan helposti siirtää projektista toiseen. Lisäksi on mahdollista luoda lapsiluokkia, jotka perivät ja korvaavat vanhempiensa ominaisuudet. Tuo tekniikka mahdollistaa monimutkaisempien olioiden ja erikoistapausten luomisen perusluokan pohjalta. Ehkäpä paras tapa selittää oliopohjaista ohjelmointia on kirjoittaa koodia. Olion luominen Olion luomiseksi on ensin määriteltävä malli, josta se voidaan luoda. Malli on nimeltään luokka ja PHP4:ssä se tulee esitellä avainsanalla class: class first_class. // minimaalinen luokka Luotu first_class-luokka on pohja, josta voidaan luoda haluttu määrä olioita. Olion luomisessa käytetään new-lausetta: $obj1 = new first_class(); $obj2 = new first_class(); print "\$obj1 is a ".gettype($obj1)."<br>"; print "\$obj2 is a ".gettype($obj2)."<br>";

8. Oliot 125 Voit tarkistaa, että $obj1 ja $obj2 sisältävät olioita käyttäen PHP:n gettype()-funktiota. Se ottaa argumentikseen minkä tahansa muuttujan ja palauttaa muuttujan tyypin. PHP:ssä, jossa ei ole tarkkaa tyypin tarkistusta ja määrittelyä, gettype() on hyödyllinen. Koodissamme gettype() palauttaa merkkijonon object ja se tulostetaan selaimelle. Olet nyt nähnyt, kuinka olioita luodaan. Toistaiseksi oliomme eivät ole lainkaan hyödyllisiä. Voit ajatella luokkaa ikään kuin muottina, josta voidaan painaa haluttu määrä tuotteita. Lisätkäämme nyt joitakin piirteitä luokkaan saadaksemme olioista hieman kiinnostavampia. Olioiden ominaisuudet Olioilla on pääsy erikoismuuttujiin nimeltä ominaisuudet. Ne voidaan esitellä missä tahansa luokan rungon sisällä, mutta selkeyden vuoksi ne kannattaa määritellä alussa. Ominaisuus voi olla arvo, taulukko tai jopa toinen olio: class first_class var $name = "harry"; Huomaa, että esittelimme muuttujan avainsanaa var käyttäen. Niin tulee tehdä luokan yhteydessä; teet jäsentelyvirheen, jos unohdat var-sanan käytön. Nyt jokainen first_class-luokan olio sisältää ominaisuuden nimeltä name, jonka arvona on harry. Tuohon ominaisuuteen päästään käsiksi olion ulkopuolelta ja sitä voidaan myös muuttaa: class first_class var $name = "harry"; $obj1 = new first_class(); $obj2 = new first_class(); $obj1->name = "bob"; print "$obj1->name<br>"; print "$obj2->name<br>"; Nuolioperaattori (->) mahdollistaa olion jäsenten käyttämisen. Vaikka $obj1 ja $obj2 saivat aluksi nimen harry, olemme nyt laittaneet $obj2-olion nimeksi bob. Muuttaminen tapahtui juuri nuolioperaattoria käyttäen. Sen jälkeen on olioiden name-ominaisuuksien arvot tulostettu selaimelle.

126 8. Oliot Oliopohjaiset kielet kuten Java vaativat ohjelmoijaa asettamaan suojaustason kaikille jäsenille. Jäsenten käyttöä voidaan siis rajoittaa: joidenkin jäsenten yleinen käyttö voidaan sallia, kun taas jotkin jäsenet on tarkoitettu vain sisäiseen käyttöön. PHP:ssä ei ole mahdollista käyttää sellaista suojausta, mikä voi aiheuttaa ongelmia, jos jokin ominaisuus olisi suojattava kaikilta muutoksilta. Voit käyttää olioita tiedon tallentamiseen, mutta assosiatiiviset taulukot saattavat sopia siihen paremmin. Seuraavassa jaksossa tutkitaan olioiden metodeja ja tehdään olioista hieman aktiivisempia. Olioiden metodit Metodi on funktio, joka on määritelty luokan sisällä. Jokainen olio on luokan ilmentymä ja sillä on metodien antama toimintakyky. Listaus 8.1 lisää metodin first_class-luokkaan. Listaus 8.1 Luokka, jossa on metodi 1: <html> 2: <head> 3: <title>listing 8.1</title> 4: <body> 5: <?php 6: class first_class 7: 8: var $name; 9: function sayhello() 10: 11: print "hello"; 12: 13: 14: 15: $obj1 = new first_class(); 16: $obj1->sayhello(); 17: // tulostaa "hello" 18:?> 19: </body> 20: </html>

8. Oliot 127 Kuten voit nähdä, metodi näyttää aivan tavalliselta funktiolta ja käyttäytyykin niin. Metodi määritellään kuitenkin aina luokan sisällä. Objektin metodia kutsutaan nuolioperaattoria (->) käyttäen. On tärkeää tietää, että metodeilla on pääsy luokan jäsenmuuttujiin. Olet jo nähnyt, kuinka ominaisuutta käsitellään luokan ulkopuolelta, mutta kuinka olio voi viitata itseensä? Listaus 8.2 Ominaisuuden käyttö metodista käsin 1: <html> 2: <head> 3: <title>listing 8.2</title> 4: <body> 5: <?php 6: class first_class 7: 8: var $name="harry"; 9: function sayhello() 10: 11: print "hello my name is $this->name<br>"; 12: 13: 14: 15: $obj1 = new first_class(); 16: $obj1->sayhello(); 17: // tulostaa "hello my name is harry" 18:?> 19: </body> 20: </html> Luokka käyttää erikoismuuttujaa $this viittaamaan nykyiseen olioon. Voit pitää sitä ikään kuin persoonapronominina. Vaikka viittaatkin olioon tälle annetun nimen kautta, olion on voitava joskus viitata itseensä, jolloin se tarvitsee $this-muuttujaa. Yhdistämällä $this ja nuolioperaattori (->) saadaan aikaan tekniikka, jolla voidaan käsitellä luokan metodia tai ominaisuutta luokan sisällä. Kuvittele, että haluat sijoittaa eri name-arvon jokaiselle luodulle first_class-oliolle. Voisit tehdä niin muuttamalla name-ominaisuutta suoraan manuaalisesti kuten aiemmin. Toisaalta voisit myös luoda metodin, joka tekee työn puolestasi; listaus 8.3 käyttää tätä tapaa.

128 8. Oliot Listaus 8.3 Ominaisuuden arvon muuttaminen metodin kautta 1: <html> 2: <head> 3: <title>listing 8.3</title> 4: </head> 5: <body> 6: <?php 7: class first_class 8: 9: var $name="harry"; 10: function setname( $n ) 11: 12: $this->name = $n; 13: 14: function sayhello() 15: 16: print "hello my name is $this->name<br>"; 17: 18: 19: 20: 21: $obj1 = new first_class(); 22: $obj1->setname("william"); 23: $obj1->sayhello(); 24: // tulostaa "hello my name is william" 25:?> 26: </body> 27: </html> Aluksi name-arvona on harry, mutta setname()-metodin käyttämisen jälkeen nimeksi tulee william. Huomaa, kuinka olion on mahdollista muuttaa omaa ominaisuuttaan. Huomaa myös, että veit metodille argumentteja aivan samalla lailla kuin funktiollekin. Yksi erikoisuus on vielä mainittava. Jos metodin nimi on sama kuin luokan nimi, metodi suoritetaan aina automaattisesti, kun uusi olio muodostetaan. Tällaisen metodin kautta voidaan luotava olio alustaa halutuilla

8. Oliot 129 arvoilla. Oliot ajavat koodin ja alustavat itsensä annettujen argumenttien mukaan. Näitä erikoismetodeja kutsutaan muodostimiksi. Listaus 8.4 lisää muodostimen first_class-luokkaan. Listaus 8.4 Luokka, jossa on muodostin 1: <html> 2: <head> 3: <title>listing 8.4</title> 4: </head> 5: <body> 6: <?php 7: class first_class 8: 9: var $name; 10: function first_class( $n="anon" ) 11: 12: $this->name = $n; 13: 14: function sayhello() 15: 16: print "hello my name is $this->name<br>"; 17: 18: 19: $obj1 = new first_class("bob"); 20: $obj2 = new first_class("harry"); 21: $obj1->sayhello(); 22: // tulostaa "hello my name is bob" 23: $obj2->sayhello(); 24: // tulostaa "hello my name is harry" 25:?> 26: </body> 27: </html> Esimerkkimme first_class-muodostinta kutsutaan automaattisesti, kun first_class-olio luodaan. Olemme laittaneet muodostimeen oletusarvon anon, jota käytetään parametrin arvona, jos muuta arvoa ei anneta.

130 8. Oliot Esimerkki Käyttäkäämme nyt edellä kuvattuja tekniikoita ja luokaamme esimerkki, joka on hieman hyödyllisempi. Luomme luokan, joka ylläpitää taulukon kenttiä, jotka on järjestelty nimettyihin sarakkeisiin. Tiedot tulee muodostaa rivi riviltä ja mukana tulee olla metodi, joka tulostaa tiedot selaimelle. Tiedon muotoilu ei ole tässä vaiheessa välttämätöntä. Luokan ominaisuuksien määrittely Ensiksi meidän tulee päättää, mitä ominaisuuksia tarvitsemme tiedon tallentamiseen. Pidämme sarakkeiden nimet taulukossa ja rivit moniulotteisessa taulukossa. Tallennamme luokkaan myös kokonaisluvun, jotta voimme saada helposti selville sarakkeiden lukumäärän. class Table var $table_array = array(); var $headers = array(); var $cols; Muodostimen luominen Meidän on annettava sarakkeiden nimet jo varhaisessa vaiheessa. Voimme antaa nimet muodostimessa laittamalla muodostimen parametriksi merkkijonotaulukon. Tuon tiedon avulla voimme sitten laskea sarakkeiden lukumäärän ja sijoittaa tuloksen cols-ominaisuuden arvoksi: function Table( $headers ) $this->headers = $headers; $this->cols = count ( $headers ); Olettaen, että oikeaa tietoa on annettu luotaessa uusi Table-olio, tiedämme heti tallennettavien sarakkeiden määrän ja kunkin sarakkeen nimen. Koska tämä tieto on tallennettu ominaisuuksiin, se on olion metodien käytettävissä. Metodi addrow() Table-olio ottaa vastaan kunkin tietorivin taulukon muodossa olettaen tietenkin, että tuo tieto tulee samassa järjestyksessä kuin sarakkeiden nimet:

8. Oliot 131 function addrow( $row ) if ( count ($row)!= $this->cols ) return false; array_push($this->table_array, $row); return true; Metodi addrow() ottaa argumentikseen taulukon, joka tallennetaan parametriin nimeltä $row. Olemme tallentaneet sarakkeiden määrän $cols-ominaisuuden arvoksi. Voimme tarkistaa, että $rowtaulukkoparametri sisältää oikean määrän alkioita käyttämällä count()-funktiota. Jos määrä ei ole oikea, palautetaan arvo false. Sitten käytämme PHP4:n array_push()-funktiota lisäämään rivi table_arrayominaisuuteen array_push()-funktiolla. Se ottaa kaksi argumenttia: taulukon, johon lisääminen tapahtuu ja lisättävän arvon. Jos toisena argumenttina on itse taulukko, se lisätään ensimmäisen taulukon yksittäisenä alkiona, jolloin syntyy moniulotteinen taulukko. Tällä tavalla voimme muodostaa taulukoista koostuvan taulukon. Metodi addrowassocarray() Luokan addrow()-metodi toimii oikein niin kauan kuin metodille vietävät taulukon alkiot ovat oikeassa järjestyksessä. Metodi sallii hieman joustavuutta. Se odottaa assosiatiivista taulukkoa. Kunkin arvon avainten tulisi vastata yhtä niistä otsikkonimistä, jotka tallennamme otsikoiksi. Muutoin ne ohitetaan: function addrowassocarray( $row_assoc ) $row = array(); foreach ( $this->headers as $header ) sif (! isset( $row_assoc[$header] )) $row_assoc[$header] = ""; $row[] = $row_assoc[$header]; array_push($this->table_array, $row); return true; Assosiatiivinen taulukko, joka viedään addrowassocarray()-metodille, tallennetaan parametriin nimeltä $row_assoc. Luomme tyhjän taulukon nimeltä $row tallentamaan arvot, jotka voimme lisätä table_arrayominaisuuteen. Käymme läpi otsikkotaulukon tarkistaaksemme, että kutakin merkkijonoa vastaava arvo on

132 8. Oliot olemassa $row_assoc-taulukossa. Tarkistukseen käytämme PHP4:n isset()-funktiota, joka ottaa argumentikseen minkä tahansa muuttujan. Se palauttaa arvon true, jos viety muuttuja on asetettu ja muutoin arvon false. Nyt viemme isset()-funktiolle $row_assoc-taulukon alkion, jonka avain on esillä olevan otsikon arvona. Jos mitään tuolla merkkijonolla indeksoitua alkiota ei ole olemassa $row_assoc-taulukossa, menemme eteenpäin ja luomme alkion tyhjää merkkijonoa käyttäen. Sen jälkeen voimme jatkaa $row-taulukon kehittämistä lisäämällä siihen $row_assoc-alkion, jonka indeksinä on otsikkotaulukon nykyinen merkkijono. Kun olemme päättäneet headers-taulukon läpikäynnin, $row sisältää järjestyksessä olevan kopion arvoista, jotka tuotiin $row_assoc-parametrissa; ohitettujen arvojen kohdalla on tyhjät merkkijonot. Nyt meillä on kaksi yksinkertaista metodia, joilla voimme lisätä rivejä Table-olion table_array-ominaisuudeksi. Nyt meidän on enää kehitettävä keino tulostaa tiedot. Metodi output() Tulostukseen tarkoitettu output()-metodi tulostaa sekä otsikot että table_array-ominaisuudet selaimelle. Metodi on tarkoitettu pääosin vianetsintään. Näytämme paremman ratkaisun myöhemmin tässä luvussa. function output() print "<pre>"; foreach ( $this->headers as $header ) print "<B>$header</B> "; print "\n"; foreach ( $this->table_array as $y ) foreach ( $y as $xcell ) print "$xcell "; print "\n"; print "</pre>"; Tämä koodilohko on melkoisen selkeä. Käymme ensin läpi taulukon otsikot ja kirjoitamme alkiot näytölle. Sitten teemme saman table_array-ominaisuudelle. Koska table_array-ominaisuus on kaksiulotteinen taulukko, kukin sen alkioista on itsekin taulukko, joka tulee käydä läpi pääsilmukan sisällä. Kaikki yhdessä Listaus 8.5 sisältää koko Table-luokan sekä koodin, joka luo Table-olion ja kutsuu kutakin sen metodia.

8. Oliot 133 Listaus 8.5 Table-luokka 1: <html> 2: <head> 3: <title>listing 8.5</title> 4: </head> 5: <body> 6: <?php 7: class Table 8: 9: var $table_array = array(); 10: var $headers = array(); 11: var $cols;.black plate (141,1) 12: function Table( $headers ) 13: 14: $this->headers = $headers; 15: $this->cols = count ( $headers ); 16: 17: 18: function addrow( $row ) 19: 20: if ( count ($row)!= $this->cols ) 21: return false; 22: array_push($this->table_array, $row); 23: return true; 24: 25: 26: function addrowassocarray( $row_assoc ) 27: 28: $row = array(); 29: foreach ( $this->headers as $header ) 30: 31: if (! isset( $row_assoc[$header] )) 32: $row_assoc[$header] = "";

134 8. Oliot 33: $row[] = $row_assoc[$header]; 34: 35: array_push($this->table_array, $row); 36: return true; 37: 38: 39: function output() 40: 41: print "<pre>"; 42: foreach ( $this->headers as $header ) 43: print "<B>$header</B> "; 44: print "\n"; 45: foreach ( $this->table_array as $y ) 46: 47: foreach ( $y as $xcell ) 48: print "$xcell "; 49: print "\n"; 50: 51: print "</pre>"; 52: 53: 54: 55: $test = new table( array("a","b","c") ); 56: $test->addrow( array(1,2,3) ); 57: $test->addrow( array(4,5,6) ); 58: $test->addrowassocarray( array ( b=>0, a=>6, c=>3 ) ); 59: $test->output(); 60:?> 61: </body> 62: </html> Listauksen 8.5 tulostus on kuvassa 8.1.

8. Oliot 135 Tulostus näyttää siistiltä niin kauan kuin yksittäiset merkkijonot ovat samanpituisia. Tilanne muuttuu, kun jokin merkkijono on erikokoinen kuin muut. KUVA 8.1 Table-olio toiminnassa. Mitä puuttuu? Vaikka tämä luokka tekeekin työn tehokkaasti puolestamme, voisimme kuitenkin lisätä koodiin vielä muutamia ominaisuuksia ja varotoimia. Koska PHP on löysästi tyypitetty, on meidän vastuullamme varmistaa, että metodeillemme viedyt parametrit ovat odottamaamme tyyppiä. Tähän tarkoitukseen voimme käyttää luvun 16, Tiedon käsittely, tietofunktioita. Voimme myös tehdä Table-oliosta hieman joustavamman lisäämällä esimerkiksi metodeja, joilla lajitellaan rivejä jonkin sarakkeen arvojen mukaan ennen tulostamista. Miksi luokka? Miksi oikeastaan olisi järkevämpää käyttää oliota kuin taulukoiden suoraa manipulointia kyseisen tehtävän suorittamiseen? Oliot eivät näytä nyt lainkaan tehokkailta. Olemme kirjoittaneet myös lisäkoodia tiedon tallentamiseksi ja palauttamiseksi. Ensiksikin koodimme on nyt uudelleen käytettävää. Voimme nyt siirtää koodin mihin tahansa toiseen projektiin, jossa tietoa on käsiteltävä tällä tavalla. Toiseksi Table-olio on aktiivinen. Voimme pyytää sitä tulostamaan tietoa eikä meidän tarvitse tällöin kirjoittaa koodia table_array-ominaisuuden läpikäymiseksi. Kolmanneksi olemme kehittäneet liittymän olion toimintojen käyttämiseen. Jos haluamme myöhemmin optimoida luokan koodia, voimme tehdä sen häiritsemättä projektin muita osia niin kauan kuin samat metodit (entisine argumentteineen ja palautustyyppeineen) jäävät jäljelle. Lopuksi etuna on vielä se, että voimme kehittää luokkia, jotka perivät, laajentavat ja korvaavat perusluokan toiminnallisuutta, mikä tekee oliopohjaisesta koodista todella mahtavaa. Periyttäminen Luodaksemme luokan, joka perii toiminnallisuutensa kantaluokaltaan, meidän on muutettava luokkamäärittelyämme hieman. Listauksessa 8.6 on mukana alkuperäinen luokkamme, josta johdetaan uusi luokka.

136 8. Oliot Listaus 8.6 Luokka, joka periytyy toisesta 1: <html> 2: <head> 3: <title>listing 8.6</title> 4: </head> 5: <body> 6: <?php 7: class first_class 8: 9: var $name = "harry"; 10: function first_class( $n ) 11: 12: $this->name = $n; 13: 14: function sayhello() 15: 16: print "Hello my name is $this->name<br>"; 17: 18: 19: 20: class second_class extends first_class 21: 22: 23: 24: 25: $test = new second_class("son of harry"); 26: $test->sayhello(); 27: // tulostaa "Hello my name is son of harry" 28:?> 29: </body> 30: </html>

8. Oliot 137 Yksinkertaisen first_class-luokan lisäksi koodissa on luotu toinen perusluokka nimeltä second_class. Huomaa luokan määrittelyssä oleva extends-lause. Se tarkoittaa, että second_class perii kaiken toiminnallisuutensa first_class-luokalta. Jokaisella second_class-oliolla on sayhello()-metodi ja nameominaisuus kuten first_class-oliollakin. Listauksessa 8.6 on muutakin tärkeää. Huomaa, että emme määritelleet muodostinta second_class-luokalle. Kuinka name-ominaisuus sitten muuttui oletusarvostaan, kun second_class-oliolle vietiin luomisen yhteydessä teksti son of harry? Koska emme antaneet second_class-luokalle omaa muodostinta, käytettiin second_class-olion luomisessa first_class-muodostinta automaattisesti. Jos jokin toista luokkaa laajentava luokka ei sisällä omaa muodostinta, käytetään kantaluokan muodostinta olioiden luomisessa; kantaluokan muodostinta kutsutaan automaattisesti aina, kun lapsiluokan olio luodaan. Tämä on PHP4:n mukana tullut piirre. Kantaluokan metodin korvaaminen Nyt second_class-luokka luo olioita, jotka käyttäytyvät täsmälleen samalla lailla kuin first_class-oliot. Oliopohjaisessa koodissa lapsiluokat voivat korvata vanhempiensa metodit; tällöin lapsiluokkien oliot voivat toimia ainakin osin omalla tavallaan. Listaus 8.7 antaa second_class-luokalle oman sayhello()-metodin. Listaus 8.7 Lapsiluokan metodi korvaa kantaluokan metodin 1: <html> 2: <head> 3: <title>listing 8.7</title> 4: </head> 5: <body> 6: <?php 7: class first_class.black plate (145,1) 8: 9: var $name = "harry"; 10: function first_class( $n ) 11: 12: $this->name = $n; 13: 14: function sayhello() 15: 16: print "Hello my name is $this->name<br>"; 17:

138 8. Oliot 18: 19: 20: class second_class extends first_class 21: 22: function sayhello() 23: 24: print "I'm not going to tell you my name<br>"; 25: 26: 27: 28: $test = new second_class("son of harry"); 29: $test->sayhello(); 30: // tulostaa "I'm not going to tell you my name" 31:?> 32: </body> 33: </html> Nyt second_class-luokan omaa sayhello()-metodia kutsutaan kantaluokan metodin sijaan. Korvatun metodin kutsuminen Ohjelmassa voidaan joskus tarvita lapsiluokan metodin lisäksi myös kantaluokan metodia. Oliopohjaisessa ohjelmoinnissa on mahdollista syödä koko kakku. Listauksessa 8.8 second_class-luokan sayhello()-metodi kutsuu first_class-luokan vastaavaa metodia. Listaus 8.8 Korvatun metodin kutsuminen 1: <html> 2: <head> 3: <title>listing 8.8</title> 4: </head> 5: <body> 6: <?php 7: class first_class 8: 9: var $name = "harry";

8. Oliot 139 10: function first_class( $n ) 11: 12: $this->name = $n; 13: 14: function sayhello() 15: 16: print "Hello my name is $this->name<br>"; 17: 18: 19: 20: class second_class extends first_class 21: 22: function sayhello() 23: 24: print "I'm not going to tell you my name -- "; 25: first_class::sayhello(); 26: 27: 28: 29: $test = new second_class("son of harry"); 30: $test->sayhello(); 31: // tulostaa "I'm not going to tell you my name -- Hello my name is son of harry" 32:?> 33: </body> 34: </html> Syntaksin parentclassname::methodname() avulla voimme kutsua mitä tahansa korvattua metodia. Tämä syntaksi tuli PHP4:n mukana. Tuollainen koodi aiheuttaisi virheen PHP3:ssa.

140 8. Oliot Periyttäminen: Esimerkki Olet nyt nähnyt, kuinka luokka voi periä, korvata ja laajentaa toisen luokan toiminnallisuutta. Voimme nyt käyttää näitä mahdollisuuksia luomalla luokan, joka perii kaiken listauksen 8.5 Table-luokalta. Uuden luokan nimi on HTMLTable ja sen tarkoituksena on parantaa Table-luokan output()_metodia. HTMLTable-luokan ominaisuudet HTMLTable muotoilee tallentamansa tiedon käyttämällä standardia HTML-taulukkoa. Tässä esimerkissä sallimme luokan käyttäjän muuttaa TABLE-elementin CELLPADDING-määritettä sekä TD-elementin BGCOLOR-määrettä. Todellisuudessa taulukkoa voidaan muokata monella muullakin tavalla. class HTMLTable extends Table var $bgcolor; var $cellpadding = "2"; Olemme määritelleet uuden luokan, joka johdetaan Table-luokasta (extends-lauseella). Laitamme luokkaan kaksi ominaisuutta, jotka ovat bgcolor ja cellpadding (oletusarvo on 2). Muodostimen luominen Olet jo nähnyt, että äitiluokan muodostinta kutsutaan automaattisesti, jos lapsiluokalla ei ole omaa muodostinta. Nyt haluamme kuitenkin teettää muodostimellamme enemmän työtä kuin Table-luokan muodostin tekisi: function HTMLTable( $headers, $bg="#ffffff" ) Table::Table($headers); $this->bgcolor=$bg; HTMLTable-muodostin ottaa argumenteikseen sarakenimitaulukon ja merkkijonon. Merkkijonosta tulee bgcolor-ominaisuuden arvo ja annamme sille oletusarvon, jolloin siitä tulee valinnainen argumentti. Kutsumme Table-luokan muodostinta ja viemme sille $header-taulukon. Laiskuus on ominaista ohjelmoinnille, joten sallimme Table-luokan muodostimen tehdä omat toimintonsa. Alustamme HTMLTableluokan bgcolor-ominaisuuden.

8. Oliot 141 Jos lapsiluokalla on muodostin, ei äitiluokan muodostinta kutsuta automaattisesti, vaan sitä on kutsuttava ulkoisesti lapsiluokan muodostimesta käsin. Metodi setcellpadding() Lapsiluokka voi tietenkin luoda kokonaan omat metodinsa. Metodi setcellpadding() sallii käyttäjän muuttaa cellpadding-ominaisuutta sen oletusarvosta. Tietenkin olisi täysin mahdollista asettaa cellpaddingominaisuus suoraan ulkoapäin, mutta se ei ole hyvä tapa. Peukalosääntönä voisi sanoa, että on parasta luoda metodeja, jotka muuttavat ominaisuuksia käyttäjien toimesta. Monimutkaisemmissa versioissa setcellpadding() voisi muuttaa muita ominaisuuksia heijastamaan cellpadding-ominaisuuteen tehtäviä muutoksia. Valitettavasti yksityinen -suojausmäärettä ei voi käyttää PHP4:ssä. function setcellpadding( $padding ) $this->cellpadding = $padding; Output()-metodi Output()-metodi korvaa täysin Table-luokan samannimisen metodin. Se tulostaa tiedot samalla logiikalla kuin kantaluokkakin, mutta lisää tulostukseen HTML-taulukon muotoilun: function output() print "<table cellpadding=\"$this->cellpadding\" border=1>"; foreach ( $this->headers as $header ) print "<td bgcolor=\"$this->bgcolor\"><b>$header</b></td>"; foreach ( $this->table_array as $row=>$cells ) print "<tr>"; foreach ( $cells as $cell ) print "<td bgcolor=\"$this->bgcolor\">$cell</td>"; print "</tr>"; print "</table>";

142 8. Oliot Output()-metodimme pitäisi olla melko selkeä, jos ymmärsit Table-luokan version. Käymme läpi sekä headerettä table_array-taulukon tulostaen sisällöt selaimelle. Muotoilemme kuitenkin taulukon tiedon käyttämällä cellpadding- ja bgcolor-ominaisuuksia, joilla muutetaan asettelua ja väriä. Table- ja HTMLTable-luokat kokonaan Listaus 8.9 sisältää molemmat luokat. Siinä luodaan myös HTMLTable-olio, muutetaan sen cellpaddingominaisuutta, lisätään tietoa ja käytetään sen output()-metodia. Todellisessa käytännön esimerkissä saisimme tiedot todennäköisesti suoraan tietokannasta. Listaus 8.9 Table- ja HTMLTable-luokat 1: <html> 2: <head> 3: <title>testing objects</title> 4: </head> 5: <body> 6: <?php 7: class Table 8: 9: var $table_array = array(); 10: var $headers = array(); 11: var $cols; 12: function Table( $headers ) 13: 14: $this->headers = $headers; 15: $this->cols = count ( $headers ); 16: 17: 18: function addrow( $row ) 19: 20: if ( count ($row)!= $this->cols ) 21: return false; 22: array_push($this->table_array, $row); 23: return true; 24:

8. Oliot 143 25: 26: function addrowassocarray( $row_assoc ) 27: 28: if ( count ($row_assoc)!= $this->cols ) 29: return false; 30: $row = array(); 31: foreach ( $this->headers as $header ) 32: 33: if (! isset( $row_assoc[$header] )) 34: $row_assoc[$header] = " "; 35: $row[] = $row_assoc[$header]; 36: 37: array_push($this->table_array, $row); 38: 39: 40: function output() 41: 42: print "<pre>"; 43: foreach ( $this->headers as $header ) 44: print "<B>$header</B> "; 45: print "\n"; 46: foreach ( $this->table_array as $y ) 47: 48: foreach ( $y as $xcell ) 49: print "$xcell "; 50: print "\n"; 51: 52: print "</pre>"; 53: 54: 55: 56: class HTMLTable extends Table 57:

144 8. Oliot 58: var $bgcolor; 59: var $cellpadding = "2"; 60: function HTMLTable( $headers, $bg="#ffffff" ) 61: 62: Table::Table($headers); 63: $this->bgcolor=$bg; 64: 65: function setcellpadding( $padding ) 66: 67: $this->cellpadding = $padding; 68: 69: function output() 70: 71: print "<table cellpadding=\"$this->cellpadding\" border=1>"; 72: foreach ( $this->headers as $header ) 73: print "<td bgcolor=\"$this->bgcolor\"><b>$header</b></td>"; 74: foreach ( $this->table_array as $row=>$cells ) 75: 76: print "<tr>"; 77: foreach ( $cells as $cell ) 78: print "<td bgcolor=\"$this->bgcolor\">$cell</td>"; 79: print "</tr>"; 80: 81: print "</table>"; 82: 83: 84: $test = new HTMLTable( array("a","b","c"), "#00FF00"); 85: $test->setcellpadding( 7 ); 86: $test->addrow( array(1,2,3)); 87: $test->addrow( array(4,5,6)); 88: $test->addrowassocarray( array ( b=>0, a=>6, c=>3 )); 89: $test->output(); 90:?>

8. Oliot 145 91: </body> 92: </html> Listauksen 8.9 tulostus esitetään kuvassa 8.2. KUVA 8.2 HTMLTable-luokka toiminnassa. Miksi käyttää periyttämistä? Miksi pilkoimme taulukkoluokan kahteen luokkaan: Table- ja HTMLTable-luokkaan? Olemmeko varmasti säästäneet aikaa ja tilaa muodostamalla HTMLTablen suoraan Table-luokasta? Vastaus on se, että hyöty piilee itse asiassa joustavuudessa. Kuvittele, että asiakas on antanut sinulle tehtäväksi luoda luokan, joka osaa ylläpitää taulukon kenttiä, jotka on järjestelty nimettyihin sarakkeisiin. Jos olit muodostanut luokan, joka kerää ja tallentaa tiedot ja tulostanut HTML-muotoillun sisällön selaimelle, kaikki näyttäisi olevan hyvin. Jos sama asiakas palaisi ja pyytäisi sinua sopeuttamaan koodia tilapäisesti kirjoittamaan siististi muotoiltua tietoa tekstitiedostoon, voisit luultavasti lisätä joitakin metodeja ja ominaisuuksia sen toteuttamiseksi. Myöhemmin asiakas saattaa havaita, että hän tarvitsee mahdollisuuden lähettää tiedot sähköpostina ja jonkin ajan kuluttua yrityksen intranet alkaisi käyttää XML:n osajoukkoa. Olisiko kaikki tuo mahdollista ottaa mukaan? Tässä vaiheessa kaiken tuon toiminnallisuuden lisääminen yhteen ja samaan luokkaan saattaisi tuntua liian hajanaiselta ja saattaisit jo harkita koodin kirjoittamista uudelleen. Kokeilkaamme tätä skenaariota Table- ja HTMLTable-esimerkeillä. Olemme jo osin erottaneet tiedon muotoilun sen vastaanottamisesta ja valmistelusta. Kun asiakkaamme pyytää, että koodin tulisi kyetä tulostamaan tiedostoon, meidän on vain johdettava uusi luokka Table-luokasta. Kutsukaamme luokkaa FileTable-luokaksi. Meidän ei tarvitse tehdä mitään muutoksia aiempaan koodiimme. Sama koskee myös MailTable- ja XMLTable-luokkia. Kuva 8.3 havainnollistaa noiden luokkien välisiä suhteita. Kuva 8.3 Table-luokan ja sen lapsiluokkien suhteet kaaviona.

146 8. Oliot Lisäksi tiedämme, että jokainen olio, joka saa ominaisuutensa Table-luokalta, omistaa joukon output()- metodeja, jotka ovat aina kytkettävissä taulukoihin. Voimme aina halutessamme kutsua output()-metodeja huolehtimatta menettelytavoista. Table-luokasta johdetut luokat osaavat kirjoittaa sähköposteja, HTMl:ää, XML:ää tai puhdasta tekstiä kutsumalla toistuvasti output()-metodia! Yhteenveto Yhden lyhyen luvun myötä ei ole mahdollista tuoda esille kaikkia oliopohjaiseen ohjelmointiin liittyviä näkökohtia. Toivon, että luku antoi kuitenkin riittävän kattavan kuvan mahdollisuuksista. Voit päättää itse, kuinka laajasti alat käyttää olioita ja luokkia ohjelmissasi. On todennäköistä, että voimakkaasti oliopohjaiset projektit vaativat hieman enemmän resursseja ajon aikana kuin perinteinen koodi. Kuitenkin oliopohjaisten tekniikoiden tehokas hyödyntäminen voi parantaa koodin joustavuutta ja organisointia. Tämä luku esitteli sinulle luokkien kehittämistä ja olioiden luomista. Opit lisäämään luokkiin ominaisuuksia ja metodeja. Luvun lopussa sait tietoa uusien luokkien luomisesta. Nämä luokat perivät ja korvaavat muiden luokkien piirteitä. K&V K Tämä tunti esitteli joitakin vähemmän tuttuja käsitteitä. Tuleeko minun todellakin ymmärtää oliopohjaista ohjelmointia tullakseni hyväksi PHP-ohjelmoijaksi? V Lyhyt vastaukseni on ei. Useimmat PHP-skriptit käyttävät vain vähän tai ei lainkaan oliopohjaista koodia. Oliopohjainen lähestymistapa ei auta tekemään asioita, joita et muuten osaisi. Oliopohjaisen ohjelmoinnin edut ovat skriptien organisoinnissa, uudelleenkäytettävyydessa ja laajennettavuudessa. Vaikka päättäisitkin luopua oliopohjaisesta ohjelmointitavasta, saatat törmätä siihen lukiessasi muiden tekemiä koodeja. Tämän tunnin tarkoituksena oli tukea sinua tuollaisen koodin ymmärtämisessä. K Mitä erikoismuuttuja $this oikein pitää sisällään? V Luokan sisältä käsin on joskus voitava kutsua luokan metodeja tai käsitellä sen ominaisuuksia. Yhdistämällä $this-muuttuja ja nuolioperaattori (->), voidaan tehdä molemmat. $this-muuttuja on viittaus ajankohtaiseen luokkaan. Työpaja Työpaja tarjoaa pikakysymyksiä, joiden avulla voit kerrata läpikäytyä materiaalia. Yritä ymmärtää vastaukset ennen kuin jatkat seuraavaan lukuun. Vastaukset annetaan liitteessä A.

8. Oliot 147 Kysymyksiä 1. Kuinka esittelisit luokan nimeltä emptyclass(), jolla ei ole metodeja tai ominaisuuksia? 2. Jos käytössäsi on emptyclass()-luokka, kuinka loisit tuon luokan olioita? 3. Kuinka voisit esitellä ominaisuuden luokan sisällä? 4. Kuinka valitsisit muodostimen nimen? 5. Kuinka loisit muodostimen? 6. Kuinka loisit tavallisen metodin luokkaan? 7. Kuinka käsittelisit luokan ominaisuuksia ja metodeja luokan sisältä käsin? 8. Kuinka käsittelisit luokan ominaisuuksia ja metodeja luokan ulkopuolelta? 9. Mitä lisäisit luokan määrittelyyn, jos haluaisit laittaa sen perimään toiminnallisuuden toiselta luokalta? Toiminta 1. Luo luokka nimeltä basecalc(), joka tallentaa kaksi numeroa ominaisuuksina. Toteuta calculate()-metodi, joka tulostaa numerot selaimelle. 2. Luo luokka nimeltä addcalc(), joka perii toiminnallisuutensa basecalc()-luokalta. Korvaa calculate()- metodi niin, että ominaisuuksien summa tulostetaan selaimelle. 3. Toista toiminta numero 2 luokalle nimeltä minuscalc(). Toteuta luokalle calculate()-metodi, joka vähentää ensimmäisen ominaisuuden toisesta tulostaen sitten erotuksen selaimelle.

148 8. Oliot