Newsgroup: it.comp.www.php
Titolo: Ereditarietà e metodi statici

Salve :)
Sto facendo qualche esperimento con la oop e l'ereditarietà in php.
Ho un problema in questa situazione:
class A {
    public function test() {
        print __CLASS__;
        print get_class($this);
    }
    public static function testStatic() {
        print __CLASS__;
    }
}
class B extends A {
}
$b = new B();
$b->test();
B::testStatic();
$b->test() stampa "AB".
B::testStatic() stampa "A".
Io avrei bisogno che B::testStatic() mi stampasse "B", ovvero che
dicesse su quale classe è stato richiamato, e non in quale è stato
definito. Non posso ovviamente usare get_class($this) perchè è un
metodo statico...
Qualcuno ha qualche idea?
Grazie :)

 metodo statico...
E' giusto che, per questo scopo, non puoi utilizzare un metodo statico
(=metodo di classe).
Sei costretto ad istanziare la classe e a chiamare un metodo con
all'interno la chiamata a "get_class".
Ciao,
     Fabrizio
--website: 
http://www.negusweb.it

 --website:
http://www.negusweb.it
Grazie per la risposta.
Non c'è quindi modo di risalire alla classe da cui un metodo statico è
richiamato dall'interno del metodo statico stesso?
Sono in una situazione in cui ha poco senso secondo me instanziare la
classe per poi richiamare il metodo, perchè non effettua alcuna
operazione sull'oggetto stesso ma restituisce semplicemente un array
di oggetti di quella classe.
Davide

 di oggetti di quella classe.
E' l'unica soluzione.
Considera però che alla fine il problema non è grande, anche perchè
dal PHP 5 in poi puoi entrare nel vari livelli di un oggetto con una
sola indirezione, ovvero:
$ritornoFunzione = new Oggetto()->Funzione(<parametri>);
a differenza delle versioni precedenti in cui dovevi:
$obj = new Oggetto();
$ritornoFunzione = $obj->Funzione(<parametri>);
L'unica rottura di scatole con il PHP è l'overload delle funzioni, che
non può essere fatto come in tutti gli altri linguaggi ad oggetti; per
questo motivo non potrai avere nel senso in cui siamo abituati più
costruttori di un oggetto.
Per questo motivo io mi creo un metodo statico, NewInstance(), che non
altro che chiamare l'unico costruttore dell'oggetto passando dei
parametri vuoti, o nulli. Questo per mantenere una certa formalità con
la programmazione ad oggetti.
Ciao,
    Fabrizio
---website: 
http://www.negusweb.it

 costruttori di un oggetto.
Non in tutti. Nemmeno python lo permette, per esempio.
E` una scelta progettuale. :)
Pero` puoi dichiarare un parametro "mixed", e verificare nel costruttore 
di che tipo e` con is_array(), is_string(), is_int(), ecc.
Onestamente preferisco cosi`, piuttosto che andare a cercare quale 
funzione (tutte con lo stesso nome) viene chiamata in un certo contesto, 
magari solo per scoprire che il parametro che mi viene passato dalla 
pagina web e` un array e non una stringa, perche` l'htmlista ha chiamato 
il campo "pippo[]" invece di "pippo". :)
Bye.

 il campo "pippo[]" invece di "pippo". :)
Preferisco l'overload delle funzioni al posto dell'uso del parametro
"mixed" e questo perchè l'overload consente di inviduare errori in
fase di compilazione (non è il caso del PHP che non è compilato, ma mi
restituisce comunque errore) , piuttosto che di runtime (più difficili
da scovare).
Ti faccio un esempio. Nella maggior parte dei casi ho delle classi con
due costruttori: uno senza parametri e uno con tanti parametri quante
sono le proprietà dell'oggetto, per inizializzarlo. Mettiamo di avere
una classe con 3 parametri: p1, p3, p3. La classe si chiama COggetto.
Ci possono essere diversi punti all'interno del mio programma in cui
istanzio un oggetto di tipo COggetto.
Farò una cosa di questo tipo:
$obj = new COggetto( valore1, valore2, valore3);
in tutti i punti in cui istanzio l'oggetto, ovviamente (e possono
essere i più disparati).
Ora, che cosa succede se a COggetto aggiungo una proprietà non
prevista?
Nel caso in cui aggiungo una nuova proprietà e quindi modifico il
costruttore (per inizializzare la quarta proprietà), con un linguaggio
compilato non riuscirò a compilare fino a quando non avrò aggiornato
tutte le sezioni di codice per implementare il quarto parametro. E
questa è cosa buona e giusta.
Se invece avessi usato un parametro <mixed>, sarebbe un problema ora
andare a ritrovare tutte le parti di codice in cui l'oggetto viene
istanziato (perchè il compilatore non mi darebbe errore, e neanche a
runtime nel caso di linguaggi interpreatiti).
Cioè usando parametri "mixed" sono io a dover cercare l'errore. Con
l'overload è il compilatore a dirmi dov'è l'errore. E quindi è più
facile evitare errori in fase di runtime (perchè l'oggetto potrebbe
comportarsi in modo strano non avendo il valore del quarto parametro
in fase di inizializzazione).
Spero di essere stato il più chiaro possibile.


 richiamato dall'interno del metodo statico stesso?
