Kirjautuminen

Haku

Tehtävät

Koodit: PHP: Oletusarvollinen taulukko

Kirjoittaja: map_

Kirjoitettu: 30.12.2009 – 30.12.2009

Tagit: koodi näytille, vinkki

PHP:ssa halutaan usein pitää E_NOTICE-virheilmoituksia päällä.

Eräs toisinaan ärsyttävä E_NOTICE-tason virhe on taulukon indeksoiminen olemattomalla avaimella. Esim. $_GET['sana'] aiheuttaa E_NOTICE-tason virheen, mikäli 'sana'-parametri jostain syystä puuttuu.

Suoraviivaisin tapa päästä näistä virheistä eroon on tehdä isset-tarkistuksia, kuten $sana = isset($_GET['sana']) ? $_GET['sana'] : '';, mutta tämä käy pidemmän päälle tylsäksi.

Listauksessa määritellään luokka DefaultingArrayObject, jonka ilmentymät toimivat kuin taulukot, mutta niitä voi aina indeksoida millä tahansa avaimella. Toteutus on suoraviivainen, sillä PHP:ssa on jo valmiina taulukon lailla käyttäytyvä luokka, ArrayObject, joka voidaan periä.

Lisäys: Eräs toinen ratkaisu esitettyyn ongelmaan on @-operaattori. Myöskään @$_GET['sana'] ei aiheuta virheilmoitusta, mutta ratkaisu ei ole ihan ongelmaton. Ks. tämän vinkin kommentit.

<?php
// DefaultingArrayObject.php

class DefaultingArrayObject extends ArrayObject
{
    protected $_default;

    public function __construct($array = array(), $default = null)
    {
        parent::__construct($array);
        $this->_default = $default;
    }

    public function setDefault($default)
    {
        $this->_default = $default;
    }

    public function offsetGet($index)
    {
        return $this->getWithDefault($index, $this->_default);
    }

    public function getWithDefault($index, $customDefault)
    {
        if (parent::offsetExists($index)) {
            return parent::offsetGet($index);
        } else {
            return $customDefault;
        }
    }
}
<?php
// Esimerkki
error_reporting(E_ALL | E_NOTICE);

require_once('DefaultingArrayObject.php');

$input = new DefaultingArrayObject($_GET);

if ($input['sana'] == 'Firefly') {  // Ei E_NOTICEa vaikka 'sana' puuttuu
  echo "Hyvä!";
}

Kommentit

Zeeli [31.12.2009 18:43:03]

#

Näppärä

janijohannes [11.02.2010 06:07:43]

#

Hmm...
Onhan tuo näppärä, mutta $_REQUEST-taulukko ajaa saman asian.

map_ [11.02.2010 10:36:31]

#

$_REQUEST kyllä yhdistää $_GETin, $_POSTin ja $_COOKIESin, mutta antaa edelleen E_NOTICEn kun sitä indeksoi olemattomalla avaimella.

echo $_REQUEST['asdasd'];

-->

Notice: Undefined index:  asd

punppis [12.03.2010 22:46:11]

#

Miksei voi vaan käyttää echo @$_REQUEST["nothing"]; ?

map_ [13.03.2010 00:32:09]

#

Kas, tuon operaattorin olemassaolo olikin unohtunut. Tästä vinkistähän tulikin suurin piirtein hyödytön :)

map_ [26.03.2010 11:24:27]

#

Juuri tuollaista pitkää ja toisteista muotoa oli tarkoitus välttää.

tsuriga [01.04.2010 04:47:18]

#

@-operaattori vain piilottaa virheen rumasti kun taas tällä saadaan palautettua ilman virhettä mikä tahansa haluttu arvo.

map_ [01.04.2010 14:34:21]

#

@ on kyllä yleisesti ottaen ruma piirre kielessä, ja useimmiten sitä ei kannata käyttää, mutta aiheuttaako se tässä tapauksessa mitään konkreettisia ongelmia?

tsuriga [13.04.2010 08:06:07]

#

Virhekontrollioperaattori on herkkä aiheuttamaan ennalta odottamattomia ongelmia. Mitä jos odotettua taulukkoa ei löydykään käytettävästä muuttujasta? @-operaattori ohittaa virheen huoletta kun taas oletusarvoista taulukkoa käytettäessä tulkki osaa tiedottaa tilanteesta. $_GET-taulukon ollessa kyseessä toki harvinaista, mutta särkinäisen PHP:n asennuksen tai eksentrisen sovelluksen tapauksessa mahdollista. Ongelmana tuossa voi siis olla debuggaus: "Osoiterivillä kyllä lukee news.php?id=2, mutta silti arvoa ei vain löydy... <monta tuntia myöhemmin> jaha, käyttämäni lisäpalikka on kutsunut unset($_GET)..."

Toisena huomiona mainittakoon manuaalin kommenteissa mainittu @-operaattorin harjoittama virhekäsittelijän kutsuminen error_levelin arvolla 0. Jos sovelluksessa on määritelty esimerkin #1 kaltainen virheenkäsittelijä niin sovellus tulostaa virhetilanteessa @-operaattoria käytettäessäkin virheviestin.

map_ [13.04.2010 11:37:51]

#

Hyviä pointteja. Itselläni on tapana määritellä vähän isompiin PHP-sovelluksiin aina virheenkäsittelijä, joka muuttaa virheet poikkeuksiksi. Käsittääkseni tilanteen voisi siis vielä korjata tarkistamalla käsittelijässä error_levelin nolluus, mutta, kuten sanottu, hyi.

Metabolix [14.12.2011 20:59:10]

#

Tämä toteutus ei valitettavasti auta silloin, kun data sisältää lisää taulukoita. Yksi ratkaisu voisi olla, että offsetGet muuttaisi palautettavat taulukot automaattisesti edelleen DefaultingArrayObject-olioiksi.

qeijo [28.02.2012 15:35:22]

#

Tiedän että on jo ikivanha ja muutenkin aika hulla homma, mutta:

class Request {

    private $params;

    public function __construct(array $array) {
        $this->params = $array;
    }

    public function __get($index) {
        return (array_key_exists($index, $this->params)) ? $this->params[$index] : null;
    }
}
$request = new Request(array("maikku" => "kimmo"));

var_dump($request->maikku);             //kimmo
var_dump($request->lasse);              //NULL
var_dump($request->maikku == "kimmo");  //bool(true)
var_dump($request->maikku == "jokke");  //bool(false)

Kirjoita kommentti

Muista lukea kirjoitusohjeet.
Tietoa sivustosta