Facebook
Twitter
Google+
Kommentare
9

Read-only Attribute

Mein erster Tag in „Freiheit“. Leider war ich die letzten fünf Tage krank und ich glaube meine Gehirn arbeitet immer noch nicht auf Hochtouren. Aber eigentlich sollte ich jetzt gerade wieder an meinem Arbeitsplatz sitzen und ein wenig die Qualität sichern.

Das ich noch nicht wieder ganz gesund bin, kann man ganz einfach daran sehen, dass ich heute ein wenig mit den magischen Methoden hantieren will. Eigentlich ja eine Eigenschaft von PHP, die ich gar nicht mag. Auf jeden Fall geht es heute darum ein Attribut eines Objektes so anzubieten, auf das man von Außen nur lesend zugreifen kann. Ein paar interne PHP Klassen bieten so etwas ja auch an. Vielleicht habt ihr euch deswegen ja schon mal gefragt, wie das geht.

Wie wollen also folgendes Verhalten erzeugen:

$bar = new Foo( );
echo $bar->readOnlyVar;
$bar->readOnlyVar = 'test'; // soll eine Exception werfen

Wirklich schwer ist es aber nicht dies hinzubekommen. Wir nehmen uns einfach die Klasse, definieren uns das Attribut erstmal als private und machen ein wenig Magie.

class Foo
{
  private $readOnlyVar;

  public function __get( $varName )
  {
    if ( $varName == 'readOnlyVar' ) {
      return $this->readOnlyVar;
   }
  }

  public function __set( $varName,$varValue )
  {
  }
}

Schon sind wir am Ende angelangt. Eigentlich sollte die Klasse sich jetzt genau wie gewünscht verhalten. Vielleicht noch kurz erklären, was da passiert. Alle Attribute, die angesprochen werden, aber nicht existieren werden an die magischen Methoden __set bzw. __get weitergeleitet. Da hat man dann die letze Chance etwas zu machen, bevor der Code sinnlos endet. Da ich versuche von Außen die Variable $readOnlyVar zu verändern, lande ich natürlich auch dort, denn ein public $readOnlyVar existiert nicht.

Finde ich den Ansatz schön? Nein auf keinen Fall! Ich bin ein Freund von settern und gettern, mit denen man das gleiche etwas eleganter und wartbarer gestallten kann. Interessant finde ich es trotzdem, da man so einer Klasse ein Verhalten mitgeben kann, dass es so eigentlich gar nicht gibt. Aber wie immer gilt: ich mag die meisten magischen Methoden nicht, aber sie sind ein Teil von PHP und deswegen könnt ihr sie auch gerne verwenden, ohne gleich böse angeschaut zu werden.

Über den Autor

Nils Langner

Nils Langner ist der Gründer von "the web hates me" und auch der Hauptautor. Im wahren Leben leitet er das Qualitätsmanagementteam im Gruner+Jahr-Digitalbereich und ist somit für Seiten wie stern.de, eltern.de und gala.de aus Qualitätssicht verantwortlich. Nils schreibt seit den Anfängen von phphatesme, welches er ebenfalls gegründet hat, nicht nur für diverse Blogs, sondern auch für Fachmagazine, wie das PHP Magazin, die t3n, die c't oder die iX. Nebenbei ist er noch ein gern gesehener Sprecher auf Konferenzen. Herr Langner schreibt die Texte über sich gerne in der dritten Form.
Kommentare

9 Comments

  1. Also ich würde folgende Umsetzung eher bevorzugen: alle readonly-Vars werden in einem separaten Container (Array, stdClass oder eigene Klasse) im Objekt gehalten und sind nicht per setter-Methode veränderbar, nur über den Konstruktor einmalig. Wenn jetzt per __set() etwas gesetzt werden soll, dann wird immer zuerst dieser Container überprüft. So ähnlich ist das auch bei Zend_Config mit readonly, allerdings kann man dort dann kein einziges Attribut mehr ändern, was in dem UseCase auch absolut korrekt ist.

    Reply
  2. Na z.B. um seine Kollegen dran zu hindern, mal eben irgendwo im Code ein neues Attribut zu erstellen (ja, nicht ändern, sondern erstellen)… Ist kein Vergnügen, sowas zu debuggen.

    Es gibt leider Menschen, die sich an keine Regeln halten wollen und dazu gezwungen werden müssen. 😉

    Reply
  3. Anderes denkbares Beispiel wäre wenn man Daten zu einem Objektmodel zusammen fast und bestimmte Attribute nicht mehr änderbar sein dürfen… ( id…)

    Reply
  4. @snirgel: Die ID Geschichte wäre auch mein Beispiel gewesen. Aber PHP hat einige Beispiele für so etwas schon eingebaut. Ich kann nur grad nicht suche. Vielleicht schaffe ich es heute Abend.

    Reply
  5. Eine bessere Lösung wäre „public final $property;“
    Leider kann man in PHP keine Variablen final setzen – oder geht das schon in 5.3? In Java kann man finale Klassenvariablen zumindest im Konstruktor noch setzen, danach aber nicht mehr.
    Ansonsten sind getter und setter auch meine bevorzugte Vorgehensweise.
    Apropos „magisch“, „getter“ und „setter“: In Magento hab ich mich mal nach einer „getFooBar()“ Methode zu Tode gesucht. Die Lösung: solche Aufrufe wurden durch eine magische „__call“ Methode 5 Ebenen höher abgefangen und diese hat die Variablen dann gesetzt bzw. ausgelesen! x)

    Reply
  6. Mir fällt hierbei mein „Container-Generator“ ein:

    http://www.hadanite-marasek.de/index.php5?topic=codegen

    Ich persönlich nutze nie __set und __get, weil ich mich damit ja um die „Selbstdokumentation“ bringe.

    Für read-only ist es mein Ansatz, eine Überklasse zu verwenden, die properties in einem Array speichert, auf den ich mit protected-Methoden zugreife. Diese Klasse verwaltet dann, dass ein Wert nicht mehr geändert werden darf, auch, welche Werte erforderlich sind.
    Von aussen wird dann eine Methode aufgerufen, die das Ding für weitere Änderungen sperrt & bei der Gelegenheit die Pflichtwerte validiert.

    Sollte ich Singleton/Registry verwenden, schaffe ich mir damit „Action at a distance“ from, err, vom Hals.

    Reply

Leave a Comment.

Link erfolgreich vorgeschlagen.

Vielen Dank, dass du einen Link vorgeschlagen hast. Wir werden ihn sobald wie möglich prüfen. Schließen