IMHO, sarebbe stato *comodo* avere un modo per fare ciò che chiedi.
Detto questo, se tu chiami B::metodo() in un punto qualsiasi del tuo
codice, vuol dire che conosci già quale sia la classe su cui stai
applicando metodo().
Le soluzioni quindi sono svariate, anche se obbligano a scrivere un po'
di codice in più. Le più semplici sono due:
[Soluzione 1: gli passi il nome della classe come argomento]
class A {
    ...
    public static function testStatic($classe) {
        print $classe;
    }
}
class B extends A { }
...
B::testStatic('B');
[Soluzione 2: fai l'overloading di testStatic() nelle classi derivate]
class A {
    ...
    public static function testStatic($classe) {
        print $classe;
    }
}
class B extends A {
    public static function testStatic() {
        parent::testStatic(__CLASS__);
    }
}
...
B::testStatic();
Ciao, Maverick
ps. se conosci la classe solo in fase di run-time, puoi chiamare:
    $classe = get_class(...); // get_class() ad es. ritorna 'B'
    call_user_func( array($classe, 'testStatic'), $classe );
-- 
«Che non siete più liberi di non avere una casa con letto per dormire.
 Lavorate voi - schiavi dei soldi - che non sentite la puzza della
 schiavitù!» (a Mario di Monte Mario, Roma) # 
http://libre.netsons.org/

On Oct 15, 11:09 pm, "Maverick FC" <freecult...@NOSPAMlibero.it>
wrote:

Grazie a tutti :)
Alla fine penso che rivedrò le mie classi e eviterò di usare quel
metodo in maniera statica; la soluzione di Maverick mi era venuta in
mente ma l'avevo scartata perchè volevo evitare di passargli il nome
della classe come parametro o di fare overloading, perchè lo scopo
delle classe a cui sto lavorando è quello di minimizzare il codice da
aggiungere nelle classi figlie.
@Negus:
ritornoFunzione = new Oggetto()->Funzione(<parametri>)
La versione di php (5.2.2) che ho sul mio serverino di sviluppo non me
lo permette, dà questo errore:
Parse error: syntax error, unexpected T_OBJECT_OPERATOR

 fase di inizializzazione).
Ma qui non hai il compilatore, vai direttamente a runtime. ;)
Quello che voglio dire e` che e` sempre sbagliato cercare di piegare un 
linguaggio a quello che sai fare tu, ed e` sempre meglio capire e 
sfruttare le sue vere potenzialita`.
Bye.

 Ma qui non hai il compilatore, vai direttamente a runtime. ;)
Il "nostro" Umberto Salsi per l'appunto ha creato un validatore. :-)
http://www.icosaedro.it/phplint/index.html
Personalmente, però, non l'ho mai usato.
Ciao, Maverick


 B::testStatic();
Il codice quissù non produce errori in PHP5, ma produce un fatal error
in PHP6: "Declaration of B::testStatic() must be compatible with that of
A::testStatic()".
Insomma, per ottenere la compatibilità con PHP6 bisogna aggiungere un
argomento inutile a B::testStatic():
class B extends A {
    public static function testStatic($dummy=null) {
        parent::testStatic(__CLASS__);
    }
}
Ciao, Maverick


 sfruttare le sue vere potenzialita`.
Tutto il contrario. Sto cercando di utilizzare tutta la grammatica, la
sintassi e le regole del linguaggio per prevenire tutti gli errori che
io, programmatore, potrei commettere.


 Per un attimo ho temuto che questo codice funzionasse davvero! :-)
Funziona, se ad ogni funzione fai un "return $this"
 
Bye.

 io, programmatore, potrei commettere.
Non intendevo la sintassi, ma proprio il concetto dietro il linguaggio.
Ti faccio un esempio: javascript.
Io lo uso veramente malissimo, perche` lo programmo in modo funzionale e a 
oggetti, mentre invece e` un linguaggio a prototipi.
La OOP di PHP e` diversa da quella di Python, che e` diversa da quella di 
Java, che e` diversa da quella di C++.
Per ogni linguaggio andrebbe usato il sistema giusto, senza cercare di 
fare in PHP quello che stai facendo in Java.
Bye.

 Funziona, se ad ogni funzione fai un "return $this"
