php.de

Zurück   php.de > Webentwicklung > PHP-Fortgeschrittene

PHP-Fortgeschrittene Arbeiten mit PHP ohne Einschränkungen

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 11.10.2005, 15:27  
Gast
 
Beiträge: n/a
Standard [Erledigt] PHP5: "Private Lazy Initialization" mit __get() mo

Guten Tag!

Folgender Sachverhalt:

Zu einem bestimmten Problem habe ich mehrere Klassen und eine sogenannte Managerklasse fuer diese entwickelt. Die Managerklasse handhabt und "wrappt" den Zugriff auf die Objekte der anderen Klassen, die als private Member initalisiert werden.

Extremes Beispiel zur Verdeutlichung:

PHP-Code:
<?php
require 'AnotherClass.php';

class 
Manager
{
  private 
$InstanceOfAnotherClass;
  public function 
__construct()
  {
    
$this->InstanceOfAnotherClass = new AnotherClass();
  }
  
// Eine in diesem Fall sinnlose Wrapperfunktion
  
public function MakeThis()
  {
    return 
$this->InstanceOfAnotherClass->foo();
  }
}

$bar = new Manager();
print 
$bar->MakeThis(); // Wrapper
print $bar->InstanceOfAnotherClass->foo(); // resultiert, wie gewuenscht, in einem Fehler
?>
Stellt euch nun vor, ich braeuchte nur einige dieser Klassen immer und die anderen eher selten. Diese anderen Klassen wuerden den Speicher (bzw. den Server) bei einer Nichtverwendung sinnlos belasten, was aber definitiv nicht mein Ziel ist.
Dafuer habe ich die magische Funktion __get() in der Klasse Manager implementiert. Soweit, so gut. Jetzt aber das eigentliche Problem:
Auf diese Art und Weise (die mir einzig bekannte) vergisst PHP5 das private-Attribut.

(Diese Verfahrensweise nennt man "Lazy Initialization")

PHP-Code:
<?php

class Manager
{
  
// Hier darf die Membervariable $InstanceOfAnotherClass noch nicht definiert sein
  
public function __construct()
  {
    
// Hier wird ersteinmal nichts gemacht
  
}
  
  
// Auch mit private Klappt es nicht
  
private function __get($member)
  {
    switch (
$member):
      case 
'InstanceOfAnotherClass':
        
// Erst beim Gebrauch laden und instanziieren
        
include 'AnotherClass.php';
        
$this->InstanceOfAnotherClass = new AnotherClass();
        return 
$this->InstanceOfAnotherClass;
        break;
      
// Den Rest lassen wir jetzt einmal aussen vor
    
endswitch;
  }

  
// Eine in diesem Fall sinnlose Wrapperfunktion
  
public function MakeThis()
  {
    
// Erwuenscht: Initalisierung erst beim Aufruf durch eine Wrapperfunktion, die Classmember ist
    
return $this->InstanceOfAnotherClass->foo();
  }
}

$bar = new Manager();
// erwuenscht, da Wrapper
print $bar->MakeThis();

// unerwuenscht, aber leider moeglich: $InstanceOfAnotherClass sollte private sein
print $bar->InstanceOfAnotherClass->foo();
?>
Man kann trotz des private-Attributes noch von aussen zugreifen. Eine Definition "private $InstanceOfAnotherClass" würde keinen Sinn ergeben, da PHP die Funktion __get() aus den Methoden dieser Klasse nicht aufrufen würde, denn fuer diese gilt ja der Zugriff auf private Member.
Hat jemand dieses Problem schon mal gehabt und eventuell sogar eine Loesung parat?? Gibt es irgendwelche Internetseiten, die fuer dieses Problem eine Loesung bieten? Meine Suche ueber Google blieb erfolglos.

Vielen Dank im Voraus.

PS. Es gibt anscheinend Probleme mit der Codierung eurer Webinhalte! (anstatt z.B. eines "ö" kommt bei mir "?", Mozilla Firefox 1.0.7)
  Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 16.10.2005, 14:50  
