Newsgroup: it.comp.www.php
Titolo: php e oop

Salve,
come da subject vorrei sapere, da chi ne ha fatto uso, se anche in php la
programmazione ad ggetti sia una cosa fattibile. Ho letto in rete che in php
si possono creare classi, ho visto in modo macroscopico gli aspetti tecnici
della questione, al momento mi interessano di più quelli pratici. Usando
questo linguaggio, il php, e questo approccio alla programmazione, oop, si
riesce ad ottimizzare il proprio codice, o le migliorie sono minime da non
giustificare, eventuali, perdite di tempo a scrivere classi o altro?
Inoltre non so se ci sono editor evoluti che permetterebbero di vedere i
metodi di una classe mentre scrivo il codice...insomma, conviene programmare
ad oggetti in php?
Grazie, saluti.
--------------------------------
Inviato via 
http://usenet.libero.it

 programmare ad oggetti in php?
dipende dalla mentalità e dalla "crescita" informatica di una persona.
un guru della programmazione ad oggetti potrebbe trovarsi in crisi a 
scrivere codice procedurale e viceversa.
IMHO, una volta che entri BENE nell'ottica dell'OOP, questa tecnica risulta 
davvero molto comoda e veloce nello sviluppo.
però devi già avere lo schema pronto, o rischi di confonderti solo le idee.
se ti ritieni già molto produttivo nella programmazione "tradizionale", 
forse imparare da zero i concetti dell'OOP non merita, se non in termini di 
"io lo so fare".
ciao
-- 
Punkarruso
mail:punkarruso chiocchiolona despammed punto com
pubblicità progresso:
http://www.gnu.org/philosophy/free-sw.it.html

Forse mi sono spiegato male...non metto in discussione la funzionalità
dell'oop. Non mi chiedevo se programmare ad oggetti fosse meglio o peggio,
almeno non dal punto di vista concettuale. Uso regolarmenti classi ed
oggetti con altri linguaggi. Usare gli oggetti è un approccio che
puntualmente adotto nella stesura del mio codice. Questa mattina ho dato un
occhio alla guida in linea sull'uso degli oggetti e, a parità di codice, in
php non mi sembra che l'uso di oggetti mi agevoli di molto. Una volta che
metto in un file la mia classe con i suoi metodi (funzioni) e proprietà
(variabili dichiarate sempre nella classe) devo scrivere altre funzioni nel
mio script php per vedere le proprietà del mio oggetto, vedernee i metodi e
via decidendo. A questo punto invece che istanziare un oggetto mia_classe,
faccio solo l'include di un file contenente le stesse funzioni che nel mio
oggetto sarebbero metodi e faccio prima. Ho provato a fare un oggetto utente
così strutturato:
UTENTE
 |
 |__AGGIUNGI UTENTE
 |
 |__CANCELLA UTENTE
 |
 |__RETRIVE UTENTE
 |
 |__PROPRIETA UTENTE
           |
           |__CODICE UTENTE
           |
           |__NOME UTENTE
           |
           |__COGNOME UTENTE
           |
           |..
Ho provato a scrivere questa classe e uno pseudo script che la utilizzasse.
Ho avuto quasi l'impressione che avrei fatto molto prima ad avere lo stesso
risultato se avessi usato delle semplice funzioni anche se...di fatto non
era poi così paradossalmente diversa come cosa, a lmeno a livello di codice.
Ovviamente però non avendo mai programmato ad oggetti in php potrei
sbagliarmi. Non sono manco un guro con questo linguaggio e sicuramente lo
conosco molto meno dei linguaggi che invece uso quotidianamente.
Tu ad esempio, usi le calssi nel tuo codice php? Riesci a sfruttare a pieno
la potenzialità delgi oggetti? (Ereditarietà, polimorfismo...) Inoltre,
posso passarmi un oggetto tra una pagina e un altra?
Grazie, saluti...


 altra?
