5. Funzioni php di base: array Lezioni di web attivo 5. Array in ambiente PHP Gli array in ambiente PHP sono piuttosto diversi dagli array dell’ambiente “C”. In “C” un array è un insieme di elementi fisicamente consecutivi (vettore) i cui gli elementi sono individuati da un indice numerico. Invece in ambiente PHP un array è una struttura associativa detta “mappa” in cui ogni valore contenuto è associato ad una chiave, non è garantita la contiguità degli elementi. Naturalmente si può sempre utilizzare un array PHP come un normale vettore che in fin dei conti è una mappa in cui le chiavi sono i primi N numeri naturali. La conseguenza di questa impostazione è che la posizione di un elemento non è definita a priori e ciò consente la realizzazione di strutture complesse come liste, cataste ed alberi. Una seconda conseguenza è che un array deve sempre essere istanziato (generato) dinamicamente e non staticamente come in “C”. Questa generazione può avvenire in modo esplicito attraverso la funzione array() che possiamo immaginare come il costruttore di un oggetto oppure implicitamente quando una variabile compare a sinistra di una assegnazione da parte di una variabile che restituisce un array. $a=array(“mele”,”pere”,”arance”); $a=array(“primo”=>“mele”,”secondo”=>”pere”,”terzo”=>”arance”); $b=explode(“,”,”mele,pere,arance”); parse_str(“primo=pere&secondo=mele&tezo=banane”,$c); //esplicita //esplicita con chiave //implicita //implicita con chiave Nel primo esempio viene generato un array di tre elementi. Poiché non sono specificate le chiavi i tre elementi sono identificati dagli indici 0,1 e 2. Quindi $a[1] vale “mele” $a[2] vale “pere” e $a[3] vale banane. In un array generato senza chiavi le chiavi assumono ordinatamente i valori 0,1,2 … Nel secondo esempio viene generato un array associativo accessibile come $a[“primo”], $a[“secondo”] e $a[“terzo”]. Nel terzo caso non c’è una dichiarazione di array ma una generazione (senza chiavi) provocata dalla funzione explode che separa i campi usando il separatore virgola. Nel quarto caso la funzione di interpretazione genera un array associativo usando come chiavi i nomi delle variabili e come valori dell’array i valori delle variabili della stringa. Un array può anche essere multidimensionale. Ad esempio: $a=array( array(1,2,3,4), array(5,6,7,8), array(9,10,11,12) ) E’ un array bidimensionale. Quindi ad esempio l’elemento $a[2][0] vale 9. Un array associativo può anche essere usato per realizzare una struttura: $moto=array( array(“marca”=>”Piaggio”,”modello”=>”Vespa”,”cilindrata”=>125), array(“marca”=>”Malaguti”,”modello”=>”Ciack”,”cilindrata”=>100), array(“marca”=>”Ducati”,”modello”=>”Monster”,”cilindrata”=>998), ) Nell’esempio l’elemento $moto[1][“modello”] vale la stringa “Ciack” mentre l’elemento $moto[2][“cilindrata”] vale l’intero 998. Come si vede negli array PHP non esiste la limitazione di elementi tutti dello stesso tipo del linguaggio “C”. ITIS “O.Belluzzi” – Laboratorio di Sistemi 1-8 Lezioni di web attivo 5. Funzioni php di base: Array 5.1 Accesso agli elementi di un array Le dimensioni di un array cambiano dinamicamente quindi per conoscere le sue dimensioni si deve applicare alla variabile la funzione count(). Se l’array è indicizzato si può percorrere con un ciclo for con una tecnica molto simile a quella del “C”. E’ possibile però anche un’altra tecnica basata sul while che si basa sul fatto che accedere ad un elemento di array che non esiste produce un NUL (falso) con un algoritmo simile a quello della lettura di un file sequenziale. Se invece l’array è associativo, sebbene si possa ancora contare la sua dimensione, non ha senso percorrerlo sequenzialmente per indice. Il costrutto foreach consente di percorrere gli array associativi indipendentemente dalla posizione fisica degli elementi. Si deve tenere presente però che in realtà un array è sempre associativo e il caso indicizzato è un caso particolare in cui la conversione in stringa dell’indice numerico fornisce la chiave. Un array può anche essere visto come un file sequenziale con un cursore interno che punta all’elemento corrente. In questa modalità si possono usare le funzioni: reset() porta il cursore all’inizio, current() restituisce l’elemento corrente, next() sposta il cursore avanti, prev() sposta il cursore indietro, end() porta il cursore alla fine , key() restituisce il valore di chiave dell’elemento corrente e each() restituisce un array contenente la coppia chiave/valore dell’elemento corrente. L’esempio seguente che mostra quattro possibili tecniche di accesso sia per un array indicizzato che per un array associativo chiariscono la situazione: Esempio 5.1 <?php //array indicizzato $a=array("mele","pere","banane"); for($i=0;$i<count($a);$i++) { //for echo("\$a[$i]:".$a[$i]); } $i=0; while(isset($a[$i])) { //while echo("\$a[$i]:".$a[$i]); $i++; } foreach($a as $v) { //foreach sui valori echo("\$a[".key($a)."]:$v"); next($a); } foreach($a as $k=>$v) { //foreach sulle chiavi echo("\$a[$k]:$v") } //array associativo $b=array("primo"=>"tortellini","secondo"=>"carne","frutta"=>"mele"); for($i=0;$i<count($b);$i++) { //for echo("\$b[".key($b)."]:".current($b)); next($b); } reset($b); //while $i=0; while(isset($b[key($b)])) { echo("\$b[".key($b)."]:".$b[key($b)]); next($b); } foreach($b as $v) { //foreach sui valore echo("\$b[".key($b)."]:$v"); next($b); } foreach($b as $k=>$v) { //foreach sulle chiavi echo("\$b[$k]:$v"); } 2-8 ITIS “O.Belluzzi” – Laboratorio di Sistemi 5. Funzioni php di base: array Lezioni di web attivo Note: Sono definiti quattro metodi: for, while, foreach sui valori, foreach sulle chiavi Indipendentemente dal tipo di array è possibile usare uno qualsiasi dei quattro metodi Nel caso dell’array indicizzato l’omissione della chiave in creazione ha di fatto generato le chiavi “0”,”1”,”2” mentre nel caso dell’array associativo le chiavi “primo”, “secondo” e “frutta sono esplicitamente specificate Il primo costrutto estrae uno ad uno tutti gli elementi presenti in un array indicizzato sfruttando la conversione automatica da intero a stringa effettuata sulla variabile $i. Quindi scrivere $a[$i] in questo caso è come scrivere ad esempio $a[“1”] mentre $a[“01”] fallirebbe (restituisce false). L’unica differenza rispetto ad un costrutto di tipo “C” è che la dimensione dell’array determinata dalla funzione count() può variare dinamicamente. Il secondo costrutto verifica l’esistenza (isset()) dell’elemento i-esimo dell’array. L’array viene percorso ordinatamente fino all’ultimo elemento esistente. Entrambe queste tecniche sono corrette solo se l’array è effettivamente indicizzato. Ad esempio se ad un array indicizzato da 0 a 9 (dieci elementi) si applica la funzione unset($a[5]) l’elemento di posizione 5 viene rimosso, quindi count($a) restituisce 9 invece che dieci e $a[5] restituisce false invece che un valore di conseguenza entrambe i cicli sbagliano (il primo percorre un elemento in meno mentre il secondo si ferma dopo 4 elementi) Il terzo esempio estrae, uno alla volta, tutti gli elementi esistenti in una variabile scalare di appoggio $v. Per conoscere il valore della chiave viene applicata la funzione key() all’elemento corrente di $a. Poiché la foreach non incrementa il puntatore all’elemento corrente è necessario applicare la funzione next() all’array in modo da spostare il puntatore alla posizione successiva. Anche il terzo esempio estrae i valori uno alla volta in un ciclo foreach ma in questo caso viene estratta anche la corrispondente chiave e non è quindi necessario spostare il puntatore interno per estrarre la chiave. Nel quinto esempio viene effettuato un ciclo numerato basato sulle dimensioni dinamiche di un array associativo. In questo caso non è possibile usare l’indice per estrarre ne la chiave (funzione key()) ne il valore (funzione current()). Il cursore interno deve essere fatto avanzare con una next(). Il quinto esempio è un ciclo while la cui terminazione si basa sul controllo di esistenza dell’elemento corrente dell’array. Poiché foreach non incrementa il cursore interno è necessaria una next() per puntare all’elemento successivo Il sesto e settimo esempio usano la foreach nel più modo naturale per un array associativo. ITIS “O.Belluzzi” – Laboratorio di Sistemi 3-8 Lezioni di web attivo 5. Funzioni php di base: Array 5.2 Operazioni sugli array Le operazioni sugli array sono numerosissime. In questo paragrafo vengono presentate le significative e frequenti: List List assegna valori a delle variabili estraendole da un array indicizzato con indice che parte da 0. List in realtà non è una funzione ma un operatore di linguaggio e questo spiega la sua strana sintassi (compare a destra di un operatore di assegnazione). Si usa quando si vuole estrarre da un array che in realtà implenta una structure i singoli elementi trasformandoli in scalari identificati con il proprio nome. Esempio 5.2 <? $info = array('caffè', 'scuro', 'caffeina'); list($bevanda, $colore, $componente) = $info; echo"Il $bevanda è $colore e la $componente lo rende speciale.\n"; ?> Note: $info è un array indicizzato perché è stato generato senza chiavi (le chiavi diventano automaticamente 0,1 e 2. L’operatore list genera un insieme di variabili scalari che ordinatamente contengono gli elementi dell’array L’esempio on-line è un po’ più elaborato perché l’ingresso dei dati nell’array è effettuato, per renderlo configurabile con una form contenente campi <select>. Lo scopo del campo <select> è di consentire l’inserimento di un insieme predefinito di valori. In questo caso l’inserimento di una terna qualsiasi di valori produrrebbe risultati stravaganti. La convalida client-side garantisce la presenza dei parametri. sort Sort costituisce un insieme di funzioni che, in vari modi (diretto, inverso, per valore, per chiave …) ordinano un array Esempio 5.3 <?php $frutti = array ("limone", "arancia", "banana", "mela"); //stampa l’array non ordinato for($i=0;$i<count($frutti);$i++) { echo("\$frutti[$i]:".$frutti[$i]); } //ordina sort($frutti); //stampa l’array ordinato for($i=0;$i<count($frutti);$i++) { echo("\$frutti[$i]:".$frutti[$i]); } ?> Note: $frutti è un array indicizzato perché è stato generato senza chiavi (le chiavi diventano automaticamente 0,1,2 e 3. L’output per la presentazione viene fatto in entrambi i casi con un ciclo for che percorre gli indici. L’ordinamento ha portato, come è ovvio in questo caso indicizzato, ad un cambiamento delle associazioni tra chiavi e valori ma esistono altre funzioni che mantengono l’associazione tra chiave e valore durante l’ordinamento. 4-8 ITIS “O.Belluzzi” – Laboratorio di Sistemi 5. Funzioni php di base: array Lezioni di web attivo stack Un array può essere visto come una struttura a catasta (pila o stack). Una catasta è una struttura dati formata una base a partire dalla quale si inserisce il primo dato e da una cima in cui si inserisce ogni volta un nuovo dato (se la catasta è vuota la cima coincide con la base) l’estrazione di un dato può avvenire solo dalla cima. L’inserimento di un dato viene chiamto push mentre l’estrazione viene chiamata pop. Buoni esempi concreti di una struttura dati del genere sono una pila di piatti appoggiata su un tavolo e una catasta di tronchi appoggiati sul terreno. pop push cima base Esistono due funzioni di array chiamate appunto array_push() ed array_pop() che operando sulla fine di un array lo fanno comportare come uno stack. Se si vuole invece operare sull’inizio si devono usare le funzioni array_unshift() ed array_shift() dal nome meno intuitivo ma che si comportano come push e pop rispettivamente. Esempio 5.4 <? If(!isset($_POST['submit'])) { $operazione="null"; $valin=""; $valout=""; $stato=""; $stack=array(); } else { $operazione=$_POST['submit']; if (isset($_POST['valin'])) $valin=$_POST['valin']; else $valin=""; if (isset($_POST['valout'])) $valout=$_POST['valout']; else $valout=""; if (isset($_POST['stato'])) $stato=$_POST['stato']; else $stato=""; } if ($stato!="") $stack=explode(",",$stato); else $stack=array(); switch ($operazione) { case "push": $valout=""; if ($valin=="") $valin="null"; array_push($stack,$valin); $stato=implode(",",$stack); break; case "pop": if (count($stack)>0) $valout=array_pop($stack); else $valout="stack vuoto"; $stato=implode(",",$stack); break; case "null": default: $valout=""; $stato=implode(",",$stack); break; } ?> ... <form action="<? echo"$PHP_SELF" ?>" method="POST" > <input type="hidden" name="stato" value="<? echo $stato ?>" > <input name="valout" type="text" id="valout" size="20" value="<? echo $valout <input name="submit" type="submit" value="pop" > ITIS “O.Belluzzi” – Laboratorio di Sistemi 5-8 Lezioni di web attivo 5. Funzioni php di base: Array <input name="valin" type="text" id="valin" size="20"> <input name="submit" type="submit" value="push" > <? $stack=array_reverse($stack,true); foreach($stack as $v) { echo $v } ?> </form> Note: Questo script presuppone di ricevere da una form (che può essere integrata nella pagina stessa mediante la tecnica degli automi) i parametri $submit (con valori “push” e “pop”) e $valin (che può avere un valore qualsiasi). Poiché la vita dell’array è limitata alla esecuzione dello script è necessario trasmettere il contenuto dell’array da una esecuzione alla successiva. In questo esempio è stata usata una tecnica particolarmente semplice: l’intero contenuto dell’array viene imploso in una variabile di stato che viene passata come parametro hidden alla successiva chiamata che a sua volta ri-esplode la stringa in un array. Una tecnica alternativa potrebbe essere il salvataggio in un file oppure l’uso delle variabili di sessione. Entrambi questi argomenti saranno trattati in seguito. L’inserimento può essere sempre fatto (l’array è dinamico quindi l’unico limite sono le risorse di sistema che non sono infinite) cioè si può sempre mettere un piatto sopra alla pila ammesso che non caschi tutto. L’estrazione può essere fatta solo se l’array non è vuoto cioè non si può togliere un piatto dal tavolo se non ci sono piatti. La presentazione dell’array viene fatta alla rovescia usando la funzione reverse_array() per tenere conto che queste funzione operano sulla fine dell’array. fifo Un array può essere visto come una struttura a coda (fila o fifo=First In Firt Out). Una coda è una struttura dati in cui il primo dato inserito è il primo anche ad essere estratto. Diversamente da una catasta che ha un solo punto di inserimento ed estrazione (la cima) una coda ha due punti di operazione: il fondo in cui i dati vengono inseriti e la cima da cui vengono estratti. Un buon esempio di FIFO è la coda ad un ufficio postale. Viene servito sempre il primo utente della fila che dopo il servizio se ne va lasciando il posto all’utente successivo; un utente appena arrivato si mette in fondo alla fila. Estrazione Inserimento Per realizzare una fifo con un array si possono combinare le due funzioni già citate: array_push(): inserisce un dato alla fine dell’array array_shitf(): estrae un dato dall’inizio dell’array Note: Questo script è praticamente identico al precedente. L’unica differenza a parte i nome degli identificatori è nell’operazione di estrazione che avviene dalla cima (array_shift()) e nella presentazione dell’array che avviene in ordine diretto. Non viene effettuata l’inversione dell’array 6-8 ITIS “O.Belluzzi” – Laboratorio di Sistemi 5. Funzioni php di base: array Lezioni di web attivo 5.3 Alcuni casi notevoli In questo paragrafo sono citati alcuni casi notevoli di utilizzo degli array associativi per l’estrazione di dati particolarmente significativi. Tutti gli esempi si basano sull’utilizzo di estensioni di PHP (funzioni) che generano array associativi a partire da strutture dati di altro tipo. pathinfo Questa funzione consente di estrarre da un percorso valido per un filesystem le parti costituenti ( cartella, nomefile ed estensione) ponendoli in un array associativo formato da: dirname (la cartella) filename (il nome comleto di estensione) extension( solo l’estensione) Esempio 5.6 <? $parti=pathinfo($GLOBALS[‘SCRIPT_FILENAME’]); echo”Cartella: ”.$parti["dirname"]."<br>\n"; echo”Nome: ”.$parti["basename"]."<br>\n"; echo”Estensione: ”.$parti["extension"]."<br>\n"; ?> Note: Questo script, mostra le parti del proprio path name assoluto. parse_url Simile alla precedente ma scompone un URL valido nelle sue componenti: scheme (protocollo in genere http ) host (nome host) port (porta di protocollo in genere 80) user (presente solo nelle richieste autenticate) pass (presente solo nelle richieste autenticate) path (percorso del documento) query (eventuali parametriati dopo il ?) fragment (eventuale ancora dentro al documento) Esempio 5.7 <? $url="http://belxxx:***@labsis:80/~belxxx/pagina.php?param=valore#sezione"; $parti=parse_url($url); echo”protocollo: ”.$parti["scheme"]."<br>\n"; echo”host: ”.$parti["host"]."<br>\n"; echo”porta: ”.$parti["port"]."<br>\n"; echo”utente: ”.$parti["user"]."<br>\n"; echo”password: ”.$parti["pass"]."<br>\n"; echo”parametri: ”.$parti["query"]."<br>\n"; echo”ancora: ”.$parti["fragment"]."<br>\n"; ?> Note: L’esempio mostra un url nella sua forma più completa possibile: oltre ai comuni valori di protocollo (http://), nome host (labsis), percorso (/~belxxx/pagina.php) contiene anche i meno comuni valori di utente (belxxx), password (***), porta (80), parametri (?param=valore) e ancora nel documento (#sezione). Se alcune parti non sono inserite l’elemento rimane vuoto. Il nome utente e password servono per fare connessioni autenticate. Ad esempio se il vostro browser supporta il protocollo ftp potete visitare la seguente pagina: ftp://belxxx:****@labsis.scuole.bo.it ottenendo un ftp via web-client. Attenti: se lo fate a scuola ricordatevi di chiudere la sessione: questo url resta nella cache del browser. ITIS “O.Belluzzi” – Laboratorio di Sistemi 7-8 Lezioni di web attivo 5. Funzioni php di base: Array mysql_fetch_assoc Questa funzione fa parte della libreria di accesso alle banche dati non ancora trattata. Viene però riportata come esempio per la sua particolare importanza. Si supponga di avere accesso ad una banca dati che contiene una tabella con informazioni e che si vogliano estrarre tali informazioni. Ad esempio la tabella sia (è un caso reale riferito alla banca dati “fahrenheit451” di labsis): ID_AUT 2 3 … Cognome Calvino Sleator … Nome Italo William … Senza entrare nel dettaglio di come i dati della tabella vengono raggiunti (sarà oggetto di studio in un successivo capitolo) una “connessione” alla banca dati fornisce un metodo di accesso alla tabella (identificato nell’esempio dalla variabile $query). Invocando la funzione mysql_fetch_assoc() con parametro $query si ottiene un array associativo che contiene la prima riga della tabella. Le chiavi di questo array sono i nomi delle colonne. Iterando la richiesta si ottiene la riga successiva fino a che la funzione invece che restituire un array restituisce FALSE che significa che non ci sono più righe (non è nota a priori la lunghezza della tabella. Esempio 5.8 <? $sock= mysql_connect("localhost","nobody",""); mysql_select_db("archivio",$sock); $msg ="SELECT * from Autori”; $query=mysql_query($msg,$sock); while ($riga=mysql_fetch_assoc($query)) { echo($riga[“ID_AUT”]); echo($riga[“Cognome”]); echo($riga[“Nome”]); } ?> Note: Questo script, che presuppone l’esistenza di una banca dati “archivio” su “localhost”, funziona solo se eseguito su labsis. Ulteriori dettagli verrano forniti nel capitolo “Database MySQL” 8-8 ITIS “O.Belluzzi” – Laboratorio di Sistemi