Newsgroup: it.comp.www.php
Titolo: [OOP] Variabile tra diversi oggetti

Sto avvicinandomi alla OOP, ma credo di commettere ancora degli errori
a livello concettuale.
Ho una classe che, mediante un suo metodo, istanzia altre classi in
base a un parametro.
class mainClass {
  var $objs = array();
  var $edit;
  function mainClass($edit) {
    $this->edit = $edit;
  }
  function addObject($name, $type = "textbox") {
    $this->objs[] = $name;
    $className = ($type == "custom") ? $field : strtolower($type);
    // Istanzia la classe apposita
    $this->$field = new $className($field);
  }
  function showObjects() {
    $output = "";
    foreach ($this->fields as $field) {
      $curObj = &$this->$field;  // Restituisce l'oggetto associato al
campo corrente
      $output .= $curObj->show();
    }
    echo($output);
  }
}
Nel metodo show() di ognuno degli oggetti istanziati dinamicamente
voglio conoscere il valore della proprietà $edit dell'oggetto
mainClass (l'output cambierà in base a tale valore). E' possibile
saperlo direttamente senza che il valore sia passato in qualche modo
agli oggetti "incorporati"?

 agli oggetti "incorporati"?
No, non puoi saperlo. Devi passarglielo come parametro:
       $output .= $curObj->show($this->edit);
Ricorda che ogni classe deve essere un mondo a se`, non deve sapere niente
di nessun'altra classe, a meno che non gli venga passata.
Quindi niente globals, niente variabili del chiamante, ecc. Solo variabili
di classe e parametri delle funzioni.
Solo cosi` potrai riutilizzare le classi in altri progetti.
Bye.

 Solo cosi` potrai riutilizzare le classi in altri progetti.
Grazie per la dettagliata spiegazione
Il fatto che ogni classe non debba sapere nulla di un'altra classe mi
spiazza un po'...
Per semplificare molto il discorso, il mio progetto è una sorta di
CMS.
La mia idea era creare una classe principale, che fosse il motore per
la gestione della maggior parte delle funzionalità dell'applicativo,
lasciando a singoli oggetti istanziati dinamicamente la
visualizzazione, il salvataggio e la modifica dei dati.
Cerco di spiegare. Mettiamo che una delle tabelle che il CMS deve
gestire contenga le anagrafiche di alcuni studenti. I  campi della
tabella avranno caratteristiche diverse: ad esempio, nel form di
inserimento di un nuovo studente, i campi "nome" e "cognome" saranno
delle textbox, il campo "sesso" una select, il campo "interrogato" una
checkbox, e così via. Ovviamente il trattamento dei dati cambierà in
base alla natura del campo, e la mia idea era di istanziare una classe
specifica per ogni tipo di campo (es. classe textbox, classe checkbox)
che si occupasse di visualizzare e salvare i dati in modo appropriato
e indipendente. Ciò avverrebbe richiamando dalla classe principale il
metodo delle varie classi dinamiche (ad es. quel $curObj->show() per
la visualizzazione nel form)
Essendo comportamenti assolutamente eterogenei da classe a classe e
potendo prevedere solo una limitata quantità di variabili comuni a
tutte, da qui nasceva la mia esigenza di conoscere arbitrariamente i
valori delle proprietà della classe principale.
Ma a quanto tu mi dici, i problemi sono due: o ho sbagliato
l'ideazione dell'applicativo (che però a me così strutturato sembra
rispondere bene alla concezione di OOP), oppure sbaglio strada
cercando una soluzione al problema

 cercando una soluzione al problema
Non hai sbagliato strada. Solo che sei all'inizio e ti stai scontrando con
un paradigma diverso dal solito. Ci siamo passati tutti. Devi solo trovare
il machete per togliere i rovi. ;)
Bye.

 Solo cosi` potrai riutilizzare le classi in altri progetti.
Sempre che ci riesci.. :-)
Tac
-- 
Using Opera's revolutionary e-mail client: 
http://www.opera.com/mail/

 il machete per togliere i rovi. ;)
Secondo me ha fatto un buon lavoro.


 > }
Innanzitutto grazie a entrambi per le spiegazioni dettagliate ai
limiti del commovente :-)
Sono tutte informazioni che mi torneranno utili nell'approfondire il
discorso sulla OOP, che in alcuni passaggi mi risulta ancora un po'
ostica. Qualunque sia la strada da percorrere, mi sono accorto che
devo prendere confidenza con concetti quali MVC, pattern e singleton.
Ciò che non mi convince, o che almeno non coincide pienamente con ciò
che avevo in mente, è il fatto che nello script di Alessandro
l'istanziamento delle classi per i diversi tipi di campo risponde a
uno switch, il che sottintende una previsione a monte delle varie
tipologie. Il mio script, invece, istanzia le classi in modo
assolutamente dinamico. Ciò permette di aggiungere nuove classi senza
modificare il "motore" del sistema. Ad esempio, un mio collega
potrebbe un domani sviluppare la classe per la checkbox e stop, senza
dover modificare la classe principale. Se non ho capito male è la
stessa obiezione mossa da TAC One. Sembra un dettaglio, ma secondo me
a livello di concezione del progetto è un aspetto importante. Il
rovescio della medaglia è proprio il punto su cui mi sono arenato,
cioè che non posso prevedere un istanziamento "particolare" con il
passaggio di un parametro specifico per una data classe, ma devo per
forza attenermi a un istanziamento "astratto".
Grazie a entrambi per i complimenti, sono un'ottima spinta a
documentarmi ulteriormente.

 Secondo me ha fatto un buon lavoro.