li ho usati e li userò ancora.
io sfrutto al massimo le potenzialità OOP che offre PHP.
forse sono le potenzialità OOP del PHP che non sono abbastanza per quel che 
ne so io sulla OOP, anche se non è che sia scafatissimo in questo tipo di 
programmazione rispetto a quella tradizionale.
avevo già scritto in un threadone sull'oop a suo tempo, proprio sul fatto 
che gli sviluppatori di PHP ci lasciano "sulle spine" senza far trasparire 
se le cose cambieranno pro o contro l'OOP; di certo così com'è adesso, la 
situazione è decisamente troppo ibrida.
ultima: dal PHP 4, gli oggetti sono serializzabili con la funzione 
serialize, in modo da poterli passare tra le pagine proprio come si fa per 
gli array.
ciao
-- 
Punkarruso
mail:punkarruso chiocchiolona despammed punto com
pubblicità progresso:
http://www.gnu.org/philosophy/motivation.it.html

via decidendo. 
Sei sicuro di dover scrivere queste funzioni?
Se hai l'oggetto ben definito, e' sufficiente instanziarlo ed invocare il metodo appropriato.
I benefici della programmazione OOP sono sempre evidenti.
Per esempio:
PHP_Beautifier (
http://www.beautifier.org
)
(serve per colorare i sorgenti di un qualsiasi linguaggio)
E' scritto ad oggetti, e per farlo funzionare basta scrivere 2 righe (fatti i dovuti $include):
$highlighter = new Core(new HFile_php3(), new Output_HTML());
print $highlighter->highlight_text("<? print 'Hello World!'; ?>");
con tre new ed una chiamata ad un metodo hai il risultato.
Devi aggiungere un altro linguaggio? E' sufficente scrivere una classe che estende quella
madre e aggiungere gli attributi che vuoi:
Sfruttando l'ereditarieta' :-)
<?
require_once("$BEAUT_PATH/Beautifier/HFile.php");
class HFile_NUOVOLINGUAGGIO extends HFile{
   function HFile_NUOVOLINGUAGGIO(){ //costruttore
     $this->HFile();	//istanzio la classe madre
     $this->nocase            	= "1"; //nuovi attributi
     $this->notrim            	= "0"; //nuovi attributi
   }
} 
?>
Ora, anche io ho poche conoscenze come te in php, anzi meno delle tue (sono un newbie :-))
ma analizzando e studiando tanto codice proprio per imparare credo che la OOP in php porti tanti vantaggi.
Bisognerebbe sentire chi programma da tanto tempo, e farsi dire da loro se/quanto č diffusa la programmazione
oop in php, forse lo e' poco perche' l'utilizzo che viene fatto del linguaggio ne preclude un uso 
intenso degli oggetti.
ciao!
Morde.
morde [at] programmer [.] net

pear-error inclusa nel pacchetto pear), ecc.
Ecco... questo e' quello che volevamo leggere.... che peccato pero',
pensavo fosse piu' radicato l'oop in php...
Ciao


 ad oggetti in php?
