Jonkin verran on tuohon olio-ohjelmointiin tullut tutustuttua ja nyt on jäänyt mietityttämään eräs seikka. Olen katsellut miten muualla on käytetty eri luokkia toisten luokkien sisällä. Vastaan on tullut oikeastaan kolmea erilaista tapaa: extends, alla kuvailtu viittaus ja luokan sisällyttäminen toisen luokan metodin sisään.
Kaikenlaisia oppaita olen lukenut, mutta silti on vielä hämärän peitossa mitä todella tapahtuu seuraavassa viittauksessa:
class LuokanNimi { function &metodinNimi() {} } class Luokka { function metodi() { $metodi =& LuokanNimi::metodinNimi(); } }
Lähinnä kysymykset siis ovat, että mitä tuossa viittauksessa todella tapahtuu ja mitä sillä saavutetaan sekä miten nämä kolme erilaista tapaa käyttää luokkaa toisen luokan sisältä eroavat toisistaan. Mitä olennaista eroa (hyötyä ja haittaa) kullakin tavalla on toisiin nähden?
Pari sivukysymystä vielä.. Mitä olennaista hyötyä abstrakteista luokista on? Miksei kyseisten abstraktien luokkien metodeja ja attribuutteja vain voisi laittaa yhden ja saman luokan sisälle, joka sitten peritään toiseen luokkaan?
Onko joku perehtynyt tarkemmin Joomla!:n sielunelämään? Olen tutkinut sitä jo jonkin aikaa ja ihmetellyt, että miksei siinä määritellä metodien ja attribuuttien näkyvyysasteita mitenkään. Johtuukohan se siitä, että Joomla! pyrkii edelleen tukemaan php4:ää, jossa näkyvyysasteita ei ollut? Miten Joomla! (tai ylipäätään php4:ää käyttävä sivu) sitten suojaa yksityiset metodit ja attribuutit?
Tuo esimerkkisi on aivan tavallinen funktiokutsu. Jos &
-merkit hämmentävät, lue tämä sivu manuaalista. Ne eivät liity luokkiin.
Konkreettisesti tuossa koodissa ei tapahdu yhtikäs mitään.
AkeMake kirjoitti:
Olen katsellut miten muualla on käytetty eri luokkia toisten luokkien sisällä. Vastaan on tullut oikeastaan kolmea erilaista tapaa: extends, alla kuvailtu viittaus ja luokan sisällyttäminen toisen luokan metodin sisään.
Tuntuu että ajattelet jotenkin turhan hankalasti. Perintä (extends) ja metodien kutsuminen luokan ulkopuolelta ovat ihan eri asiat, ei niitä kannata rinnastaa ja vertailla keskenään. Perintä on aika keskeinen osa olio-ohjelmointia ja siitä on netti täynnä parempaa materiaalia kuin mitä minä osaisin tähän kirjoittaa, mutta ehkä joku muu innostuu selittämään.
En ymmärrä mitä tarkoitat kolmannella käyttötavalla.
AkeMake kirjoitti:
Mitä olennaista hyötyä abstrakteista luokista on?
Abstrakti luokka on ikäänkuin luokan ja interfacen välimuoto. Kuten interface, se voi esitellä metodeita jotka täytyy toteuttaa perivissä luokissa. Abstrakti luokka voi myös itse toteuttaa metodeita - yleensä sellaisia, jotka jokainen perivä luokka toteuttaisi kuitenkin samalla tavalla. Eli abstrakti luokka on "osittain toteutettu interface".
Joissain kielissä interfacet voivat sisältää myös toteutuksia, joten abstraktin luokan käsitettä ei niissä tarvita.
AkeMake kirjoitti:
Miksei kyseisten abstraktien luokkien metodeja ja attribuutteja vain voisi laittaa yhden ja saman luokan sisälle, joka sitten peritään toiseen luokkaan?
En ymmärrä kysymystä. :/
Jos OO-tutoriaalit eivät oikein avaudu kaikilta osin, kannattaa lukemisen lisäksi kirjoittaa paljon koodia ja miettiä itse miten kielen erilaisia rakenteita olisi järkevä käyttää. Kun välillä palaa taas oppaiden pariin tai lukee muiden koodia, tehtyjä ratkaisuja ymmärtää varmasti paljon paremmin, koska on itse joutunut ratkaisemaan samantapaisia ongelmia omissa projekteissa.
"Alla kuvailtu viittaus" viittaa ilmeisestikin luokan staattisiin jäseniin, jotka ovat siis yhteisiä kaikille luokan toteutuksille (vrt. "normaalit" jäsenet, jotka ovat erillisiä kaikille luokasta luoduille olioille). Staattisia ominaisuuksia käytettäessä luokasta ei siis tarvitse luoda oliota, minkä johdosta staattisia ominaisuuksia nähdäänkin geneerisissä aputehtävissä, mm. usean kielen Math-luokan metodit. Luokan määrittely metodin sisällä on vain erikoistilanne, jossa luokan näkyvyysalue on ko. metodiblokki. Yleensä luokka määritellään joko globaalin (ennen PHP 5.3) tai vapaavalinnaisen nimiavaruuden blokissa.
Hetki on kun Joomlan lähdekoodia viimeksi katselin, mutta voisin kuvitella, että työresurssit on mieluummin käytetty softan ns. näkyviin parannuksiin koodin uudelleenkirjoituksen sijaan. Tällöin Joomlasta löytyy hyvin luultavasti vielä PHP4-jäänteitä, ja silloinhan se ei "suojaa", nelosen oliomalli oli rakennettu nallekarkeista ja marsipaanista. En äkkiseltään keksi syytä lähteä emuloimaan nelosversiolla vitosversion ominaisuuksia sen sijaan, että vedettäisiin koko roska uusiksi vitosen malliin.
jlaire kirjoitti:
Tuntuu että ajattelet jotenkin turhan hankalasti. Perintä (extends) ja metodien kutsuminen luokan ulkopuolelta ovat ihan eri asiat, ei niitä kannata rinnastaa ja vertailla keskenään.
Miksei? Eikö ne ole melkein samanlaisia juttuja. Perinnässä metodi haetaan vain parent::metodinNimi() ja muuten LuokanNimi->metodinNimi(). Niin onko se ero tosiaan siinä, että jälkimmäisessä pitäisi tehdä jokin olio tästä LuokanNimi luokasta ennen kuin sitä voi käyttää? Entä sitten jos metodi olisikin staattinen, jolloin sitä voisi hakea tekemättä ylimääräistä oliota. Eivätkö nämä kaksi tapaa ole silloin melkein samanlaiset?
Kolmannella tavalla tarkoitin sitä, että tiedosto, jossa luokka sijaitsee includetaan toisen luokan metodin sisään. Silloin tietysti luokka olisi käytössä vain sille yksittäiselle metodille. Mitä hyötyä tästä olisi verrattuna siihen, että luokka vain perisi sen toisen luokan? Rajapinnoistakin olen jotain oppaita lukenut, mutten ole oikein tajunnut mikä niiden hyöty on. Mureakuhan oppaassa oleva rajapintaesimerkki ei aukaissut minulle ollenkaan mitä hyötyä niistä on. Eiväthän rajapinnat tee mitään vaan kertovat ainoastaan käyttäjälle mitä metodeita rajapintaa käyttävän luokan täytyy vähintään määritellä.
jlaire kirjoitti:
En ymmärrä kysymystä. :/
Olinkin ymmärtänyt abstraktien luokkien toiminnan ihan väärin. Tuon voi siis unohtaa. Abstrakti luokkahan on siis lähes sama asia kuin rajapinta? En tajua mitä hyötyä on esitellä luokassa metodit joita toisen luokan on pakko käyttää. Enkä kyllä myöskään tajua mikä abstraktin luokan ja rajapintojen todellinen ero on. Olisiko teillä antaa jotain konkreettista esimerkkiä, jossa abstraktien luokkien ja rajapintojen käytöstä olisi hyötyä?
Jos avaan, suljen ja käsittelen tietokantayhteyttä luokan sisällä, kannattaako se tietokantayhteyden avaava metodi määritellä staattiseksi, jolloin yhteys olisi yleisesti käytössä eikä jokaisen olion tarvitsisi avata yhteyttä aina jokaisella käyttökerralla uudestaan? Samoin käyttäjän tiedot staattiseen taulukkoattribuuttiin, jolloin tietoja voisi käyttää kaikkialta? Vai onko näihin jotain parempaa toteutustapaa?
Lue tuo: http://www.cs.helsinki.fi/u/wikla/ohjelmointi/
AkeMake kirjoitti:
Olisiko teillä antaa jotain konkreettista esimerkkiä, jossa rajapintojen käytöstä olisi hyötyä?
Itse olen itselleni kertonut että tuossa on järkeä.
<?php class view { public $autoCleanTags = true; private $template = ""; public function setTemplate($template) { if(file_exists($template)) { ob_start(); include($template); $this->template = ob_get_clean(); } else { throw new Exception ("Template polku on vaara."); } } public function content($replacmentTag, $content) { if(isset($replacmentTag, $content)) { $this->template = str_replace($replacmentTag, $content, $this->template); } } public function view($replacmentTag, $pathToView, $args = array()) { if(file_exists($pathToView) AND isset($replacmentTag)) { ob_start(); include($pathToView); $this->content($replacmentTag, ob_get_clean()); } else { throw new Exception ("View - polku virheellinen."); } } public function html() { if(empty($this->template)) { throw new Exception ("Aseta (setTemplate) template polku - ohjurissa."); } else { if($this->autoCleanTags == true) { $this->template = preg_replace("/{(.*)}/", "", $this->template); } return $this->template; } } } ?>
Käyttökohde esim:
<?php class login extends view { public function __construct() { try { /** Valitaan sivupohja ja asetetaan title **/ parent::setTemplate(VIEW . "/templates/login/template.html"); parent::content("{TITLE}", "Kirjaudu palveluun"); $viesti = "Kirjaudu palveluun"; /** Kirjautuminen **/ if(isset($_POST["kirjaudu"])) { try { $kirjautuminen = new userlogin(); $kirjautuminen->kirjaudu(); } catch (Exception $e) { $viesti = $e->getMessage(); } } /** Uloskirjautuminen **/ if(isset($_GET["action"]) AND $_GET["action"] == "kirjaudu-ulos") { try { $kirjautuminen = new userlogin(); $kirjautuminen->kirjauduUlos(); } catch (Exception $e) { $viesti = $e->getMessage(); } } /** Login formi **/ parent::view("{CONTENT}", VIEW . "/view/login/login.html", array( "viesti" => $viesti )); } catch (Exception $e) { print $e->getMessage(); } } public function __toString() { try { return parent::html(); } catch (Exception $e) { print $e->getMessage(); } } } ?>
tai..
<?php class defaultc extends view { public function __construct() { try { parent::setTemplate(VIEW . "/templates/default/template.html"); parent::content("{TITLE}", "**** talohoito - Työnhallinta"); /** Kayttajan henkilokohtaiset avoimet tyot/ilmoitukset **/ $ilmoitukset = new ilmoitukset(); $kayttajanIlmoitukset = $ilmoitukset->ilmoitukset($_SESSION["userdata"]["id"], "1"); /** haetaan kaikki avoimet huoltotyot **/ $ilmoitukset = new ilmoitukset(); $kaikkiIlmoitukset = $ilmoitukset->ilmoitukset("%", "1"); parent::view("{TOPMENU}", VIEW . "/blocks/topmenu.html"); parent::view("{CONTENT}", VIEW . "/view/default/default.html", /** Palautetavat tiedot **/ array( "ilmoitukset" => $kayttajanIlmoitukset, "kaikkiilmoitukset" => $kaikkiIlmoitukset )); parent::view("{DIALOG_UUSIILM}", VIEW . "/view/dialogs/uusiIlmoitusForm.html"); parent::view("{DIALOG_TYONTIEDOT}", VIEW . "/view/dialogs/tyonTiedot.html"); } catch (Exception $e) { print $e->getMessage(); } } public function __toString() { try { return parent::html(); } catch (Exception $e) { print $e->getMessage(); } } } ?>
Parent voisi toki olla $this->.
Edit: Luin koko ketjun läpi ja tulin siihen tulokseen että esimerkkini ei vastannut oikeastaan mihinkään esitettyyn kysymykseen paitsi ehkä hipoen extends kysymystä joka oli koko ketjun aihe: "olio-ohjelmointi ja extends"..
Tosin se noudattaa kyllä interfacen periaatetta, eli view luokka määrittää mitä metoodeja sen lapsen täytyy hyödyntää.
Tuossa lisää lukemista..
https://www.php.net/manual/en/language.oop5.interfaces.php
qeijo kirjoitti:
Tosin se noudattaa kyllä interfacen periaatetta, eli view luokka määrittää mitä metoodeja sen lapsen täytyy hyödyntää.
Eikä noudata. Rajapinta määrittelee mitä metodeja toteuttavan luokan tulee toteuttaa, mutta ei itse tarjoa toteutusta niille. Jos tuntuu siltä että intefacessa olisi tarpeellista tai edes mahdollista toteuttaa joitain metodeja, silloin rajapinta ei ole oikea ratkaisu ongelmaan vaan tulisi käyttää abstraktia tai tavallista luokkaa.
Rajapinnat ja ja abstraktit luokat ovat hyödyllisiä usein silloin kun halutaan tarjota mahdollisuus toteuttaa jokin toiminnallisuus useammalla eri tavalla. Otetaan vaikkapa esimerkiksi tuo qeion view-luokka, jonka tarkoituksena on ilmeisesti ottaa vastaan template-tiedostoja ja tehdä niille erilaisia muokkauksia ja korvauksia. Jos haluaisimme muokata ohjelmaa niin että templatet voisivat sijaita joko levyllä tiedostoina tai tietokannassa, voisimme hyödyntää rajapintoja seuraavasti:
<?php abstract class view { /** * Abstract representation of a view */ public $autoCleanTags = true; private $template = ""; private $templateStorage; public function __construct(TemplateStorage $storage) { $this->templateStorage = $storage; } /** * Extending classes should implement this method */ abstract public function initialize(); protected function setTemplate($templateName) { if(($this->template = $this->templateStorage->getTemplate($templateName)) === null) { throw new Exception ("Templaten nimi on vaara."); } } protected function view($replacmentTag, $viewName, $args = array()) { if(isset($replacmentTag) AND ($view = $this->templateStorage->getView($viewName)) !== null) { $this->content($replacmentTag, $view); } else { throw new Exception ("View - nimi virheellinen."); } } protected function content($replacmentTag, $content) { if(isset($replacmentTag, $content)) { $this->template = str_replace($replacmentTag, $content, $this->template); } } protected function html() { if(empty($this->template)) { throw new Exception ("Aseta (setTemplate) template polku - ohjurissa."); } else { if($this->autoCleanTags == true) { $this->template = preg_replace("/{(.*)}/", "", $this->template); } return $this->template; } } public function __toString() { try { return $this->html(); } catch (Exception $e) { return $e->getMessage(); } } } class loginView extends view { public function initialize() { $this->setTemplate('loginTemplate.html'); $this->content("{TITLE}", "Kirjaudu palveluun"); $this->view("{CONTENT}", 'loginView.html'); } } class defaultc extends view { public function initialize() { $this->setTemplate(VIEW . "template_default_template.html"); $this->content("{TITLE}", "**** talohoito - Työnhallinta"); $this->view("{TOPMENU}", "blocks_topmenu.html"); $this->view("{CONTENT}", "default_default.html", $this->view("{DIALOG_UUSIILM}", "dialogs_uusiIlmoitusForm.html"); $this->view("{DIALOG_TYONTIEDOT}", "dialogs_tyonTiedot.html"); } } interface TemplateStorage { /** * @return string template or null if template cannot be found for the given name */ public function getTemplate($name); /** * @return string view or null if view cannot be found for the given name */ public function getView($name); } class FilesystemUtils { /** * A class that provides common filesystem utils * * This is here mainly to demonstrate inheritance in this example */ public function getFileContent($path) { if(is_readable($path)) { $content = file_get_contents($path); return $content !== false ? $content : null; } else { return null; } } } class FilesystemTemplateStorage implements TemplateStorage extends FilesystemUtils { /** * A class to retrieve templates stored in filesystem */ private $baseDir; public function __construct($baseDir) { $this->baseDir = $baseDir; } public function getTemplate($name) { return $this->getFileContent($this->baseDir.DIRECTORY_SEPARATOR.'template'.DIRECTORY_SEPARATOR.$name); } public function getView($name) { return $this->getFileContent($this->baseDir.DIRECTORY_SEPARATOR.'view'.DIRECTORY_SEPARATOR.$name); } } class DatabaseTemplateStorage implements TemplateStorage { /** * A class to retrieve templates stored in database */ private $connection; public function __construct(PDO $connection) { $this->connection = $connection; } public function getTemplate($name) { $statement = $this->connection->prepare('SELECT content FROM template WHERE name = ?'); return $this->querySingleValue($statement, array($name)); } public function getView($name) { $statement = $this->connection->prepare('SELECT content FROM view WHERE name = ?'); return $this->querySingleValue($statement, array($name)); } private function querySingleValue(PDOStatement $statement, array $parameters = array()) { if($statement->execute($parameters) === false) { return null; } $value = $statement->fetchColumn(); return $value !== false ? $value : null; } } class Controller { /* Example usage of views with different storages */ public function showLogin() { $storage = new FilesystemTemplateStorage('/tmp/application/templates'); $view = new loginView($storage); $view->initialize(); echo $view; } public function showDefaultc() { // Implementing DBManager is out of the scope of this example, // but getConnection should return a PDO-object $storage = new DatabaseTemplateStorage(DBManager::getConnection()); $view = new defaultc($storage); $view->initialize(); echo $view; } }
Koodista tuli näköjään kohtuullisen laaja ja lisäsin siihen myös esimerkin abstraktin luokan käytöstä view-luokan yhteydessä. Ideana tuossa on että view-luokka tarjoaa eri näkymille työkalut niiden käsittelyyn, mutta jokainen näkymä alustetaan eri tavalla ja siksi niiden tulee toteuttaa itse initialize()-metodi. Rajapinnan käytön hyötynä tässä taas on että view-luokan ei tarvitse tietää missä templatet sijaitsee (levyllä vai kannassa). Riittää kun se tietää että $storage toteuttaa tietyn rajapinnan minkä kautta templatet on saatavilla. Näin samaa view-koodia voi hyödyntää minkä tahansa TemplateStorage-rajapinnan toteuttavan luokan kanssa ilman muutoksia view-luokan koodiin.
Tukki kirjoitti:
qeijo kirjoitti:
Tosin se noudattaa kyllä interfacen periaatetta, eli view luokka määrittää mitä metoodeja sen lapsen täytyy hyödyntää.
Eikä noudata. Rajapinta määrittelee mitä metodeja toteuttavan luokan tulee toteuttaa, mutta ei itse tarjoa toteutusta niille.
juuri näin.
qeijo kirjoitti:
Tosin se noudattaa kyllä interfacen periaatetta
Tukki kirjoitti:
Eikä noudata. Rajapinta -- ei itse tarjoa toteutusta niille [metodeille]
Korostettu ero on merkitsevä rajapinnan ja abstraktin luokan erottava tekijä. View-luokkasi on lähempänä abstraktia luokkaa toteuttaessaan kaiken paitsi konkstruktoinnin itse (luokalta kyllä löytyy oletuskonstruktori, eli mikään ei estä ohjelmoijaa luomasta luokasta esiintymää, oli se sitten tarkoitus tai ei). View-luokkasi näyttäisi toteuttavan myös controllerin toimintoja.
tsuriga kirjoitti:
View-luokkasi näyttäisi toteuttavan myös controllerin toimintoja.
Login ja defaultc toimii tuossa kyllä ohjurin roolissa, view on mielestäni "vain" template luokka jonka tarkoitus on kasata template ja liittää siihen ohjureitten luoman sisällön.
Juotatte vaan viinaa sille View:lle, jos se ei meinaa pysyä tyhmänä. (Viitaten RoR PSA #3:een)
qeijo kirjoitti:
Login ja defaultc toimii tuossa kyllä ohjurin roolissa
Pahoittelut, juurikin näihin oli tarkoitus viitata. Nuo login
- ja defaultc
-kontrolleri kun perivät esimerkissäsi view-luokan, ts. nähtävissä hienoista oikomista MVC-mallin suhteen.
Kiitos selvennyksistä. Tuli minulle niin vaikeaa asiaa, että pitää lähteä pureskelemaan noita ajan kanssa.
Vielä tuli sellainen kysymys mieleen, että mikä idea on viitata funktioon tai metodiin? Mitä sillä siis saavutetaan? Yritin googletella vastausta (suomeksi), mutta ainoat viittauksista puhuvat oppaat liittyivät vain muuttujaan viittamiseen. Englanniksi googlettamiseen taas kielipää ei riittänyt.
<?php class Luokka { private function &metodi($arvo) { static $taulu; if(!isset($taulu)) { $taulu = array(); } $taulu[] = $arvo; return $taulu; } public function toinenMetodi($arvo) { $taulu = $this->metodi($arvo); return $ṱaulu[count($taulu)-1]; } } $olio = new Luokka(); print $olio->toinenMetodi('tekstiä');
Huomasitko merkin ṱ
koodissasi? Ei taida toimia ihan toivotusti.
&-merkki funktion yhteydessä tarkoittaa, että ei palauteta arvoa vaan viittaus muuttujaan. Silloin tuloksen voi myös sijoittaa viittauksena ja sen kautta voi muokata alkuperäistä arvoa. Näin funktio voi palauttaa esimerkiksi muokattavan viittauksen johonkin staattiseen muuttujaan tai luokan jäseneen.
function &f() { static $x = 0; echo "f: x = $x\n"; return $x; } $viittaus =& f(); // Viittauksen vuoksi funktion staattinen $x muuttuu. $viittaus = 123; f();
Käytännössä viittaukset ovat PHP:ssä harvoin tarpeen – kuten tuossakin koodissasi. Useimmat asiat voi aivan helposti tehdä muullakin tavalla. Erityisesti "optimointiin" viittaukset ovat väärä ratkaisu, nimittäin PHP-tulkki osaa jo valmiiksi optimoida muuttujien kopioinnit niin, että oikeasti dataa ei kopioida, ennen kuin se muuttuu (copy-on-write).
Mitenkähän tuollainen merkki tuonne on päässyt.. :o Testailin tuota hiukan ja toimi moitteettomasti, mutta tämän jälkeen tein pieniä muutoksia ja tuo merkki on tullut siinä yhteydessä. No, muutenkin tuo nyt vain oli tuollainen tarpeeton pikku esimerkki, jota en oikeasti käytä mihinkään.
Taisin osaksi ymmärtää tuon funktioon viittauksen. tai sitten en.. En vain vieläkään ymmärrä mitä pelkällä funktioon viittaamisella saavutetaan. Etuhan tulee vasta siinä, kun tuloksen sijoittaa viittauksena?
Löysin tuolta Joomla!:sta tiedoston, jossa minun nähdäkseni käytetään ainoastaan funktioon viittausta (register-metodi) eikä tulosta sijoiteta viittauksena. Mitä tällä saavutetaan?
Kai se on parempi, että näiden vastausten jälkeen lähden vain koodailemaan olioita kanssa, niin eiköhän asiat lähde siitä ajan kanssa selkiytymään. :)
AkeMake kirjoitti:
En vain vieläkään ymmärrä mitä pelkällä funktioon viittaamisella saavutetaan.
Mitään "funktioon viittaamista" ei ole olemassakaan. &-merkki funktion määrittelyssä on sitä varten, että tuloksena ylipäänsä on viittaus eikä vain kopio arvosta. Voit todeta tämän käytännöllisesti niin, että otat edellisestä mallikoodistani kyseisen merkin pois: ei toimi.
AkeMake kirjoitti:
Etuhan tulee vasta siinä, kun tuloksen sijoittaa viittauksena?
"Etu" saavutetaan vasta, kun keksit koko hommalle jotain järkevää käyttöä. PHP:n viittauksia pidetään jopa niin turhina, että ne ollaan tietoisesti jättämässä pois vaihtoehtoisesta PHP-toteutuksesta.
AkeMake kirjoitti:
Löysin tuolta tiedoston, jossa minun nähdäkseni käytetään ainoastaan funktioon viittausta (register-metodi) eikä tulosta sijoiteta viittauksena. Mitä tällä saavutetaan?
Jos tulosta ei sijoiteta viittauksena, funktio toimii käytännössä aivan samoin kuin ilman &-merkkiä.
Mielestäni selitin jo edellisessä viestissäni aika perusteellisesti, että viittauksilla sinänsä ei saavuteta yhtään mitään. Mainitsin aivan erityisesti, että temppu ei sovi optimointiin; tästä voit rivien välistä päätellä, että aika moni kuvittelee tuolla tavalla nopeuttavansa koodia jotenkin. Voi olla, että joku Joomla!-kehittäjäkin on kuvitellut niin, tai ehkä viittaukselle on joskus aiemmin ollut tuossa käyttöä tai on käyttöä toisessa tiedostossa. Koodi näyttää syntaksinsa puolesta olevan PHP 4:n ajoilta, joten siinä voi olla myös historiallisia jäänteitä (viittausoptimointi ajalta ennen PHP:n COW-toteutusta) tai se voi muuten vain olla vanhaa ja huonoa.
(Sori että menee offtopiciksi, mutta oli pakko kommentoida kun alla oleva näkyi tuolla "viimeisin viesti" laatikossa)
Metabolix kirjoitti:
Mitään "funktioon viittaamista" ei ole olemassakaan.
Mitäs se sitten on silloin kun annetaan callback-funktio esim usortille?
Grez kirjoitti:
(Sori että menee offtopiciksi, mutta oli pakko kommentoida kun alla oleva näkyi tuolla "viimeisin viesti" laatikossa)
Metabolix kirjoitti:
Mitään "funktioon viittaamista" ei ole olemassakaan.
Mitäs se sitten on silloin kun annetaan callback-funktio esim usortille?
Kutsu. <3
No ei sitä kyllä siinä yhteydessä kutsuta. Kutsu on siellä usort-funktion sisällä.
Grez kirjoitti:
Mitäs se sitten on silloin kun annetaan callback-funktio esim usortille?
PHP:ssähän käytetään perinteisesti vain funktion nimeä tai taulukkoa, jossa on ensin olio tai luokan nimi ja perässä funktion nimi. Ei sitä voi tässä yhteydessä väittää funktioon viittaamiseksi, kun kerran muuttujienkin kohdalla puhutaan nyt oikeista viittauksista (&-merkistä) eikä nimen avulla viittaamisesta (${$nimi}-merkinnästä).
Siitä voidaan ehkä neuvotella, mitä Closure-luokka tarkalleen tekee, mutta muuta funktioviittaukseksi kelpaavaa tilannetta ei PHP:ssä nähdäkseni ole.
Ettei jäisi epäselvyyttä tästä funktion nimen string-muotoisuudesta, laitetaan vielä malliksi tämä hämäävä versio, jossa puuttuvat lainausmerkit aiheuttavat varoituksen:
call_user_func(htmlspecialchars, "moi"); // PHP:n tulkinta: call_user_func('htmlspecialchars', "moi");
PHP kirjoitti:
PHP Notice: Use of undefined constant htmlspecialchars - assumed 'htmlspecialchars' in php shell code on line 1
Metabolix kirjoitti:
funktion nimi. Ei sitä voi tässä yhteydessä väittää funktioon viittaamiseksi, kun kerran muuttujienkin kohdalla puhutaan nyt oikeista viittauksista (&-merkistä) eikä nimen avulla viittaamisesta (${$nimi}-merkinnästä).
Siis jos välität funtiolle sellaisen muuttujan nimen, johon funktiolla on näkyvyys, niin kyllähän se nimenomaan on muuttujaan viittaamista enemmän kuin arvon antamista. Jos annat funktiolle muuttujan nimen, niin sehän pystyy myös muuttamaan ko. arvoa ihan niinkuin perinteisessäkin viittauksessa.
Mielestäni nimi nimenomaan on tapa viitata johonkin.
Myönnän toki, että viittamistapa poikkeaa useissa muissa kielissä käytössä olevasta tavasta, eli sitä toisten kielten tapaa viitata funktioihin ei PHP:ssä tosiaan ole, eikä & liity funktioihin viittaamiseen.
Grez kirjoitti:
Jos annat funktiolle muuttujan nimen, niin sehän pystyy myös muuttamaan arvoa ihan niinkuin perinteisessäkin viittauksessa.
Millaisella nimellä pystyt mielestäsi viittaamaan funktion sisällä olevaan staattiseen muuttujaan? Entä taulukon tiettyyn alkioon tai muuttujaan $a->b->c? Eli ei, nimillä ei todellakaan saavuteta samanlaista viittausmahdollisuutta kuin oikeilla viittauksilla. Pelkillä nimillä pääsee käsiksi ainoastaan globaaleihin ja nykyisen funktion muuttujiin. Muuttujan nimen voisi minusta käsittää ennemminkin $GLOBALS-taulukon (tai kuvitteellisen $LOCALS-taulukon) indeksiksi ja $$x-merkintä vain oikotieksi $GLOBALS[$x]-merkinnälle.
Funktioihin pätee oikeastaan sama, vaikka toki funktiot ovatkin lähtökohtaisesti globaaleja ja yksiselitteisesti nimettyjä. PHP 5.3:n uudet, Closure-luokkaan tukeutuvat funktiot ovat kuitenkin nimettömiä, eikä niihin voi siksi tuolla tavalla "viitata".
Menipä taas atomien halkomiseksi.
Aihe on jo aika vanha, joten et voi enää vastata siihen.