Anche secondo me.
Preciso che non e` detto che il mio sia l'unico sistema, anzi. Potrebbero
anche essercene di migliori, e credo ci siano. Bisogna solo trovarli. :)
Bye.

 documentarmi ulteriormente.
Noi siamo qua per discuterne e confrontare diverse esperienze. La mia
speranza, ogni volta che rispondo a qualcuno sul ng, e` che prima o poi
quello diventi piu` bravo di me e io possa "sfruttarlo" per chiedere aiuto. ;)
Bye.

 forza attenermi a un istanziamento "astratto".
Hai preso in considerazione l'approccio che ho citato io ?
//istanziamento particolare
$text = new Textarea();
$text->isRequired( true );
$text->label = "Note"
$text->stripHtml = false;
$form->addObject( $text );
Ciao


 sapere qualcosa di alcune altre, ma con le limitazioni che dicevo.
Il problema è appunto minimizzare. In genere mi trovo a "portare fuori le  
responsabilità" piu' che spostarle da un'altra, durante il refactoring.
Il che porta appunto all'approccio sul form.
//codice tagliato, esasperazione in progressione e refactoring finale
function addObj( $name, $class ){ switch ... }
function addObj( $name, $class ){ return new $class( $name ) }
che poi porta inevitabilmente a:
function addObj( $name, $class ){
	$obj = new $class( $name ) ;
	if ( $class = 'xxx' ) { /* il cliente ha fatto lo stronzo, customizzo * }
	$this->$name = $class;
}
e infine a:
function addObj( $Class )
{
	$name = $Class->name;
	$this->$name = $Class;
	//metodo normalizzato, la logica di scelta
	//dei campi non rientra nelle responsabilità
	//della classe, quindi avviene all'esterno.
}
Stesso discorso per il singleton (vedi esempio sopra db/xml, che potrebbe  
essere anche
un'altro oggetto db con configurazione differente), la logica di scelta  
del db appartiene
all'applicazione, non all'oggetto form/activerecord/succoallapera. Il  
driver db viene passato come istanza concreta (quindi manipolabile e  
soggetta alle restrizioni e al cloaking degli scope) invece che come  
risultato di una chiamata statica (e di conseguenza globale).
ps: non vorrei sembrare antipatico o invasato, ma se si parla di teoria -  
questa è la mia. Tieni conto che nella libreria per i form che stò  
sviluppando (per la terza volta, visto che sono inetto) la classe che  
gestisce il form è un singleton (cosa abbastanza singolare se vogliamo),  
quindi per quel che mi riguarda la teoria è un conto, la pratica in molti  
casi un altro.


 molti casi un altro.
Onestamente non capisco perche`... :)
Se ti va di spiegarmelo (magari aprendo un nuovo thread per chiarezza) ne
sarei felice.
Grazie.
Bye.

 sarei felice.
Ok, ma te la sei cercata !:. :-)


 Ok, ma te la sei cercata !:. :-)