L'utilità della OOP è, secondo me, molto più legata alla qualità ed alla
formazione del progettista o del programmatore piuttosto che all'uso di un
linguaggio specifico.
A difesa delle potenzialità del PHP nella programmazione ad oggetti, posso
portare l'esperienza maturata in un paio di progetti sviluppati nel corso
del 2002 - premetto che non abbia usato prima dell'inizio dell'anno scorso
il PHP professionalmente, sebbene sviluppi software per lavoro già da alcuni
anni.
Nel corso del 2002 ho avuto l'occasione di affrontare due progetti di
commercio elettronico che furono sviluppati in PHP per ragioni commerciali
(è una delle piattaforme più diffuse presso i providers).
In entrambi i casi era necessaria una netta separazione fra l'aspetto delle
pagine web e il codice dell'applicazione.
Abbiamo sviluppato un framework basato sul paradigma
Modello-Vista-Controllo (MVC).
Lo strato di presentazione (vista) responsabile dell'aspetto delle pagine
web viene fornito dagli utenti del nostro prodotto, tramite lo sviluppo di
templates con un sistema da noi sviluppato. I templates sono scritti in
una versione estesa dell'HTML, ma vengono compilati in un formato intermedio
dal sistema; alle richieste successive, se non i files dei templates non
sono stati modificati, verrà usata la versione già compilata.
Lo strato di controllo è costituito dal codice delle singole pagine, il
dispatch al codice da eseguire è dinamico -per così dire, "ad eventi"- in
base alle azioni da eseguire specificate nei templates stessi. Lo strato di
controllo implementa la logica dell'applicazione e fa da colla tra lo strato
Modello e quello Vista.
Il dominio dell'applicazione (gli oggetti trattati dalla stessa) sono
implementati nello strato Modello. In generale, questi oggetti non
implementano alcuna funzione di visualizzazione. E' stato inoltre costruito
un sistema per mappare gli oggetti su un database relazionale, il mapper O/R
è sufficientemente flessibile da poter "materializzare" gli oggetti non
dalle sole tabelle ma da ogni tipo di relazione (in altre parole, può
costruire oggetti anche da join su più tabelle). Il mapper O/R include un
cache che evita di ricaricare dal database i dati degli oggetti già presenti
in memoria, se non sono stati modificati.
Faccio un piccolo esempio per chiarire le idee: un catalogo di prodotti,
suddivisi in più categorie. E' possibile aggiungere, modificare o cancellare
sia i prodotti che le categorie.
Partiamo dal dominio del problema, definiamo gli oggetti base della tematica
che stiamo trattando.
------------------------------ 8< ------------------------------ da Catalogo.php
class Prodotto extends Persistent {
    # Persistent è la classe base per gli oggetti che possono essere
    # letti e scritti da un database.
 
    # Riepilogo qui gli attributi dei Prodotti, ciò non è necessario né
    # utile al ns. framework, ma è comodo come documentazione.
    var $ProdottoID;
    var $CategoriaID; // codice della categoria di appartenenza
    var $Descrizione;
    var $_PrezzoEuro; // il prezzo in Euro
    # Gli attributi ed i metodi il cui nome inizia per underscore (_) non sono
    # accessibile dal sistema dei templates.
 
    function Categoria()
      # Categoria() -> oggetto Categoria
      #   La categoria a cui appartiene questo Prodotto
    {
	global $Database;
	# $Database è un singleton che viene costruito dal framework,
	# in base alle impostazioni presenti in un file di configurazione
	# dell'applicazione.
	return $Database->sqlFetch('Categoria', # nome della classe
				   'CategoriaID = ' . $this->CategoriaID
				   # criterio (WHERE di SQL)
				   );
    }
 
    function PrezzoEuro()
      # PrezzoEuro() -> stringa
      #   Il prezzo del prodotto in Euro, nel formato "1.234,56"
    {
	return number_format($this->_PrezzoEuro,2,",",".");
    }
 
    function PrezzoLire()
      # PrezzoLire() -> stringa
      #   Il prezzo del prodotto in Lire, nel formato "1.234.567"
    {
	return number_format($this->_PrezzoEuro / 1936.27,0,".",",");
    }
 
    function urlPaginaProdotto()
      # urlPaginaProdotto -> stringa
      #   URL della pagina del prodotto, lo inserisco per comodità qui
      #   anche se sarebbe più corretto implementarlo nello strato di
      #   Controllo. Il framework permette di farlo, ma richiede codice più
      #   complesso che complicherebbe inutilmente questo semplice esempio.
    {
        return "prodotto.php?ProdottoID=" . $this->ProdottoID;
    }
}
# La definizione della tabella del database, il framework genera automaticamente
# il codice per il backend prescelto. Questa definizione viene inoltre utilizzata
# per effettuare le dovute conversioni durante la lettura e la scrittura dei dati.
$tblProdotto = new TableDef('Prodotto', # nome della classe
			    'Prodotti'  # nome della tabella nel database
			    );
$tblProdotto->addField('ProdottoID', # nome del campo
		       IntegerField(), # tipo del campo,
		       false, # NOT NULL
		       true  # (parte della) chiave primaria
		       );
