[php] __get() / __set() functies

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Dennis
  • Registratie: Februari 2001
  • Nu online
Ik schrijf vandaag even een zeer compact database framework voor een door mij te ontwikkelen applicatie. Nou heb ik voor elke tabel zegmaar een corresponderende klasse. Die zijn afgeleid van een hoofdobject en bevatten allemaal een array/hashtable met daarin veldwaarden.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
class Page extends Persistent
{
    private $values = array(
    "changed" => false,
    "notpersisted" => false,
    "Id" => "", 
    "ParentId" => "", 
    "PageName" => "", 
    "Template" => "");
    
    public function __get($name)
    {
        if (isset($this->values[$name]))
        {
            return $this->values[$name];
        }
        else
        {
            throw new Exception($name." is not a valid property.");
        }
    }
    
    public function __set($name, $value)
    {
        if (isset($this->values[$name]))
        {
            // The given value is different from current value.
            if ($value != $this->values[$name])
            {
                $this->values[$name] = $value;
                $this->values["changed"] = true;
            }
        }
        else
        {
            throw new Exception($name." is not a valid property.");
        }
    }
    
    public function __construct()
    {
        $this->notpersisted = false;
    }
    
    public static function Load(SqlRow $row)
    {
        $object = new Page();
        try
        {
            $object->values["Id"] = $row->values["Id"];
            $object->values["ParentId"] = $row->values["ParentId"];
            $object->values["PageName"] = $row->values["PageName"];
            $object->values["Template"] = $row->values["Template"];
        }
        catch (Exception $exception)
        {
            throw new Exception("SqlRow object " + $row + " does not match destination class '" + "Page" + "'");
        }
        
        return $object;
    }
}


Dit werkt uitstekend! Echter, zoals je ziet wil ik in de static load methode een object bouwen aan de hand van een SqlRow object. Ook deze bevat zo'n zelfde constructie met array en accessors maar php wil deze niet gebruiken zodra ik de $row->values["Template"]; aanroep. Zowel private/protected/public maken het onmogelijk om de __get en __set methoden te gebruiken.

Ik begrijp niet waarom het bij de ene situatie wél werkt, en bij een 'externe aanroep' niet. :?.

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Waarom zou je uberhaubt de properties in de vorm van een array willen aanspreken als je toch al gebruik maakt van __get en __set? Waarom niet gewoon $row->Id en $row->ParentId etc? De reden dat het niet werkt (extern zoals je noemt, in public scope specifieker) is dat $values private is en dus niet direct bereikbaar is voor andere objecten. En het opvragen van een element uit een array wordt niet doorgestuurd naar de magic method __get. $name kan nu eenmaal niet gevuld worden op die manier.

Waarom maar je uberhaubt eigenlijk gebruik van een array voor je velden? Het lijkt me beter om gewoon enkele losse variabelen en bijbehorende get en set methods te schrijven. Zo heb je ook meer controle over welke data bereikbaar is en hoe. Als je er toch voor kiest __get en __set te houden op deze manier, dan kun je binnen __set nog steeds dynamisch schrijven en wel op de volgende manier:
PHP:
1
$this->$name = $value;


Dan nog wat over je naamgeving. Waarom $object en geen $page? En Load vind ik ook niet echt een duidelijke informatieve naam. Ik zou eerder kiezen voor initializeNewPageWith of iets dergelijks. Dat leest een stuk gemakkelijker imo.

Noushka's Magnificent Dream | Unity


Acties:
  • 0 Henk 'm!

  • Dennis
  • Registratie: Februari 2001
  • Nu online
Michali schreef op zaterdag 27 augustus 2005 @ 17:29:
Waarom zou je uberhaubt de properties in de vorm van een array willen aanspreken als je toch al gebruik maakt van __get en __set? Waarom niet gewoon $row->Id en $row->ParentId etc? De reden dat het niet werkt (extern zoals je noemt, in public scope specifieker) is dat $values private is en dus niet direct bereikbaar is voor andere objecten. En het opvragen van een element uit een array wordt niet doorgestuurd naar de magic method __get. $name kan nu eenmaal niet gevuld worden op die manier.

Waarom maar je uberhaubt eigenlijk gebruik van een array voor je velden? Het lijkt me beter om gewoon enkele losse variabelen en bijbehorende get en set methods te schrijven. Zo heb je ook meer controle over welke data bereikbaar is en hoe. Als je er toch voor kiest __get en __set te houden op deze manier, dan kun je binnen __set nog steeds dynamisch schrijven en wel op de volgende manier:
PHP:
1
$this->$name = $value;


Dan nog wat over je naamgeving. Waarom $object en geen $page? En Load vind ik ook niet echt een duidelijke informatieve naam. Ik zou eerder kiezen voor initializeNewPageWith of iets dergelijks. Dat leest een stuk gemakkelijker imo.
Hey, bedankt voor je tips! $Page is inderdaad veel beter dan $object, maar dit is maar een concept. Ik zal het nog wel aanpassen :).

Verder vraag ik me af hoe je met php een get en set methode maakt die automatisch worden aangeroepen? Of bedoelde jij zoiets als SetPropertyXXX en GetPropertieXXX :?. Dat vind ik geen mooie oplossing namelijk.

Ik betwijfel overigens of het aanspreken van een array element niet naar __get doorgestuurd wordt, want waarom werkt het in de bovenstaande code dan wél? De code waarin het niet werkt is die van het SqlRow object.

Acties:
  • 0 Henk 'm!

  • Michali
  • Registratie: Juli 2002
  • Laatst online: 29-05 22:54
Dennis schreef op zaterdag 27 augustus 2005 @ 18:16:
Verder vraag ik me af hoe je met php een get en set methode maakt die automatisch worden aangeroepen? Of bedoelde jij zoiets als SetPropertyXXX en GetPropertieXXX :?. Dat vind ik geen mooie oplossing namelijk.
setProperty() en getProperty() bedoel ik idd. Anders zou ik toch voor een switch statement kiezen binnen __get en __set:
PHP:
1
2
3
4
5
6
7
8
9
10
11
public function __get($name)
{
  switch ( $name )
  {
    case 'eenProperty':
    case 'eenAndereProperty':
      return $this->$name;
    default:
      return null;
  }
}

Dit zou ik doen om controle te houden over welke properties een ander object mag opvragen.
Ik betwijfel overigens of het aanspreken van een array element niet naar __get doorgestuurd wordt, want waarom werkt het in de bovenstaande code dan wél? De code waarin het niet werkt is die van het SqlRow object.
Omdat je met $object->values gewoon direct referreert naar de $values variabel binnen Page. Doe maar eens een var_dump($name) binnen __get(), dan kun je zo zien of hij wel wordt aangeroepen en welke waarde hij steeds heeft. Welke waarde zou $name anders moeten krijgen? Lijkt me niet dat het dan ook echt 'values["Id"]' is wat er in komt te staan. Alleen de index ('Id' bv.) wordt sowieso niet alleen meegegeven.

[ Voor 3% gewijzigd door Michali op 27-08-2005 19:38 ]

Noushka's Magnificent Dream | Unity