Neuer Benutzer
 
Registriert seit: 27.09.2005
Beiträge: 22
nightfreak
Standard

Ich habe mir das jetzt nicht näher angeschaut, aber wenn das wirklich so ist solltest Du Dich besser an die PHP Entwickler wenden und sie bitten das zu beheben, oder sie zumindest fragen was sie sich dabei gedacht haben. Meiner Meinung nach sind __get() und __set() nur fürs Prototyping, oder "Quick and Dirty Scripts" zu gebrauchen weil sie eine Dokumentationslücke hinterlassen. Jemand der sich aus deinem Code eine Doku generiert bekommt keine Information über Deine "InstanceOfAnotherClass".
Lazy Initialization würde ich so machen:

PHP-Code:
<?php
class Manager
{
    private 
$instanceOfAnotherClass NULL;

    private function 
getInstanceOf AnotherClass()
    {
        
//erst beim ersten Aufruf wird das Objekt initialisiert
        
if (is_null($this->instanceOfAnotherClass)) {
            include_once(
'AnotherClass.php');
            
$this->instanceOfAnotherClass = new AnotherClass();
        }
        return 
$this->instanceOfAnotherClass;
    }
}
?>
nightfreak ist offline   Mit Zitat antworten
Alt 16.10.2005, 15:30  
Waq
Erfahrener Benutzer
 
Registriert seit: 15.08.2004
Beiträge: 2.473
Waq
Standard

Um das ans laufen zu bringen, müsste man wohl an __get() etc. übergeben, von wo aus sie aufgerufen werden, damit man innerhalb der Methode regeln kann, wer sie aufrufen darf. Da __get() immer für alle abgefangenen Variablen zuständig ist, kann man das nicht von aussen Regeln.
Und da die ZendEngine das wohl auf absehbare Zeit nicht tun wird (Patch einschicken hilft, ausser er wird abgelehnt), kann man sich wohl hässlicherweise an debug_backtrace() vergreifen... oder die Konstruktion über den Haufen werfen.

Ach, mit __get __set und __call kann man schöne Decorator bauen. Und Doku kommt nicht nur aus dem PHPDocumentor.
__________________
mod = master of disaster
Waq ist offline   Mit Zitat antworten
Alt 16.10.2005, 15:45  
Neuer Benutzer
 
Registriert seit: 27.09.2005
Beiträge: 22
nightfreak
Standard

Zitat:
Zitat von Waq
Ach, mit __get __set und __call kann man schöne Decorator bauen.
Hört sich interessant an, könntest Du das näher erläutern?
nightfreak ist offline   Mit Zitat antworten
Alt 16.10.2005, 15:49  
Gast
 
Beiträge: n/a
Standard

Wie es aussieht muss noch ein wenig an den Objekt-Überladungsfähigkeiten von PHP5 gearbeitet werden.
Ich habe im Laufe der Woche fast alle möglichen Varianten probiert, aber keine läuft so, wie man es theoretisch erwartet. Wenigstens für mein Problem habe ich eine Lösung gefunden, die aber wiederum mehr Schreibarbeit benötigt (es ist schon ohne dies ein großes Projekt), und somit die Wartbarkeit und die Skalierbarkeit des PHP-Codes beeinträchtigt, was doch eigentlich nicht das Ziel dieser neuen Sprachfeatures von PHP 5 war... naja.

Ich werde immer mal gucken ob und wie sich dieses Verhalten geändert hat und dann hier im Forum Bescheid sagen.

Und vielen Dank für eure Hilfe, hier werde ich wahrscheinlich öfters vorbeischauen!

Grüße

Martin
  Mit Zitat antworten
Alt 16.10.2005, 16:02  
Waq
Erfahrener Benutzer
 
Registriert seit: 15.08.2004
Beiträge: 2.473
Waq
Standard