$tblProdotto->addField('CategoriaID', IntegerField());
$tblProdotto->addIndex(array('CategoriaID'));
$tblProdotto->addField('Descrizione', VarcharField(255));
$tblProdotto->addField('_PrezzoEuro', MoneyField());
class Categoria extends Persistent {
    var $CategoriaID;
    var $Descrizione;
 
    function Prodotti()
      # Prodotti() -> lista di oggetti Prodotto
      #   I prodotti appartenenti a questa categoria
    {
	global $Database;
	return $Database->sqlCollection('Prodotti', # nome della classe
					'CategoriaID = ' . $this->CategoriaID,
					'ProdottoID DESC' # ordine (ORDER BY di sql)
					);
    }
 
    function urlPaginaCategoria()
      # urlPaginaCategoria() -> string
    {
        return "categoria.php?CategoriaID=" . $this->CategoriaID;
    }
}
$tblCategoria = new TableDef('Categoria','Categorie');
$tblCategoria->addField('CategoriaID', IntegerField(), false, true);
$tblCategoria->addField('Descrizione', VarcharField(255));
class Catalogo {
      function Categorie()
        # Categorie() -> lista di oggetti Categoria
      {
          global $Database;
	  return $Database->sqlCollection('Categoria',
	                                  null, # nessun criterio di ricerca
					  'CategoriaID DESC');
      }
}
------------------------------ 8< ------------------------------
Lo strato di controllo implementa la logica dell'applicazione, l'esempio
completo comprenderebbe tre files:
 - index.php: lista delle categoria
 - categoria.php: pagina della categoria con relativa lista dei prodotti
 - prodotto.php: pagina del prodotto
------------------------------ 8< ------------------------------ index.php
class IndexPage extends Page {
      function render($messaggio=false)
        # mostra il catalogo, se $messaggio viene specificato verrà
	# visualizzato all'utente
      {
          global $Database;
	  $catalogo = new Catalogo;
	  $tpl = new HTMLTemplate('index.tpl');
	  if($messaggio !== false) {
	      $ctx = array('Messaggio' => $messaggio);
	      $tpl->push($messaggio);
	  }
	  $tpl->push($catalogo);
	  $tpl->render();
      }
      function default_action()
      {
          $this->render();
      }
 
      function aggiungiCategoria_action()
      {
          global $Database;
 
	  $descrizione = trim($_REQUEST['Descrizione']);
	  if($descrizione == '') {
	      $this->render('Descrizione non specificata');
	  } else {
	      $categoria = new Categoria;
	      $categoria->Descrizione = $descrizione;
	      $categoria->_insert();
 
	      header('Location: ' . $categoria->urlPaginaCategoria());
	  }
      }
}
$pt = new IndexPage;
$pt->publish();
------------------------------ 8< ------------------------------
------------------------------ 8< ------------------------------ categoria.php
class CategoriaPage extends Page {
      var $categoria;
      function before_dispatch()
      {
          global $Database;
 
	  if(!is_set($_REQUEST['CategoriaID'])) {
	    header('Location: index.php');
	    exit();
	  }
 
	  $categoriaID = intval($_REQUEST['CategoriaID']);
	  $this->categoria = $Database->sqlFetch('Categoria',
	                     'CategoriaID = ' . $categoriaID);      
      }
      function render($messaggio=false)
        # mostra il catalogo, se $messaggio viene specificato verrà
	# visualizzato all'utente
      {
          global $Database;
 
	  $tpl = new HTMLTemplate('categoria.tpl');
	  if($messaggio !== false) {
	      $ctx = array('Messaggio' => $messaggio);
	      $tpl->push($messaggio);
	  }
	  $tpl->push($this->categoria);
	  $tpl->render();
      }
      function default_action()
      {
          $this->render();
      }
 
      function modificaCategoria_action()
      {
          $descrizione = trim($_REQUEST['Descrizione']);
	  if($descrizione == '') {
  	      $this->render('Descrizione non specificata');
	  } else {
	      $this->categoria->Descrizione = $descrizione;
	      $this->categoria->_update();
	      $this->render('Categoria modificata');
	  }
      }
 