Va bene, voi avete sconfinato e io sono ancora pieno di dubbi :-) No,
a parte gli scherzi, sono ben contento che il mio quesito iniziale
abbia portato a questo interessante confronto e che siano emersi tanti
concetti che vorrei approfondire personalmente più avanti. Ho letto e
riletto i vostri suggerimenti, ma ancora non ho trovato una soluzione
efficace al mio problema. Ovviamente sono io duro di comprendonio,
quindi vi chiedo ancora un po' di pazienza.
Scusate se ricapitolo tutto dall'inizio. Cerco di astrarre il discorso
il più possibile, tralasciando per il momento alcune nozioni (ad
esempio il modello MVC).
Ho questo mio CMS. Il CMS è costituito da varie pagine, ognuna delle
quali fa riferimento a una tabella del db. Ad es. la  pagina
studenti.php si occupa della gestione delle anagrafiche degli studenti
ed è collegata alla tabella "studenti" del db. La pagina studenti.php
innanzitutto istanzia la classe principale, il motore del CMS. Poi
richiama il metodo per l'aggiunta dei campi, ognuno dei quali sarà
riferito a un campo del db. Quindi qualcosa del tipo
$cms = new cms($table);
$cms->addField("nome", "textbox");
$cms->addField("curriculum", "textarea");
...
Il metodo addField del motore istanzia la classe definita dal "tipo"
di campo (il secondo argomento passato al metodo) assegnandogli il
nome del campo. Quindi qualcosa del genere.
function addField($field, $type) {
  $this->$field = new $type();
}
In questo modo la creazione dell'oggetto di un dato campo avviene in
modo assolutamente "astratto". Non ci sono switch, né controlli sulla
variabile type. Questa è l'idea fondamentale su cui regge il progetto,
che ritengo indispensabile ma che comporta diversi problemi.
Ora provo ad astrarre il discorso ancora di più.
La classe principale è quindi un ambiente molto vasto, che si occupa
di gestire (appoggiandosi su altre classi o su metodi interni) tutta
una serie di funzioni del CMS, dal controllo del login dell'utente al
salvataggio dei dati sul db, e così via. Per ogni campo della tabella
a cui fa riferimento la pagina, l'ambiente istanzia un oggetto del
tipo specificato. Tutti questi oggetti avranno una struttura comune,
in particolare dei metodi comuni (e quindi, se non ho capito male,
potrebbero implementare la stessa interfaccia) che si occuperanno di
diverse operazioni. Tuttavia, essendo di type diversi l'uno dagli
altri, avranno delle differenze nella struttura dei metodi (ad esempio
una textbox visualizzerà il valore associato come semplice testo, una
checkbox lo convertirà in uno stato della relativa casella, ecc.).
Fin qui mi sembra tutto abbastanza lineare. Ogni volta che sorgerà
l'esigenza di un nuovo tipo di campo, basterà sviluppare la relativa
classe che utilizzi i metodi dell'interfaccia in modo appropriato,
*senza intervenire sul motore (la classe principale)*
Ora poniamo che l'ambiente, la classe principale, abbia le seguenti
variabili:
$var1
$var2
$var3
Mettiamo che l'istanziamento astratto dei vari oggetti/campi preveda
il passaggio di una di queste variabili
$this->$field = new $type($this->var1);
Questa variabile basta per le classi textbox, textarea e checkbox. Ma
mettiamo che io debba sviluppare una nuova classe select e che, per la
visualizzazione, essa debba conoscere anche lo stato della variabile
$var2 dell'ambiente. E' qui che nasce il problema! Possibile che il
metodo show() dell'istanza della classe select non possa sapere il
valore che ha in quel momento una variabile dell'ambiente principale
(senza che essa venga passata in qualche modo)?
A me sembra assurdo... mi sembrerebbe una limitazione assurda della
OOP (o almeno di quella di PHP 4).
Fatemi sapere!

 Ok, ma te la sei cercata !:. :-)
Va bene, voi avete sconfinato e io sono ancora pieno di dubbi :-) No,


 OOP (o almeno di quella di PHP 4).
E' il vantaggio della programmazione OOP. I punti di accesso sono ben  
definiti, questo aiuta la manutenzione a lungo termine e a riutilizzare le  
classi.
Quanto alla tua classe puoi sempre fare:
function add( $name, $field )
{
	$this->$name = new $field( $this->var1 );
	$this->$name->setController( $this );
}
class select ()
{
	function __construct( $var )
	{
		$this->var = $var;
	}
	function setController( $controller )
	{
		$this->controller = $controller;
	}
	function output ()
	{
		$var2 = $this->controller->var2;


 }
Quindi, se non ho capito male, passi alla classe select il riferimento
all'oggetto "ambiente". Perfetto, era ciò che avevo pensato di fare.
Ma se tra l'istanziamento di select e la chiamata del metodo output il
valore di $var2 è cambiato, io non avrò un riferimento "aggiornato",
giusto? E questo è un altro problema.
class cms {
$var2 = 1;
function add( $name, $field ) {
  $this->$name = new $field( $this->var1 );
  $this->$name->setController( $this );
}
function show() {
  $this->var2 = 0;  // Cambia il valore di $var2
  per ogni oggetto istanziato... {
    $this->$name->output();  // Richiama il metodo output dei vari
oggetti
  }
}
}
E poi stavo pensando, ma passare il riferimento all'intero "ambiente"
per ogni oggetto campo istanziato non è uno spreco di risorse assurdo?

 per ogni oggetto campo istanziato non è uno spreco di risorse assurdo?
Questa perplessità però rimane

 per ogni oggetto campo istanziato non è uno spreco di risorse assurdo?
Non direi, visto che è un riferimento. Fosse una copia sarebbe un'altra  
questione.
Ma anche così, finchè non noti la differenza va anche bene. Ottimizzare  
troppo presto è la radice di ogni male ('premature optimization is the  
root of all evil').
Si crea qualcosa di funziona (che è quindi già di per se utile) e poi al  
limite si fà un po' di tuninng.
Ciao


 Questa perplessità però rimane
Il reference è un indirizzo di memoria, a rigor di logica (in pratica non  
saprei) non cambia di dimensione se referenzi una variabile di due byte o  
di 1 mega.