Zitat:
Zitat von mmorgenstern
keine läuft so, wie man es theoretisch erwartet.
Doch durchaus.
Ob __get() private ist oder nicht darf keine Auswirkungen haben, da __get() für alle abgefangenen Variablen zuständig ist.
Und wenn die Variable als private definiert ist, ist sie definiert und __get() wird nicht mehr aufgerufen.

Privates __get() ist im Moment einfach nicht vorgesehen, es verhält sich aber alles so, wie es soll.
__________________
mod = master of disaster
Waq ist offline   Mit Zitat antworten
Alt 16.10.2005, 16:15  
Gast
 
Beiträge: n/a
Standard

Erstaunlich?? Nein, kein Wunder. Ich teste mit PHP5.1RC1 auf meinem Apache. Und debuggen aber im ZendStudio, welches PHP 5.0.4 verwendet.

Folgender Code gibt unterschiedliche Ergebnisse:

PHP-Code:
<?php

class foo
{
    private 
$bar 32;
    public function 
__get($member)
    {
        if (
$member == 'bar')
            return 
132;
    }
}

$foo = new foo;
print 
$foo->bar;


?>
PHP 5.0.4:
Fatal error: Cannot access private property foo::$bar in C:\PHP5Dev\tests\overloading\test2.php on line 14

PHP 5.1RC1:
132
  Mit Zitat antworten
Alt 16.10.2005, 16:41  
Waq
Erfahrener Benutzer
 
Registriert seit: 15.08.2004
Beiträge: 2.473
Waq
Standard

In PHP 5.1 wird der Zugriff von aussen auf eine private Variable als "findet nix" interpretiert, weswegen __get() aufgerufen wird.
In PHP 5.0 wird die private Variable gefunden, was im fatal error endet.

Ein Zugriff von innen wird nie __get() aufrufen, da $bar ja schon definiert ist.
__________________
mod = master of disaster
Waq ist offline   Mit Zitat antworten
Alt 16.10.2005, 16:51  
Gast
 
Beiträge: n/a
Standard

Ja okay, die Frage ist nur welche Variante nun ein Bug ist oder nicht. Das Verhalten von PHP5.1 wäre richtiger als bei 5.0, da private und protected nicht sichtbar sind und somit die Funktionen __get, __call und __set greifen, egal ob klassenintern die member schon definiert wurden oder nicht. Sonst wären diese Funktionen doch sinnlos. Bei public ist das Verhalten auch okay, dort wird kein __get verwendet wenn die Eigenschaft existiert.

Wenn man von innen (also von der Klasse aus) auf __get zurückgreifen will, darf man die Eigenschaft noch nicht definieren (wie im 2. Beispiel ganz oben). Eigentlich auch ein logisches Verhalten. Aber alles irgendwie nicht richtig dokumentiert...
  Mit Zitat antworten
Alt 16.10.2005, 16:55  
Waq
Erfahrener Benutzer
 
Registriert seit: 15.08.2004
Beiträge: 2.473
Waq
Standard

Ein Bug ist keins, die Theorie hat sich von 5.0 zu 5.1 halt verändert.
Im Endeffekt ist diese Abfangerei nicht auf die Feinheiten von Sichtbarkeitsmodellen ausgelegt, sondern eher auf ein gibbet oder gibbet nich.
Nützlich um schnell nen Decorator zu schreiben, oder zur Lazy-Initialisierung ohne private-Spirenzchen.
__________________
mod = master of disaster
Waq ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
php __get, lazy initialization php, php __get aufrufen, php5 lazy loading, __get aufruf, lazy initialisation, php __get return private members, php lazy load __get, __get switch class php, php __get implementation, php function __get, php __get lazy initialization, php lazy initialization, php __get switch, php5 private, php __get __set private protected, php property __get, php __get bug, php5 lazy, php property lazy initialization

Alle Zeitangaben in WEZ +2. Es ist jetzt 20:46 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.