      function cancellaCategoria_action()
      {
          $this->categoria->_delete();
	  header('Location: index.php');
      }
}
------------------------------ 8< ------------------------------
Tralascio prodotto.php, che è del tutto simile ai file precedenti.
Passiamo ai templates (strato Vista), le pagine web sono generate dagli
oggetti HTMLTemplate che leggono file costruiti in un linguaggio apposito,
costituito dall'HTML più alcuni attributi simil-XML che si possono apporre
sui tags.
Ad esempio il file index.tpl potrebbe essere così:
------------------------------ 8< ------------------------------ index.tpl
...
<UL pt:list="Categorie">
  <LI>
    <A HREF="#" pt:attrs="href: urlPaginaCategoria"
                pt:value="Descrizione">...</A>		
  </LI>
</UL>
...
------------------------------ 8< ------------------------------
Il sistema di template funziona come uno stack - come i blocchi ({}) annidati
in php - al livello più elevato l'oggetto corrente del template è l'oggetto
Catalogo (si veda il codice che costruisce il template in index.php).
Il comando pt:list costruisce un ciclo (come un foreach del php) sugli
oggetti dell'attributo 'Categorie' - il nome viene risolto cercando negli
oggetti presenti nello stack, in questo caso viene trovato il metodo
Categorie() definito nell'oggetto Catalogo. (Gli attributi possono essere
sia metodi che proprietà/variabili degli oggetti)
In pratica, il contenuto del tag <UL> verrà ripetuto per ogni oggetto
Categoria presente nella lista restituita dal metodo Categorie()
dell'oggetto Catalogo. Ad ogni invocazione, l'oggetto Categoria selezionato
verrà messo in cima allo stack.
Il comando pt:attrs="href: urlPaginaCategoria" fa sì che il valore parametro
HREF del tag <A> venga sostituito con il valore dell'attributo
"urlPaginaCategoria" - che verrà cercato nello stack, sarà selezionato il
metodo omonimo nell'oggetto Categoria (inseritovi dal comando precedente).
Il comando pt:value fa si che il contenuto del tag <A> venga sostituito con
il valore dell'attributo "Descrizione" - sarà la proprietà omonima
dell'oggetto Categoria.
Il sistema di template comprende anche altri comandi (pt:if, pt:remove,
pt:attrs-if, pt:in) ed una sintassi più complessa per gli attributi (è
possibile specificare la classe di appartenenza, i parametri da passare nel
caso siano dei metodi).
Attualmente questo framework è privato, tuttavia l'azienda per cui lavoro
potrebbe renderlo disponibile come software libero (open source) se ci fosse
sufficiente interesse.
In definitiva, il PHP offre buone funzionalità per la programmazione OOP.
Ci sono tuttavia alcuni problemi ed alcuni "pitfall" contro cui ci siamo
scontrati:
 - la mancanza delle eccezioni rende la gestione degli errori alquanto
   macchinosa. Le funzionalità del Zend Engine v1 in quest'ambito sono
   equivalenti a quelle del Visual Basic - e questo non è un complimento.
 - le capacità di metaprogrammazione e di "reflection" del PHP sono
   tutto sommato buone, anche se potrebbero essere ulteriormente migliorate.
   In particolare, non potendo definire metaclassi e non potendo trattare
   come oggetti veri e propri i metodi e gli attributi degli oggetti,
   costruire alcune parti del framework (mapper O/R, NameResolver del
   sistema dei templates e dispatcher dinamico nella classe Page) si sono
   rivelate più complicate delle previsioni iniziali.
 
 - la semantica di copia-su-assegnazione del PHP e il modo in cui funzionano
   i reference sono eccessivamente complicati, capire come funzionano e
   quando usarli richiede molto tempo.
 
Per fortuna il Zend Engine v2 dovrebbe correggere tutti questi punti.
Personalmente non credo che riuscirò mai ad essere produttivo in PHP quanto
lo sono in altri linguaggi OOP (Smalltalk, Python/Zope) e non (Erlang, ad
esempio) - ma comunque, nel panorama degli strumenti più utilizzati per il
web development, è posizionato molto meglio di altri sotto il punto di vista
della produttività.
-- 
Roberto Lupi