Be' certo, ma secondo me non ha molto senso, in un'ottica di logica
relazionale, far ritornare l'oggetto ad un metodo setter. Preferisco
scrivere qualche lettera in più, piuttosto che rompere la logica.


 scrivere qualche lettera in più, piuttosto che rompere la logica.
Perche` per te e` logica relazionale.
Fai conto che non lo sia. Fai conto che solo i getter ritornino qualcosa 
che non e` $this, e che tutto il resto deva tornare $this.
Dimentica anche che esistano getter e setter come li intendi su Java. Usa 
i getter solo per qualcosa che la classe deve calcolare al momento della 
chiamata, non per valori che tu gli inserisci. Usa i setter solo per 
modificare dei default, il resto devono essere variabili public. Le 
variabili private/protected devono essere solo usate dalla classe, non 
devono essere modificabili in nessun modo dall'esterno, nemmeno con setter 
(altrimenti tanto vale che siano pubbliche).
Questo intendevo quando dicevo di cambiare modo di programmare tra PHP e 
Java.
Adesso qualcuno mi saltera` alla gola scandalizzato ("Oh mio dio! Come 
posso vivere senza getter/setter?!? Ti rendi conto dei rischi di 
sicurezza?"), ma io la penso cosi`. Se voglio getter e setter uso Java.
Bye.

 (altrimenti tanto vale che siano pubbliche).
Guarda, per me l'OOP sta al paradigma procedurale come il capitalismo
sta al feudalesimo, e questa tua mi sembra la classica refrattarietà che
esisteva in molti al passaggio dal feudalesimo al capitalismo. :-P
Se PHP tende al C++ in quanto a funzionalità e al Perl in quanto a
flessibilità, IMHO diventa uno dei migliori linguaggi in circolazione.
Sono comunque d'accordo con te nel dire che vivaddio esiste pure Python.


 flessibilità, IMHO diventa uno dei migliori linguaggi in circolazione.
A me invece basterebbero poche aggiunte al linguaggio base (i named 
parameters, per dire, ed eventualmente il subclassing, magari multifile, 
che potrebbe tranquillamente sostituire i namespace). Per il resto il 
linguaggio mi va bene com'e`.
Bye.

 sicurezza?"), ma io la penso cosi`. Se voglio getter e setter uso Java.
E' questione di buona programmazione, non di Java. E soprattutto di
codice universalmente accettato.


 fare in PHP quello che stai facendo in Java.
Java e C++ si somigliano molto. Cambiano fondamentalmente per la
possibilità, data in C++, di poter ancora scrivere codice procedurare,
e l'ereditarietà multipla. Fondamentalmente, poi, sono molto simili.
Tengo a sottolineare comunque che parlare di PHP e Java è comunque
parlare di cose completamente diverse. Java (su WEB) è un'insieme di
tecnlogie, PHP è solo un linguaggio.


 molta confusione. :/
Sì, in parte avevo pensato fosse un errore involontario (lo fanno in
molti), però c'erano anche altre frasi per cui sembrava che tu fossi per
un utilizzo davvero "minimo" dell'OOP: con la tendenza a convergere tra
applicazioni web e desktop, IMHO l'OOP dovrebbe essere esteso al
massimo, perché è il metodo più naturale per rappresentare la realtà.
Programmare in 
ASP.NET
 è già quasi come programmare un app. desktop...


 codice universalmente accettato.
Io non accetto getter e setter, per esempio, quindi non e` universalmente 
accettata.
In Eclipse c'e` addirittura una funzione che ti crea i getter e i setter 
per le proprieta` pubbliche di una classe. Una porcheria, IMHO.
Se ho 50 proprieta` mi crea 100 metodi! Mi incasina la classe, la rende 
meno leggibile, piu` pesante da compilare (ed eventualmente da caricare da 
disco e da tenere in RAM), introduce uno strato di indirezione che 
rallenta il codice. Per cosa? Perche` lo dice la convenzione. Io ci vedo 
solo svantaggi.
Se ho bisogno di controllare uno o piu` di quei valori faccio prima a 
mettere un __set con uno switch dentro, ben commentato.
Oh, sia chiaro che non sono incazzato, tantomeno con te. ;)
Solo che secondo me certe conv(i|e)nzioni sono sbagliate.
Bye.

 Solo che secondo me certe conv(i|e)nzioni sono sbagliate.
Questione di pratica. Non so quanti progetti grandi, sostanzioni che
vengono frequentemente aggiornato hai realizzato. Ma stai sicuro che
più ne realizzerai, più apprezzerai la rigidezza delle implementazioni
dell'OOP di Java e C++.
