2010-10-26 11 views
10

Prima di tutto: A quite similar problem è stato pubblicato e in qualche modo risolto già, ma non risponde ancora al mio problema specifico. Maggiori informazioni su questo più tardi.PHP Il metodo padre ereditato non può accedere alla proprietà privata del figlio

In parole: Ho una classe base che fornisce alcuni metodi a tutti i childs, ma non contiene alcuna proprietà. Mio figlio eredita questi metodi, che dovrebbero essere usati per accedere alle proprietà del bambino. Se la proprietà del figlio è protected o public, tutto funziona correttamente, ma se la proprietà del figlio è private, ha esito negativo senza errori (non succede nulla).

in codice:

class MyBaseClass { 
    public function __set($name, $value) { 
     if(!property_exists($this, $name)) 
      throw new Exception("Property '$name' does not exist!"); 
     $this->$name = $value; 
    } 
} 

class ChildClass extends MyBaseClass { 
    public $publicProperty; 
    protected $protectedProperty; 
    private $privateProperty; 
} 

$myChild = new ChildClass(); 
$myChild->publicProperty = 'hello world'; //works of course! 
$myChild->protectedProperty = 'hello world'; //works as expected 
$myChild->privateProperty = 'hello world'; //doesn't work? 

il suddetto problema simile ha ottenuto la soluzione di utilizzare il metodo magico __set() per accedere alle proprietà private, ma questo io sto già facendo. Se implemento __set() all'interno del bambino, funziona ovviamente, ma l'idea è che il figlio erediti lo __set() dal suo genitore, ma ovviamente non può accedere al metodo privato del figlio.

Lo fa apposta? Sto sbagliando qualcosa di sbagliato? o il mio approccio è solo una schifezza di design?

Background: La mia idea originale era: Il tutto dinamico su __set() è una cosa che non mi piace. Di solito una proprietà privata dovrebbe mai essere accessibile dall'esterno, quindi ho implementato lanciando metodi __set- e __get nella mia ultima classe base (da cui ereditano tutte le classi).

Ora voglio generare dinamicamente un'istanza da un file XML e quindi ho bisogno di accedere alle proprietà. Ho fatto la regola, che qualsiasi classe XML-istanzabile ha bisogno di implementare il magico metodo __set() e quindi può essere creato dinamicamente. Invece di implementarlo in ogni classe che potrebbe essere generata un giorno, ho deciso di farli ereditare da una classe chiamata come class Spawnable { } che fornisce il metodo __set necessario.

+0

Questo non dovrebbe funzionare ... Questo '$ myChild-> protectedProperty = 'hello world';' dovrebbe generare un errore irreversibile ... Come la proprietà private. http://php.net/manual/en/language.oop5.visibility.php – dododedodonl

risposta

17

Questa è la differenza tra private e protected. I metodi e le proprietà private non possono essere ereditati o raggiunti. Dovrai invece cambiarli in protetti.

Vedi le manual on visibility

membri dichiarati protetti può essere accessibile solo all'interno della classe stessa e ereditato nonché le classi superiori. I membri dichiarati come privati ​​possono accedere solo alla classe dalla classe che definisce il membro .

+2

Ovviamente hai ragione! Ho in qualche modo immaginato che il metodo __set() rientri nell'ambito del bambino, perché lo ha ereditato dalla classe base. Ciò significherebbe che il bambino vuole accedervi con le proprietà private di # s utilizzando il metodo del genitore. Ma ovviamente in PHP il bambino non sta effettivamente "importando" i metodi dal genitore, ma piuttosto li chiama, come "Parent :: Method()". Quindi esce dalla visibilità e può - ovviamente - accedere solo ai campi pubblici e protetti. Questo è molto insoddisfacente, anche se lo so ora. Molte grazie per il vostro aiuto! – Jan

4

Immagino che si possa modellare qualcosa usando Reflection. Ad esempio, nella classe Spawnable:

public function __set($name, $value) 
{ 
    $reflector = new ReflectionClass(get_class($this)); 
    $prop = $reflector->getProperty($name); 
    $prop->setAccessible(true); 
    $prop->setValue($this, $value); 
} 

Non è il codice più carino, però.

+0

Oh bello? Aspetta un secondo! Usando Refelction posso effettivamente rendere temporaneamente accessibili le proprietà private, iniettare valori e renderli di nuovo inaccessibili? Questo risolverà molti dei miei problemi. – Jan

+0

... ovviamente non è l'approccio migliore, ma di solito tengo comunque chiusi i miei dati personali. Ho solo bisogno di implementare il modo .NET di avere XML-Configs con oggetti che possono essere instanciati in fase di runtime. Funzionalità molto bella, che voglio nel mio framework php. Grazie per il suggerimento, controllerò la documentazione di riflessione. – Jan

+1

Sì, tutti i tipi di cattiveria possono essere fatti con la riflessione. Tieni presente che è piuttosto lento, però. – Frode

1

Dopo aver esaminato il mio concetto, penso che sia una cattiva idea, seguire questo approccio. Questo è un problema generale con la mancanza di PHP di differenza tra proprietà e campi.Naturalmente i campi privati ​​dovrebbero mai essere accessibili dall'esterno, ma solo proprietà, che sono definite dal programmatore. L'assenza di proprietà automatiche (e non intendo questi metodi magici __set() e __get()) o alcune regole convenzionali per l'accesso alle proprietà, rende difficile indovinare, quale convenzione di denominazione è stata utilizzata dal programmatore quando si implementano i setter per i campi privati ​​in la sua classe

Il concetto meglio qui potrebbe essere, per invocare l'esistenza di setter ben named-per ogni classe spawnable, anche se potrebbe rompersi, se qualcuno ha contribuito il codice, che non sta attuando le attese setter di nome convenzionali.

Tuttavia, molte grazie per i vostri pensieri e suggerimenti!

+0

In che modo una proprietà non è un campo? – DanMan

+0

http://stackoverflow.com/a/295109/489772 – Jan

Problemi correlati