2010-07-21 4 views
14

Oto, co mam: Wszystkie obiekty, które można przechowywać w bazie danych, rozszerzają klasę abstrakcji DatabaseObject, która ma cały kod logiczny, aby faktycznie obserwować zmiany atrybutów i uruchamiać kwerendy danych.Jak przesłonić właściwość statyczną obiektu nadrzędnego i pozwolić obiektowi nadrzędnemu na dostęp do nowej wartości w PHP?

Używam dwóch zmiennych statycznych do zdefiniowania szczegółów specyficznych dla obiektu. Definiuję je ogólnie w klasie bazowej, a następnie rzekomo nadpisuję je w rzeczywistych obiektach bazy danych.

Problem: Kiedy kod w klasie nadrzędnej jest rzeczywiście wykonywany, używa starej wartości nadrzędnej zamiast bieżącej wartości obiektu.

Oto kod dla klasy bazowej:

abstract class DatabaseObject { 

    public $id; 

    private static $databaseTable = NULL; 
    private static $databaseFields = array(); 

    private $data = array(); 
    private $changedFields = array(); 

    public function IDatabaseObject($id) { 
    $this->id = $id; 
    $this->data = Database::GetSingle(self::$databaseTable, $id); 

    Utils::copyToObject($this, $this->data, self::$databaseFields); 
    } 

    public static function Load($id) { 
    return new self($userID); 
    } 

    public static function Create($data) { 

    $id = Database::Insert(self::$databaseTable, $data); 

    return new self($id); 
    } 

    public function Save() { 
    $data = Utils::copyFromObject($this, $this->changedFields); 

    Database::Update(self::$databaseTable, $data, $this->id); 

    } 

    public function __constructor() { 
    // We do this to allow __get and __set to be called on public vars 
    foreach(self::$databaseFields as $field) { 
     unset($this->$field); 
    } 
    } 

    public function __get($variableName) { 
    return $this->$variableName; 
    } 

    public function __set($variableName, $variableValue) { 
    // We only want to update what has been changed 
    if(!in_array($variableName, $this->changedFields) && in_array($variableName, self::$databaseFields)) { 
     array_push($this->changedFields, $variableName); 
    } 

    $this->$variableName = $variableValue; 
    } 
} 

A oto kod dla jednego z obiektów wystających klasę bazową powyżej:

class Client extends DatabaseObject { 

    public static $databaseTable = "clients"; 
    public static $databaseFields = array("name","contactName","primaryUserID","email","is_active","rg","cpf","cnpj","ie","addrType","addrName","addrNumber","addrComplement","addrPostalCode","addrNeighborhood","addrCity","addrState","addrCountry","phoneLandline","phoneFax","phoneMobile"); 

    public $name; 
    public $contactName; 

    public $primaryUserID; 
    public $email; 

    public $is_active; 

    public $rg; 
    public $cpf; 
    public $cnpj; 
    public $ie; 

    public $addrType; 
    public $addrName; 
    public $addrNumber; 
    public $addrComplement; 
    public $addrPostalCode; 
    public $addrNeighborhood; 
    public $addrCity; 
    public $addrState; 
    public $addrCountry; 

    public $phoneLandline; 
    public $phoneFax; 
    public $phoneMobile; 

    public static function Load($id) { 
return new Client($id); 
    } 

} 

Co robię źle tutaj? Czy istnieje inny sposób, w jaki mogę osiągnąć ten sam rezultat?

Krótki dodatek: Deklaruję atrybuty w treści klasy głównie po to, aby była widoczna przez funkcję autouzupełniania NetBeans.

+1

możliwy duplikat [Dziedziczenia klasy w PHP 5.2: Nadpisywanie zmiennej statycznej w rozszerzeniu?] (Http://stackoverflow.com/questions/3017777/class-inheritance-in -php-5-2-overriding-static-variable-in-extension-class) – outis

+0

To jest uzasadnione pytanie w php, które ma dość mylącą implementację, ale pytanie można naprawdę zawęzić, aby było bardziej ogólne i dostępne dla innych osób. –

Odpowiedz

41

Szukasz Late Static Binding.

Więc trzeba użyć:

static::$databaseTable 

zamiast

self::$databaseTable 

Ta funkcja jest dostępna od PHP 5.3. Symulowanie tego w PHP 5.2 jest bardzo trudne z dwóch powodów: get_called_class jest dostępny tylko od PHP 5.3. Dlatego też musi zostać zasymulowany przy użyciu debug_backtrace. Drugi problem polega na tym, że jeśli masz wywoływaną klasę, nadal nie możesz używać $calledClass::$property, ponieważ jest to również funkcja PHP 5.3. Tutaj musisz użyć eval lub Reflection. Mam więc nadzieję, że masz PHP 5.3;)

+0

Niestety, nie mogę uaktualnić mojej wersji PHP. Na serwerze działa Plesk 9.5, który obsługuje tylko do 5.2.13; Obawiam się, że ręczna aktualizacja może przerwać niektóre aplikacje. Zobaczę, czy mogę wymyślić alternatywny sposób wykonania tego samego zadania. – DfKimera

+0

Dziękuję bardzo za tę wskazówkę, miałem dokładnie ten sam problem! –

+0

Najlepszym sposobem jest przekazanie klasy jako pierwszego parametru do dowolnej metody, która musi uzyskać dostęp do tych właściwości. W ten sposób możesz przeszukać tę klasę bezpośrednio w celu zastąpienia. Jeśli go nie znajdziesz, możesz wejść na drabinkę rodzicielską, aż znajdziesz pole. –

Powiązane problemy