Cos'è PHP
A metà degli anni Novanta il Web era ancora formato in gran parte da pagine statiche, cioè da documenti HTML il cui contenuto non poteva cambiare fino a quando qualcuno non interveniva manualmente a modificarlo. Con l'evoluzione di Internet, però, si cominciò a sentire l'esigenza di rendere dinamici i contenuti, cioè di far sì che la stessa pagina fosse in grado di proporre contenuti diversi, personalizzati in base alle preferenze degli utenti, oppure estratti da una base di dati (database) in continua evoluzione.
PHP nasce nel 1994, ad opera di Rasmus Lerdorf, come una serie di macro la cui funzione era quella di facilitare ai programmatori l'amministrazione delle homepage personali: da qui trae origine il suo nome, che allora significava appunto Personal Home Page. In seguito, queste macro furono riscritte ed ampliate fino a comprendere un pacchetto chiamato Form Interpreter (PHP/FI).
Essendo un progetto di tipo open source (cioè "codice aperto", quindi disponibile e modificabile da tutti), ben presto si formò una ricca comunità di sviluppatori che portò alla creazione di PHP 3: la versione del linguaggio che diede il via alla crescita esponenziale della sua popolarità. Tale popolarità era dovuta anche alla forte integrazione di PHP con il Web server Apache (il più diffuso in rete), e con il database MySQL. Tale combinazione di prodotti, integralmente ispirata alla filosofia del free software, diventò ben presto vincente in un mondo in continua evoluzione come quello di Internet.
Alla fine del 1998 erano circa 250.000 i server Web che supportavano PHP: un anno dopo superavano il milione. I 2 milioni furono toccati in aprile del 2000, e alla fine dello stesso anno erano addirittura 4.800.000. Il 2000 è stato sicuramente l'anno di maggiore crescita del PHP, coincisa anche con il rilascio della versione 4, con un nuovo motore (Zend) molto più veloce del precedente ed una lunga serie di nuove funzioni, fra cui quelle importantissime per la gestione delle sessioni. La crescita di PHP, nonostante sia rimasta bloccata fra luglio e ottobre del 2001, è poi proseguita toccando quota 7.300.000 server alla fine del 2001, per superare i 10 milioni alla fine del 2002, quando è stata rilasciata la versione 4.3.0. La continua evoluzione dei linguaggi di programmazione concorrenti e l'incremento notevole dell'utilizzo del linguaggio anche in applicazioni enterprise ha portato la Zend a sviluppare una nuova versione del motore per supportare una struttura ad oggetti molto più rigida e potente.
Nasce così PHP 5, che si propone come innovazione nell'ambito dello sviluppo web open source soprattutto grazie agli strumenti di supporto professionali forniti con la distribuzione standard ed al grande sforzo di Zend che, grazie alla partnership con IBM, sta cercando di spingere sul mercato soluzioni di supporto enterprise a questo ottimo linguaggio. Lo sviluppo di PHP procede comunque con due progetti paralleli che supportano ed evolvono sia la versione 4 che la versione 5. Questa scelta è stata fatta poichè tuttora sono pochi i fornitori di hosting che hanno deciso di fare il porting dei propri server alla nuova versione del linguaggio.
Oggi PHP è conosciuto come PHP: Hypertext Preprocessor, ed è un linguaggio completo di scripting, sofisticato e flessibile, che può girare praticamente su qualsiasi server Web, su qualsiasi sistema operativo (Windows o Unix/Linux, ma anche Mac, AS/400, Novell, OS/2 e altri), e consente di interagire praticamente con qualsiasi tipo di database (SQLite, MySQL, PostgreSQL, SQL Server, Oracle, SyBase, Access e altri). Si può utilizzare per i più svariati tipi di progetti, dalla semplice home page dinamica fino al grande portale o al sito di e-commerce
La programmazione web: lato client e lato server
Parlando di PHP e di altri linguaggi di scripting può capitare di sentir
citare le espressioni "lato client" e "lato server": per chi non è esperto della
materia, tali definizioni possono suonare un po' misteriose. Proviamo a chiarire
questi concetti: vediamo come funziona, in maniera estremamente semplificata, la
richiesta di una pagina Web. L'utente apre il suo browser e digita un indirizzo
Internet, ad esempio www.nostrosito.it/pagina1.html
: a questo punto
il browser si collega al server www.nostrosito.it
e gli chiede la
pagina pagina1.html
. Tale pagina contiene esclusivamente codice
HTML: il server la prende e la spedisce al browser, così com'è (insieme ad
eventuali file allegati, ad esempio immagini). Il nostro utente quindi avrà la
possibilità di visualizzare questa pagina.
Supponiamo ora che l'utente richieda invece la pagina
pagina2.php
:
questa, contrariamente a quella di prima, non contiene solo codice HTML,
ma anche PHP. In questo caso il server, prima di spedire la pagina,
esegue il codice PHP, che in genere produce altro codice HTML: ad esempio, PHP
potrebbe controllare che ore sono e generare un messaggio di questo tipo: "Buon
pomeriggio, sono le 17.10!" oppure: "Ehi, che ci fai alzato alle 4 del
mattino?". Dopo l'esecuzione, la pagina non conterrà più codice PHP, ma solo
HTML. A questo punto è pronta per essere spedita al browser. (Ovviamente, il
file che non contiene più codice PHP non è quello "originale", ma la "copia" che
viene spedita al browser. L'originale rimane disponibile per le prossime
richieste.) Quindi l'utente vede solo il codice HTML, e non ha accesso al codice
PHP che ha generato la pagina.
Per comprendere ancora meglio questo concetto, confrontiamo PHP con un altro linguaggio di scripting molto diffuso sul Web, cioè JavaScript, che di solito viene usato come linguaggio "lato client": JavaScript infatti viene eseguito non dal server, ma dal browser dell'utente (il client, appunto). JavaScript ci consente di eseguire operazioni che riguardano il sistema dell'utente, come ad esempio aprire una nuova finestra del browser, o controllare la compilazione di un modulo segnalando eventuali errori prima che i dati vengano spediti al server. Ci permette anche di avere un'interazione con l'utente: ad esempio, possiamo far sì che quando il mouse passa su una determinata immagine, tale immagine si modifichi.
Per svolgere tutti questi compiti, JavaScript deve essere eseguito sul sistema dell'utente: per questo il codice JavaScript viene spedito al browser insieme al codice HTML. Quindi l'utente ha la possibilità di visualizzarlo, contrariamente a ciò che accade con PHP. Abbiamo citato alcune utili funzioni svolte da JavaScript sul browser dell'utente: PHP, essendo eseguito sul server, non è in grado di svolgere direttamente queste funzioni. Ma attenzione: questo non significa che non sia in grado ugualmente di controllarle! Infatti PHP svolge principalmente la funzione di 'creare' il codice della pagina che viene spedita all'utente: di conseguenza, così come può creare codice HTML, allo stesso modo può creare codice JavaScript. Questo significa che PHP ci può permettere, ad esempio, di decidere se ad un utente dobbiamo spedire il codice JavaScript che apre una nuova finestra, oppure no. In pratica, quindi, lavorando sul lato server abbiamo il controllo anche del lato client. Rimane un ultimo dettaglio da svelare: come fa il server a sapere quando una pagina contiene codice PHP che deve essere eseguito prima dell'invio al browser? Semplice: si basa sull'estensione delle pagine richieste.
Nell'esempio che abbiamo visto prima, pagina1 aveva l'estensione
.html
,
mentre pagina2 aveva l'estensione .php
: sulla base di questo, il
server sa che nel secondo caso deve eseguire PHP, mentre nel primo può spedire
il file così com'è. In realtà il server deve essere istruito per poter fare ciò:
generalmente gli si dice di eseguire PHP per le pagine che hanno estensione
.php
. È possibile comunque assegnargli qualsiasi altra estensione
(fino a qualche anno fa veniva utilizzata phtml
, anche se ormai la
pratica è caduta in disuso). Si possono utilizzare anche le estensioni standard
.htm
e
.html
, ma ciò significherebbe chiamare PHP per
tutte le pagine richieste, anche se non contengono codice PHP: questo
rallenterebbe inutilmente il lavoro del server e dunque è meglio evitarlo.
Caratteristiche e vantaggi di PHP
A fronte di quello detto precedentemente va precisato che PHP non è l'unico linguaggio lato server disponibile per chi si appresta a sviluppare pagine web. Sono disponibili varie alternative, sia proprietarie che open source, ed ognuna di queste ha i suoi pregi ed i suoi difetti. Dato che il paragone tra due linguaggi di programmazione di buon livello è spesso soggettivo, in questa sede preferisco descrivere in modo semplice le caratteristiche di PHP ed i vantaggi che queste possono portare allo sviluppatore, lasciando a voi l'eventuale compito di confrontarlo con altri strumenti.
La versione di PHP su cui si basa questa guida (la 5.1.2) implementa soluzioni avanzate che permettono un controllo completo sulle operazioni che possono essere svolte dal nostro server web. L'accesso ai cookie ed alle sessioni è molto semplice ed intuitivo, avvenendo attraverso semplici variabili (vedi paragrafo relativo) che possono essere accedute da qualunque posizione all'interno del codice.
PHP ha una lunga storia legata esclusivamente al web, e per questo motivo esistono moltissime librerie testate e complete per svolgere i compiti più diversi: abbiamo strumenti per la gestione delle template, librerie che permettono la gestione completa di un mail server, sia in invio che in ricezione e molto altro ancora. A supporto di tutto questo bisogna dire che il modulo per eseguire script PHP è ormai installato di default sui server di hosting, e che la comunità di sviluppatori risolve molto velocemente i bug che si presentano agli utenti.
A supporto di PHP, sia Zend che la comunità php.net, hanno associato una serie di strumenti molto utili:
Il repository PEAR (http://pear.php.net) che contiene decine di classi ben organizzate e documentate per svolgere la maggior parte delle operazioni ad alto e basso livello richieste durante lo sviluppo di applicazioni web. Tra queste ricordiamo il layer di astrazione per l'accesso ai database, le classi per il debugging ed il logging, quelle per la generazione di grafici avanzati e quelle per la gestione delle template.
Il repository PECL (http://pecl.php.net/packages.php) che contiene molte estensioni native che estendono le potenzialità del linguaggio con funzionalità di basso livello ad alte prestazioni. Abbiamo sistemi di cache ed ottimizzazione del codice intermedio generato durante l'esecuzione di script PHP, sistemi per il debugging avanzato ed il profiling del codice e molto altro.
Il template engine Smarty (http://smarty.php.net) , uno dei più robusti ed utilizzati template engine per PHP in circolazione.
A tutto questo va aggiunto che la funzione di Zend con IBM sta portando allo sviluppo di strumenti di supporto professionali per gli sviluppatori, quali Zend Studio 5.0, Zend Safe Guard ed altri strumenti che coprono perfettamente tutto il processo di sviluppo e mantenimento del software.
Non è tutto rose e fiori purtroppo: per esempio il fatto che PHP venga distribuito in due versioni differenti (tuttora la 4 e la 5) limita gli sviluppatori nell'utilizzo delle caratteristiche della nuova versione, dato che la maggior parte dei servizi di hosting continuano ad aggiornare quella precedente. Oltretutto il fatto che PHP funzioni ad estensioni non è sempre un vantaggio, dato che spesso e volentieri i vari servizi di hosting hanno configurazioni differenti. Un'altra lacuna, che obbliga gli sviluppatori a sviluppare codice specifico per raggirarla, è la mancanza del supporto per caratteri Unicode che rende più complicato lo sviluppo di applicazioni multilingua per paesi che accettano caratteri speciali all'interno delle loro parole. Fortunatamente la versione 6 di PHP (che è tutt'ora in sviluppo) includerà nativamente questo supporto.
Insomma: PHP è un ottimo linguaggio, leader tra quelli open source per lo sviluppo web, molto semplice da imparare e subito produttivo. Oltretutto ha una serie di strumenti di appoggio molto completi e con la versione 5 un robusto supporto per la programmazione ad oggetti. Anche se con qualche difetto, penso sia la scelta più adeguata per un gran numero di situazioni.
PHP è un linguaggio la cui funzione fondamentale è quella di produrre codice HTML, che è quello dal quale sono formate le pagine web. Ma, poichè PHP è un linguaggio di programmazione, abbiamo la possibilità di analizzare diverse situazioni (l'input degli utenti, i dati contenuti in un database) e di decidere, di conseguenza, di produrre codice HTML condizionato ai risultati dell'elaborazione. Questo è, in parole povere, il Web dinamico. Come abbiamo visto precedentemente, quando il server riceve una richiesta per una pagina PHP, la fa analizzare dall'interprete del linguaggio, il quale restituisce un file contenente solo il codice che deve essere inviato al browser (in linea di massima HTML, ma può esserci anche codice JavaScript, fogli di stile CSS o qualunque altro contenuto fruibile da un browser, come immagini e documenti Pdf).
PHP e l'HTML
Detto questo, come come avviene la produzione di codice HTML? La prima cosa da sapere è come fa l'interprete PHP a discernere quale porzione di un file contiene codice da elaborare e quale codice da restituire solamente all'utente. Questa fase di riconoscimento è molto importante, dato che permette a PHP di essere incluso all'interno di normale codice HTML in modo da renderne dinamica la creazione. Il codice PHP deve essere compreso fra appositi tag di apertura e di chiusura, che sono i seguenti:
<?php //tag di apertura
?> //tag di chiusura
Tutto ciò che è contenuto fra questi tag deve corrispondere alle regole
sintattiche del PHP, ed è codice che sarà eseguito dall'interprete e non sarà
inviato direttamente al browser al browser. Per generare l'output da inviare al
browser attraverso codice PHP viene normalmente utilizzato il costrutto
echo
. Vediamo un semplice esempio, composto da codice HTML e codice PHP
(il codice PHP è evidenziato in rosso):
<html> <head> <title> <?php echo "Pagina di prova PHP"; ?> </title> </head> <body> <?php echo "Buona giornata!"; ?> </body> </html>
Questo banalissimo codice produrrà un file HTML il cui contenuto sarà semplicemente:
<html>
<head>
<title>
Pagina di prova PHP
</title>
</head>
<body>
Buona giornata!
</body>
</html>
E quindi l'utente vedrà sul suo browser la riga "Buona giornata!". È
opportuno ricordare che il dato da inviare al browser che segue il comando
echo
può essere racchiuso tra parentesi e che al comando possono essere
date in input più stringhe (questo è il nome che viene dato ad una ripetizione
di qualunque carattere compreso tra due apici singoli (' ') o doppi (" ")),
separate da virgole, così:
echo "Buongiorno a tutti!", "<br />\n", "È una bellissima giornata";
Se si decide di utilizzare il separatore virgola, non possono essere
utilizzate le parentesi. Nel prosieguo del corso useremo spesso il verbo
'stampare' riferito alle azioni prodotte dal comando
echo
o da
istruzioni con funzionalità analoghe (quali print
,
sprintf
e altro): ricordiamoci però che si tratta di una convenzione, perchè in questo
caso la 'stampa' non avviene su carta, ma sull'input che verrà inviato al
browser!
Facciamo caso ad un dettaglio: nelle istruzioni in cui stampavamo "Buongiorno
a tutti", abbiamo inserito, dopo il <br />
, il simbolo \n
.
Questo simbolo ha una funzione abbastanza importante nella programmazione e
nello scripting che serve più che altro per dare leggibilità al codice HTML che
stiamo producendo. Infatti PHP, quando trova questa combinazione di caratteri
fra virgolette, li trasforma in un carattere di ritorno a capo:
questo ci permette di controllare l'impaginazione del nostro codice HTML.
Bisogna però stare molto attenti a non confondere il codice HTML con il layout
della pagina che l'utente visualizzerà sul browser: infatti, sul browser è solo
il tag <br />
che forza il testo ad andare a capo.
Quando questo tag non c'è, il browser allinea tutto il testo proseguendo sulla stessa linea (almeno fino a quando gli altri elementi della pagina e le dimensioni della finestra non gli "consigliano" di fare diversamente), anche se il codice HTML ha un ritorno a capo.
Vediamo di chiarire questo concetto con un paio di esempi:
<?php
echo "prima riga\n";
echo "seconda riga<br />";
echo "terza riga"; ?>
Questo codice php produrrà il seguente codice HTML:
prima riga
seconda riga<br />terza riga
mentre l'utente, sul browser, leggerà:
prima riga seconda riga
terza riga
Questo perchè il codice PHP, mettendo il codice 'newline' dopo il testo 'prima riga', fa sì che il codice HTML venga formato con un ritorno a capo dopo tale testo. Il file ricevuto dal browser quindi andrà a capo proprio lì. Il browser, però, non trovando un tag che gli indichi di andare a capo, affiancherà la frase 'prima riga' alla frase 'seconda riga', limitandosi a mettere uno spazio fra le due. Successivamente accade l'esatto contrario: PHP produce un codice HTML nel quale il testo 'seconda riga' è seguito dal tag <br />, ma non dal codice 'newline'. Per questo, nel file HTML, 'seconda riga<br />' e 'terza riga' vengono attaccati. Il browser, però, quando trova il tag <br /> porta il testo a capo.
Avrete forse notato che in fondo ad ogni istruzione PHP abbiamo messo un punto e virgola; infatti la sintassi del PHP prevede che il punto e virgola debba obbligatoriamente chiudere ogni istruzione. Ricordiamoci quindi di metterlo sempre, con qualche eccezione che vedremo più avanti. Da quanto abbiamo detto finora emerge una realtà molto importante: chi vuole avvicinarsi al PHP deve già avere una conoscenza approfondita di HTML e di tutto quanto può far parte di una pagina web.
Questo perchè lo scopo principale di PHP è proprio la produzione di questi codici.
La struttura sintattica del linguaggio
Nel paragrafo precedente abbiamo visto che PHP necessita di una coppia di tag per l'apertura e la chiusura del codice contenuto in un file richiesto da un Web Server. Si tratta dei tag
<?php
.....
?>
Abbiamo però la possibilità di usare anche alcune sintassi alternative, che
sono comunque sconsigliate per permettere una corretta distribuzione e
portabilità dei propri progetti. In primo luogo, in script scritti in versioni
precedenti di PHP, potremmo trovare il classico tag
<script>
con
specificato esplicitamente il linguaggio PHP:
<script language="php">
.......
</script>
Un'altra possibilità è quella di usare i
tag brevi
, che devono
essere abilitati manualmente modificando le impostazioni del file di
configurazione php.ini
:
<?
....
?>
Ricordiamoci tuttavia che in PHP 5 la configurazione standard disabilita i tag brevi. Un'ultima possibilità è quella di usare i tag in "stile ASP":
<%
....
%>
Anche questi però devono essere abilitati in
php.ini
e sono
praticamente inutilizzati dalla maggior parte dei programmatori. Tutta questa
varietà di sintassi è causata dalla volontà degli sviluppatori di mantenere
la retrocompatibilità con le vecchie versioni che, a causa di
scelte differenti di design, permettevano l'utilizzo di tag alternativi. È bene
ricordare che rimane buona pratica utilizzare i tag completi evitando se
possibile i tag brevi ed escludendo le altre possibilità.
Per chi non ci avesse fatto caso, puntualizzo un concetto molto importante: i tag delimitano il codice PHP, ed il codice contenuto al loro interno non sarà inviato al browser, ma compilato e eseguito. Da questo potremmo dedurre che tutto ciò che sta fuori da questi tag non verrà toccato da PHP, che si limiterà a passarlo al browser così com'è, eventualmente ripetendolo in base a situazioni particolari che vederemo in seguito. In linea di massima è bene ricordare che scrivere:
<?php echo "<strong>"; ?> prova</strong>
e:
<strong>prova</strong>
(o qualsiasi altra combinazione) restituisce lo stesso risultato.
I commenti
Un altro argomento molto importante legato alla sintassi di PHP sono i commenti. Chi ha esperienza, anche minima, di programmazione, sa bene che molte volte i commenti si rivelano di importanza decisiva quando si tratta di mettere le mani su un programma realizzato da qualcun altro, e anche quando il programma è stato scritto da noi stessi, soprattutto se è passato qualche tempo dalla realizzazione. I commenti svolgono un ruolo fondamentale in questa fase di "rivisitazione" del codice, in quanto possono facilitare di molto la comprensione di passaggi apparentemente oscuri.
È bene quindi non risparmiare mai un commento quando possibile (senza comunque esagerare altrimenti, al posto di chiarire il codice lo renderete ancora più illeggibile), anche perchè il loro utilizzo non appesantisce l'esecuzione dello script (l'interprete PHP salta tutte le parti che riconosce come commenti), nè il trasferimento della pagina al browser (infatti i commenti, essendo contenuti all'interno del codice PHP, fanno parte di ciò che non viene inviato al browser).
Abbiamo tre diverse possibilità per posizionare i commenti all'interno del nostro codice: la prima è l'uso dei commenti in stile C++, caratterizzati da due barre:
<?php // Commento in stile C++ ?>
La seconda sono i commenti in stile Perl e Python, contraddistinti dall'uso del cancelletto (anche se ormai obsoleti e poco utilizzati):
<?php
# Commento in stile Perl
# e python
?>
Entrambi questi tipi di commenti sono limitati ad una sola riga: l'interprete PHP, quando trova le barre o il cancelletto, salta tutto ciò che si trova da quel punto fino al termine della riga. Questo ci permette di porre il commento anche sulla stessa riga del codice commentato, così:
<?php
echo 'Buongiorno a tutti <br />';
//stampo un messaggio di saluto
print 'Esclusi quelli antipatici';
# faccio una precisazione
// Questa riga contiene solo commento
?>
L'ultimo tipo di commento che abbiamo a disposizione permette di specificare commenti multilinea senza dover ripetere i caratteri ogni nuova riga grazie ad una coppia di caratteri utilizzati per l'apertura e la chiusura. Tutto il codice che segue /* viene considerato commento da PHP finchè non incontra la serie di caratteri */. Un semplice esempio:
<?php
/*
Questo è un commento
multiriga specificando
utilizzando la stessa sintassi
usata in Java e C
*/
echo /* commento */ "Ciao a tutti"
/* i commenti vengono saltati*/;
?>
Riguardo i commenti multilinea, è importante ricordare che non possono essere innestati e che comunque rappresentano un separatore per l'interprete PHP. Per questo motivo le seguenti sintassi sono errate:
<?php
/*
Commento /*
multilinea
*/
Qui verrà generato un errore ...
*/
ec/* questa sintassi è errata */ho "prova";
?>
La scelta di quale tipo di commento utilizzare è solitamente soggettiva, anche se spesso vengono utilizzati i commenti multiriga per documentare il codice e quelli a riga singola per aggiungergli dei semplici appunti sul funzionamento logico.
Le variabili
Le variabili sono alcuni dei componenti fondamentali di qualsiasi linguaggio di programmazione, in quanto ci consentono di trattare i dati del nostro programma senza sapere a priori quale sarà il loro valore. Possiamo immaginare una variabile come una specie di contenitore all'interno del quale viene conservato il valore che ci interessa, e che può cambiare di volta in volta.
In PHP possiamo scegliere il nome delle variabili usando lettere, numeri ed il trattino di sottolineatura, o underscore (_). Il primo carattere del nome deve essere però una lettera o un underscore (non un numero). Dobbiamo inoltre ricordarci che il nome delle variabili è sensibile all'uso delle maiuscole e delle minuscole: di conseguenza, se scriviamo due volte un nome di variabile usando le maiuscole in maniera differente, per PHP si tratterà di due variabili distinte! Nello script PHP il nome delle variabili è preceduto dal simbolo del dollaro ($). PHP ha una caratteristica che lo rende molto più flessibile rispetto ad altri linguaggi di programmazione: non richiede, infatti, che le variabili vengano dichiarate prima del loro uso. Possiamo quindi permetterci di riferirci ad una variabile direttamente con la sua valorizzazione:
<?php
$a = 5;
?>
Questo semplicissimo codice definisce la variabile 'a', assegnandole il valore 5. In fondo all'istruzione abbiamo il punto e virgola, che, come già accennato in precedenza, deve chiudere tutte le istruzioni PHP. L'utilità di una variabile diventa fondamentale nel momento in cui è possibile utilizzarla all'interno di espressioni matematiche o logiche. Vediamo un semplice esempio:
<?php
$a = 9;
$b = 4;
$c = $a * $b;
echo "Il risultato dell'operazione (9 * 4) è : $c";
?>
Con questo codice abbiamo valorizzato tre variabili: 'a', alla quale stavolta abbiamo dato il valore 9; 'b', a cui abbiamo assegnato il valore 4; e infine 'c', alla quale abbiamo detto che dovrà assumere il valore del prodotto di 'a' e 'b'. Infine abbiamo stampato il risultato ottenuto. Evidentemente, dopo l'esecuzione del codice 'c' varrà 36.
Negli esempi sopra abbiamo visto l'inizializzazione delle variabili, termine che sta ad indicare la prima volta in cui assegniamo un valore ad una variabile. In realtà, possiamo riferirci ad una variabile anche senza che sia stata inizializzata, anche se questa risulta un'operazione sconsigliata e potrebbe generare errori durante l'esecuzione in base ad alcune direttive di configurazione di PHP che vedremo più avanti. Ad esempio, supponendo che nel nostro script non sia stata valorizzata nessuna variabile 'z', potremmo avere un'istruzione di questo genere:
<?php echo $z; ?>
Questo codice non produrrà alcun output, in quanto la variabile 'z' non
esiste. Gli errori generati quando si cerca di utilizzare in lettura una
variabile non inizializzata sono di tipo E_NOTICE
: sono gli errori
di livello più basso, cioè meno gravi, che normalmente non vengono mostrati da
PHP, ma che possiamo abilitare attraverso il file di configurazione
php.ini
. Un errore di questo genere in effetti non compromette il buon
funzionamento dello script, che infatti viene eseguito regolarmente; però
potrebbe essere ugualmente indice di un qualche errore commesso da chi ha
scritto il codice. Vi faccio un esempio per chiarire meglio quanto esposto:
<?php
$a = 74;
$b = 29;
$risultato = $a + $b;
echo $risulato;
?>
Questo codice vorrebbe assegnare i valori 74 e 29 a due variabili, poi sommarli e infine stampare il risultato. Però contiene un errore: nell'istruzione di stampa abbiamo indicato la variabile '$risulato' invece che '$risultato'. Chi ha scritto il codice si aspetterebbe di vedere comparire sul browser il risultato 103, invece non troverà proprio nulla, perchè la variabile '$risulato' non è definita, e quindi non ha nessun valore.
A questo punto, il nostro ignaro programmatore potrebbe anche perdere molto tempo alla ricerca del problema (in realtà questo vi sembrerà un problema banalissimo, ed in effetti lo è; però ricordiamoci che un caso del genere potrebbe presentarsi in un contesto molto più complesso, ed inoltre molto spesso un errore semplice come questo si dimostra molto più difficile da scovare per chi lo ha commesso). Qui però la segnalazione di errore di PHP può venirci in aiuto: infatti, se siamo abituati ad utilizzare le variabili nella maniera più corretta, cioè dopo averle inizializzate, un errore come questo ci indica chiaramente che abbiamo sbagliato a scrivere il nome. Per questo il nostro consiglio è quello di tenere abilitata la visualizzazione degli errori anche di tipo E_NOTICE, e di utilizzare le variabili solo se inizializzate o dopo aver controllato la loro esistenza (vedere nel file PHP.INI che siano presenti le seguenti direttive: display_errors = On e error_reporting = E_ALL).
I tipi di dato
Una variabile può contenere diversi tipi di valori, ognuno dei quali ha un comportamento ed un'utilità differente. Analizzeremo brevemente i tipi di dato che PHP permette di utilizzare all'interno del proprio codice premettendo che PHP, a differenza di altri linguaggi, associa il tipo di dato al valore e non alla variabile (ad esempio possiamo assegnare alla stessa variabile una stringa e poi un numero senza incorrere in alcun errore) ed effettua conversioni automatiche dei valori nel momento in cui siano richiesti tipi di dato differenti (ad esempio in un'espressione).
I tipi di dato boolean servono per indicare i valori vero o falso all'interno di espressioni logiche. Il tipo booleano è associato alle variabili che contengono il risultato di un'espressione booleana oppure i valori true e false. Vediamo un rapido esempio:
<?php $vero = true; $falso = false; ?>
Un numero intero, positivo o negativo, il cui valore massimo (assoluto) può variare in base al sistema operativo su cui gira PHP, ma che generalmente si può considerare, per ricordarlo facilmente, di circa 2 miliardi (2 elevato alla 31esima potenza).
<?php $int1 = 129; $int2 = -715; $int3 = 5 * 8; //$int3 vale 40 ?>
Un numero decimale (a volte citato come "double" o "real"). Attenzione: per indicare i decimali non si usa la virgola, ma il punto. Anche in questo caso la dimensione massima dipende dalla piattaforma. Normalmente comunque si considera un massimo di circa 1.8e308 con una precisione di 14 cifre decimali. Si possono utilizzare le seguenti sintassi:
<?php $vm1 = 4.153; // 4,153 $vm2 = 3.2e5; // 3,2 * 10^5, cioè 320.000 $vm3 = 4E-8; // 4 * 10^-8, cioè 4/100.000.000 = 0,00000004 ?>
Una stringa è un qualsiasi insieme di caratteri, senza limitazione normalmente contenuto all'interno di una coppia di apici doppi o apici singoli. Le stringhe delimitate da apici sono la forma più semplice, consigliata quando all'interno della stringa non vi sono variabili di cui vogliamo ricavare il valore:
<?php
$frase = 'Anna disse: "Ciao a tutti!" ma nessuno rispose';
echo $frase;
?>
Questo codice stamperà la frase: 'Anna disse: "Ciao a tutti!" ma nessuno rispose'. Gli apici doppi ci consentono di usare le stringhe in una maniera più sofisticata, in quanto, se all'interno della stringa delimitata da virgolette PHP riconosce un nome di variabile, lo sostituisce con il valore della variabile stessa.
<?php
$nome = 'Anna';
echo "$nome è simpatica... a pochi<BR>"; // stampa: Anna è
simpatica... a pochi
echo "{$nome} è simpatica a pochi<BR>"; //
stampa identica a sopra
echo '$nome è simpatica... a pochi<BR>'; // stampa: $nome è
simpatica... a pochi
?>
Ci sono un paio di regole molto importanti da ricordare quando si usano le stringhe delimitate da apici o virgolette: siccome può capitare che una stringa debba contenere a sua volta un apice o un paio di virgolette, abbiamo bisogno di un sistema per far capire a PHP che quel carattere fa parte della stringa e non è il suo delimitatore. In questo caso si usa il cosiddetto 'carattere di escape', cioè la barra rovesciata (backslash: \). Vediamo alcuni esempi:
<?php
echo 'Torniamo un\'altra volta'; //stampa: Torniamo
un'altra volta
echo "Torniamo un'altra volta"; //stampa: Torniamo
un'altra volta
echo "Torniamo un\'altra volta"; //stampa: Torniamo
un\'altra volta
echo 'Torniamo un'altra volta'; /*causa un errore */
echo 'Anna disse "Ciao" e se ne andò'; /*stampa: Anna
disse "Ciao" e se ne andò*/
echo "Anna disse \"Ciao\" e se ne andò"; /*stampa: Anna
disse "Ciao" e se ne andò*/
echo 'Anna disse \"Ciao\" e se ne andò'; /*stampa: Anna
disse \"Ciao\" e se ne andò*/
echo "Anna disse "Ciao" e se ne andò"; //errore
?>
Da questi esempi si può capire che il backslash deve essere utilizzato come carattere di escape quando vogliamo includere nella stringa lo stesso tipo di carattere che la delimita; se mettiamo un backslash davanti ad un apice doppio in una stringa delimitata da apici singoli (o viceversa), anche il backslash entrerà a far parte della stringa stessa, come si vede nel terzo e nel settimo esempio. Il backslash viene usato anche come 'escape di sè stesso', nei casi in cui vogliamo esplicitamente includerlo nella stringa:
<?php
echo "Questo: \"\\\" è un backslash"; /*stampa: Questo:
"\" è un backslash*/
echo 'Questo: \'\\\' è un backslash'; /*stampa:
Questo: '\' è un backslash*/
echo "Questo: '\' è un backslash"; /*stampa: Questo:
'\' è un backslash*/
echo "Questo: '\\' è un backslash"; /*stampa: Questo:
'\' è un backslash*/
?>
Analizziamo il primo esempio: il primo backslash fa l'escape del primo paio di virgolette; il secondo backslash fa l'escape del terzo, che quindi viene incluso nella stringa; il quarto fa l'escape del secondo paio di virgolette. Il secondo esempio equivale al primo, con l'uso degli apici al posto delle virgolette. Negli ultimi due casi non è necessario fare l'escape del backslash, in quanto il backslash che vogliamo stampare non può essere scambiato per un carattere di escape (infatti vicino ad esso ci sono degli apici, che in una stringa delimitata da virgolette non hanno bisogno di escape). Di conseguenza, fare o non fare l'escape del backslash in questa situazione è la stessa cosa, e difatti i due esempi forniscono lo stesso risultato.
Passiamo ad esaminare l'ultimo modo di rappresentare le stringhe: la sintassi
heredoc, poco utilizzata se non in situazioni nelle quali è necessario
specificare stringhe molto lunghe. Questa ci consente di delimitare una stringa
con i caratteri <<<
seguiti da un identificatore (in genere si usa EOD
,
ma è solo una convenzione: è possibile utilizzare qualsiasi stringa composta di
caratteri alfanumerici e underscore, di cui il primo carattere deve essere non
numerico: la stessa regola dei nomi di variabile). Tutto ciò che segue questo
delimitatore viene considerato parte della stringa, fino a quando non viene
ripetuto l'identificatore seguito da un punto e virgola.
Attenzione: l'identificatore
di chiusura deve occupare una riga a sè stante, deve iniziare a colonna 1 e non
deve contenere nessun altro carattere (nemmeno spazi vuoti) dopo il punto e
virgola.
<?php $nome = "Paolo"; $stringa = <<<EOD Il mio nome è $nome e il suo nome è sconosciuto EOD; echo $stringa; ?>
Questo codice stamperà 'Il mio nome è Paolo e il suo nome è sconosciuto'. Infatti la sintassi heredoc risolve i nomi di variabile così come le virgolette. Rispetto a queste ultime, con questa sintassi abbiamo il vantaggio di poter includere delle virgolette nella stringa senza far uso dell'escape:
<?php $frase = "ciao a tutti"; $stringa = <<<EOD Il mio saluto è "$frase" EOD; echo $stringa; ?>
In questo caso stamperemo 'Il mio saluto è "ciao a tutti"'.
Possiamo considerare un array come una variabile complessa, che contiene una serie di valori, ciascuno dei quali caratterizzato da una chiave, o indice che lo identifica univocamente. Facciamo un primo esempio, definendo un array composto di cinque valori:
$colori = array('bianco', 'nero', 'giallo', 'verde', 'rosso');
A questo punto ciascuno dei nostri cinque colori è caratterizzato da un indice numerico, che PHP assegna automaticamente a partire da 0. Per recuperare un determinato valore dalla variabile che contiene l'array, è sufficiente specificare il suo indice all'interno di parentesi quadre dietro al nome della variabile:
echo $colori[1]; //stampa 'nero'
echo $colori[4]; //stampa 'rosso'
Gli array verranno trattati in modo più approfondito nella prossima lezione.
Le classi e gli oggetti sono due degli argomenti sui quali gli sviluppatori di PHP hanno voluto puntare maggiormente nella nuova versione. L'argomento verrà trattato in modo approfondito nella Guida Teorica a PHP.
Gli operatori
Gli operatori sono un altro degli elementi di base di qualsiasi linguaggio di programmazione, in quanto ci consentono non solo di effettuare le tradizionali operazioni aritmetiche, ma più in generale di manipolare il contenuto delle nostre variabili. Il più classico e conosciuto degli operatori è quello di assegnazione:
Operatore di assegnazione
$nome = 'Giorgio';
Il simbolo '=' serve infatti ad assegnare alla variabile $nome il valore 'Giorgio'. In generale, possiamo dire che con l'operatore di assegnazione prendiamo ciò che sta alla destra del segno '=' ed assegnamo lo stesso valore a ciò che sta a sinistra. Potremmo ad esempio assegnare ad una variabile il valore di un'altra variabile:
$a = 5; $b = $a;
Con la prima istruzione assegnamo ad $a il valore 5, con la seconda assegnamo a $b lo stesso valore di $a.
Altri operatori molto facili da comprendere sono quelli che permettono di effettuare operazioni aritmetiche sui dati: addizione, sottrazione, divisione, moltiplicazione, modulo.
Operazioni aritmetiche
$a = 3 + 7; //addizione
$b = 5 - 2; //sottrazione
$c = 9 * 6; //moltiplicazione
$d = 8 / 2; //divisione
$e = 7 % 4; /*modulo (il modulo è il resto della
divisione, quindi in questo caso 3)*/
Uno degli operatori più utilizzati è quello che serve per concatenare le stringhe: il punto.
$nome = 'pippo';
$stringa1 = 'ciao ' . $nome; //$stringa1 vale 'ciao
pippo'
Con l'operatore di assegnazione si può anche usare una variabile per effettuare un calcolo il cui risultato deve essere assegnato alla variabile stessa. Ad esempio, supponiamo di avere una variabile di cui vogliamo aumentare il valore:
$a = $a + 10; //il valore di $a aumenta di 10
Con questa istruzione, viene eseguito il calcolo che sta alla destra del segno '=' ed il risultato viene memorizzato nella variabile indicata a sinistra. Quindi è chiaro che il valore di tale variabile prima dell'istruzione viene utilizzato per il calcolo, ma dopo che l'istruzione è stata eseguita questo valore è cambiato. Un risultato di questo tipo si può ottenere anche con gli operatori di assegnazione combinati, che ci permettono di rendere il codice più compatto:
Operazioni di calcolo
$x += 4; //incrementa $x di 4
(equivale a $x = $x + 4)
$x -= 3; //decrementa $x di 3 (equivale a $x = $x - 3)
$x .= $a; /*il valore della stringa $a viene
concatenato a $x (equivale a $x = $x . $a)*/
$x /= 5; //equivale a $x = $x / 5
$x *= 4; //equivale a $x = $x * 4
$x %= 2; //equivale a $x = $x % 2
In questo modo diciamo a PHP che vogliamo assegnare alla variabile specificata a sinistra il risultato dell'operazione che si trova prima del simbolo uguale applicandola alla variabile stessa ed al valore specificato a destra. Più facile a farsi che a dirsi.
Nel caso fosse necessario incrementare e decrementare una variabile di una sola unità, ci vengono incontro gli operatori di incremento e decremento:
Incremento e decremento
$a++; ++$a; //incrementa di 1
$a--; --$a; //decrementa di 1
La differenza tra anteporre e posporre l'operatore di incremento o decremento è fondamentale nel momento in cui si utilizzando questi operatori all'interno di espressioni. Vi basti sapere che anteporre l'operatore alla variabile dice al compilatore di incrementare la variabile e successivamente utilizzare il suo valore all'interno dell'espressione, mentre posporre l'operatore informa il compilatore che dovrà utilizzare nell'espressione il valore attuale e successivamente applicarvi l'incremento o il decremento.
Gli operatori di confronto sono fondamentali perchè ci permettono, effettuando dei confronti fra valori, di prendere delle decisioni, cioè di far svolgere al nostro script determinate operazioni invece di altre. Quando utilizziamo gli operatori di confronto, confrontiamo i due valori posti a sinistra e a destra dell'operatore stesso. Il risultato di questa operazione sarà, ogni volta un valore booleano (true o false). Questi operatori sono:
Operazioni di confronto
== : uguale
!= : diverso
=== : identico (cioè uguale e dello stesso tipo: ad esempio per due variabili
di tipo intero)
> : maggiore
>= : maggiore o uguale
< : minore
<= : minore o uguale
Vediamo alcuni esempi:
//assegnamo valori a tre variabili
$a = 7; $b = 7.0; $c = 4;
//Confrontiamo i valori
$a == $b; //vero
$a == $c; //falso
$a === $b; //falso, perchè $a è intero mentre $b è
float
$a > $c; //vero
$c >= $a; //falso, $c è minore di $a
$a < $b; //falso, hanno lo stesso valore
$c <= $b; //vero
Una piccola osservazione sul terzo confronto: siccome abbiamo assegnato il valore di $b usando la notazione col punto decimale, per PHP $b è una variabile del tipo in virgola mobile, anche se in realtà il suo valore è intero. Per questo il confronto di identità restituisce falso.
Fino a qui abbiamo visto comunque casi molto semplici perchè tutte le variabili avevano valori numerici. Gli stessi confronti però si possono fare anche con altri tipi di variabili, ed in particolare con le stringhe. In questo caso il confronto viene fatto basandosi sull'ordine alfabetico dei caratteri: vale a dire che vengono considerati 'minori' i caratteri che 'vengono prima' nell'ordine alfabetico. Quindi 'a' è minore di 'b', 'b' è minore di 'c', eccetera. Inoltre tutte le lettere minuscole sono 'maggiori' delle lettere maiuscole, e tutte, maiuscole e minuscole, sono 'maggiori' delle cifre da 0 a 9:
$a = 'Mario'; $b = 'Giorgio'; $c = 'Giovanni'; $d = 'antonio';
$e = '4 gatti';
$a < $b; //falso, la 'G' precede la 'M'
$b < $c; //vero, la 'r' ('Gior') precede la 'v' ('Giov')
$d > $a; /*vero, la 'a' minuscola è 'maggiore' di
qualsiasi lettera maiuscola*/
$c > $e; //vero, ogni lettera è 'maggiore' di qualsiasi
cifra
Dato che PHP è un linguaggio con una tipizzazione debole permette di confrontare tra loro variabili contenenti tipi di dato differenti cercando di trasformare le variabili in valori confrontabili. Se per esempio effettuassimo un confronto (==) tra una variabile contenente l'intero uno (1) ed una contenente la stringa uno (1) otterremmo un valore di verità dato che PHP trasformerebbe entrambi i valori in numeri in modo che siano confrontabili. Per assegnare questo valore numerico, PHP controlla se all'inizio della stringa ci sono dei numeri: se ne trova, considererà tutti i numeri che trova inizialmente come il valore numerico di quella stringa. Se non ne trova, il valore della stringa sarà 0:
$a = 7; $b = 5; $c='molte persone'; $d='7 persone'; $e='5';
$a == $d; //vero, $d vale 7
$a === $d; /*falso, valgono entrambi 7 ma $a è un
intero mentre $d è una stringa*/
$b > $c; //vero, $b vale 5 mentre $c vale 0
$e > $c; /*falso: questo è un confronto fra due
stringhe, quindi valgono le regole viste prima*/
Prestiamo attenzione all'ultimo esempio: il valore di $e era stato assegnato usando gli apici, e questo fa sì che PHP lo consideri una stringa anche se il contenuto è un numero.
Il confronto fra un numero e una stringa può avvenire in maniera voluta, ma è più probabile che avvenga per caso, quando cioè una variabile che pensavamo contenesse un numero contiene in realtà una stringa. È evidente che in questo caso potremo facilmente ottenere un risultato diverso da quello che ci aspettavamo, o, viceversa, potremmo ottenere casualmente il risultato atteso: in quest'ultima situazione è possibile che risultati inaspettati arrivino più avanti nello script, se utilizzeremo di nuovo la stessa variabile.
In tutte queste situazioni, tener presente il modo in cui PHP tratta questi confronti può essere di aiuto per spiegarci comportamenti apparentemente bizzarri del nostro script. È comunque buona norma assicurarsi che due espressioni restituiscano risultati dello stesso tipo quando si effettuano confronti, oppure utilizzare gli operatori === e !== che tengono conto anche del tipo di dato utilizzato.
Con gli operatori logici possiamo combinare più valori booleani, oppure negarne uno (nel caso di NOT). Questi valori sono:
or: valuta se almeno uno dei due operatori è vero; si può indicare con 'Or' oppure '||'
and: valuta se entrambi gli operatori sono veri; si indica con 'And' o '&&'
xor: viene chiamato anche 'or esclusivo', e valuta se uno solo dei due operatori è vero: l'altro deve essere falso; si indica con 'Xor'
not: vale come negazione e si usa con un solo operatore: in pratica è vero quando l'operatore è falso, e viceversa; si indica con '!'
Anche in questa occasione vediamo qualche esempio:
10 > 8 And 7 < 6; /*falso, perchè la
prima condizione è vera ma la seconda è falsa*/
10 > 8 Or 7 < 6; //vero
9 > 5 And 5 == 5; //vero: entrambe le condizioni sono
vere
9 > 5 Xor 5 == 5; /*falso: solo una delle due deve
essere vera perchè si verifichi lo 'Xor'*/
4 < 3 || 7 > 9; //falso: nessuna delle due condizioni è
vera
6 == 6 && 1 > 4; //falso: solo la prima condizione è
vera
Per quanto riguarda gli operatori 'and' e 'or', le due diverse notazioni differiscono per il livello di precedenza in caso di espressioni complesse. Infatti, siccome è possibile combinare molti operatori in espressioni anche assai complicate, è necessario sapere con quale ordine PHP valuta i diversi operatori. Queste regole ricalcano le regole algebriche in base alle quali moltiplicazioni e divisioni hanno la precedenza su addizioni e sottrazioni, ma sono più complesse perchè devono considerare anche gli altri operatori. Vediamo quindi qual è l'ordine di priorità dei diversi operatori, iniziando da quelli che hanno la priorità maggiore:
Operatori di incremento e decremento (++ --)
Moltiplicazione, divisione, modulo (* / %)
Addizione e sottrazione (+ -)
Operatori di confronto per minore e maggiore (< <= => >)
Operatori di confronto per uguaglianza e disuguaglianza (== === !=)
Operatore logico 'and', nella notazione col simbolo (&&)
Operatore logico 'or', nella notazione col simbolo (||)
Operatori di assegnazione, compresi quelli 'sintetici' (= += -= /= *= %= .=)
Operatore logico 'and', nella notazione letterale (And)
Operatore logico 'xor' (Xor)
Operatore logico 'or', nella notazione letterale (Or)
Abbiamo già visto prima, in occasione degli esempi sugli operatori logici, l'applicazione di questi principi di precedenza: infatti in tutte quelle espressioni venivano valutati prima gli operatori di confronto e, solo dopo, quelli logici. Un'altra classica rappresentazione di esempio è quella dell'espressione algebrica:
5 + 4 * 2; /*questa espressione vale
13 e non 18,
perchè la moltiplicazione viene eseguita prima*/
(5 + 4) * 2; /*questa invece vale 18,
perchè le parentesi modificano l'ordine di esecuzione*/
Come abbiamo visto, così come avviene in algebra, usando le parentesi possiamo determinare a nostro piacere quali operatori devono essere valutati per primi. Per questo motivo, sebbene sia possibile imparare a memoria l'ordine di precedenza che abbiamo visto poco fa, il nostro consiglio è quello di non tenerne conto, e di utilizzare sempre le parentesi quando abbiamo bisogno di costruire un'espressione un po' complessa: in questo modo ridurremo il rischio di errori, e soprattutto renderemo il nostro codice molto più leggibile. Infatti leggere un'espressione regolata dalle parentesi è molto più immediato che non doversi ricordare quali degli operatori hanno la precedenza sugli altri.
Le espressioni
Dopo questa breve introduzione sugli operatori, possiamo definire un'espressione come una qualsiasi combinazione di funzioni (v. lezioni successive), valori e operatori che si risolvono in un valore. Nel caso visto prima, l'espressione 7+3 ha come valore 10.
In generale, in PHP, qualsiasi cosa utilizzabile come un valore può essere considerata un'espressione. Vediamo alcuni rapidi esempi:
15 * 3; //espressione il cui valore è
45
'Giacomo' . ' Verdi'; //espressione il cui valore è
'Giacomo Verdi'
$a + $b; /*espressione il cui valore è dato dalla somma
dei valori delle variabili $a e $b*/
Come possiamo vedere, quindi, la presenza di operatori fa sì che il valore dell'espressione risulti diverso da quello dei singoli valori che fanno parte dell'espressione stessa. Vediamo un caso particolare, quello dell'operatore di assegnazione:
$a = 6; //il valore di questa espressione è 6
Quando usiamo una espressione per assegnare un valore ad una variabile, il valore che tale espressione assume è uguale a quello che si trova a destra dell'operatore di assegnazione (che è anche quello che viene assegnato all'operatore di sinistra). Questo significa che noi possiamo scrivere
<?php
echo 'Paolo'; //stampa 'Paolo';
echo ($nome = 'Paolo'); //stampa sempre 'Paolo';
?>
Le due espressioni hanno infatti lo stesso valore, cioè 'Paolo'. Quindi con le due istruzioni viste sopra otteniamo sul browser lo stesso risultato. La differenza, ovviamente, è che con la seconda, oltre a stampare il valore a video, abbiamo anche assegnato lo stesso valore alla variabile $nome.
Vediamo qualche altro esempio:
7 > 4; //valore dell'espressione:
true (vero)
$a = 7 > 4; /*valore dell'espressione: lo stesso di
prima; la variabile $a assume il valore true*/
$b = 5 * 4; //valore dell'espressione: 20; viene
assegnato a $b
Precedentemente avevamo accennato ad una differenza nella valutazione dell'espressione fra i diversi modi di utilizzare gli operatori di incremento e di decremento. Vediamo ora di approfondire questo concetto:
$a = 10; $b = 10;
++$a; //incrementiamo $a, che diventa 11; l'espressione
vale 11
$b++; //anche $b diventa 11; qui però l'espressione
vale 10
La differenza è questa: se usiamo l'operatore di incremento (o di decremento) prima della variabile, l'espressione assume il nuovo valore della variabile stessa. Se invece lo mettiamo dopo, l'espressione prenderà il valore che la variabile aveva prima dell'operazione. Di conseguenza:
$a = 5; $b = 5;
echo ++$a; //$a diventa 6, e viene stampato '6'
echo $b++; //anche $b diventa 6, ma viene stampato '5'
echo ++$b; //a questo punto $b è diventato 7, e viene
stampato '7'
Istruzione If
Con le strutture di controllo andiamo ad analizzare un altro degli aspetti fondamentali della programmazione: la possibilità cioè di eseguire operazioni diverse, ed eventualmente di eseguirle più volte, in base alla valutazione di determinate condizioni. In questa lezione esamineremo le istruzioni che ci permettono di eseguire o non eseguire certe porzioni di codice.
La principale di queste istruzioni è la if
, la cui sintassi più
elementare è la seguente:
if( <condizione> ) {
<codice>
}
Dopo l'if
, deve essere indicata fra parentesi un'espressione da
valutare (condizione). Questa espressione verrà valutata in senso booleano, cioè
il suo valore sarà considerato vero o falso. Nel caso in cui l'espressione non
abbia un valore booleano, PHP convertirà comunque questo valore in booleano
utilizzando precise regole che vedremo tra qualche riga. Dunque, se la
condizione è vera, l'istruzione successiva viene eseguita. In caso contrario,
viene ignorata. Potremmo anche avere la necessità di eseguire, nel caso in cui
la condizione sia vera, non una sola ma più istruzioni. Questo è perfettamente
possibile, ma dobbiamo ricordarci di comprendere questo blocco di istruzioni fra
due parentesi graffe, ad esempio così:
// ....
$nome = 'Luca';
if ($nome == 'Luca')
{
echo "ciao Luca!<br>";
echo "dove sono i tuoi amici?<br>";
}
echo "ciao a tutti voi";
In questo modo, se la variabile $nome
ha effettivamente il
valore 'Luca' vengono eseguite le due istruzioni successive, comprese fra le
parentesi graffe. Dopo avere valutato la condizione ed eventualmente eseguito le
due istruzioni previste, lo script proseguirà con ciò che sta fuori dalle
parentesi graffe. Quindi nel nostro esempio la frase "ciao a tutti voi" viene
prodotta in ogni caso. È buona norma usare comunque le parentesi graffe per
delimitare il codice condizionato, anche quando è costituito da una sola
istruzione: infatti questo rende il codice più leggibile, ed inoltre potrebbe
evitarci degli errori se ci dovesse capitare di voler aggiungere delle
istruzioni al blocco condizionato dimenticando di aggiungere le graffe.
Dobbiamo notare un particolare, riguardo alla sintassi di questa istruzione:
per la prima volta, vediamo che in questo costrutto mancano i punto e virgola.
Infatti la if
e la condizione espressa fra parentesi non devono
averli; continuiamo invece a metterli nel blocco di codice condizionato.
Abbiamo detto poco fa che la condizione espressa fra parentesi potrebbe non avere un valore booleano. PHP però è in grado di considerare booleano qualsiasi valore, in base ad alcune regole molto semplici. Facciamo un altro esempio banale:
if (5) {
print "ciao Luca!";
}
Questo codice, da un punto di vista logico, non ha nessun senso, ma ci permette di capire come PHP interpreta le nostre espressioni. Infatti in questo caso la stringa "ciao Luca!" verrà sempre stampata. Questo perchè, per PHP, il valore 5, così come qualsiasi numero diverso da 0, è considerato 'vero'. In sostanza, PHP considera come falsi:
il valore numerico 0, nonchè una stringa che contiene '0'
una stringa vuota
un array con zero elementi
un valore NULL, cioè una variabile che non è stata definita o che è stata eliminata con unset(), oppure a cui è stato assegnato il valore NULL esplicitamente
Qualsiasi altro valore, per PHP è un valore vero. Quindi qualsiasi numero, intero o decimale purchè diverso da 0, qualsiasi stringa non vuota, se usati come espressione condizionale saranno considerati veri. Quindi anche la banale espressione che abbiamo utilizzato nell'esempio di prima.
Analizziamo ora un caso che spesso crea problemi se non viene compreso fin dalle prime battute. Vediamo questo codice
$a = 7;
if ($a = 4)
echo '$a è uguale a 4!';
A prima vista, qualcuno potrebbe essere ingannato da queste istruzioni,
soprattutto chi ha precedenti esperienze di programmazione in linguaggi
strutturati diversamente, nei quali un'espressione come $a = 4
potrebbe essere sia un'assegnazione che un test. Costoro infatti si aspetteranno
che questo blocco di codice non stampi niente, e rimarrebbero molto sorpresi,
qualora lo provassero, di vedere invece sul browser la frase '$a è uguale a 4'.
Questo succederebbe perchè l'espressione che abbiamo messo fra parentesi è
un'assegnazione: cioè essa assegna alla variabile $a il valore 4. L'istruzione
seguente viene quindi eseguita, per il motivo che abbiamo visto prima: il valore
della nostra espressione è 4, che per PHP è un valore vero. Se invece che if
($a = 4)
avessimo scritto if ($a = 0)
l'istruzione seguente
sarebbe stata saltata, perchè la nostra condizione avrebbe preso valore 0, cioè
falso. Per ottenere il risultato corretto logicamente, avremmo dovuto utilizzare
l'operatore di confronto:
$a = 7;
if ($a == 4)
echo '$a è uguale a 4!';
Ricordiamoci quindi, quando vogliamo verificare se il valore di una variabile è uguale a qualcosa, di utilizzare l'operatore condizionale di uguaglianza, cioè il doppio uguale ("=="). In caso contrario, non solo otterremo molto spesso risultati diversi da quelli che ci saremmo aspettati, ma avremo anche modificato il valore di una variabile che volevamo soltanto verificare.
Istruzioni Else e Elseif
Andiamo ora un po' più a fondo nell'analisi dell'istruzione if
:
essa infatti ci permette non solo di indicare quali istruzioni vogliamo eseguire
se la condizione è vera, ma anche di esprimere un blocco di codice da eseguire
quando la condizione è falsa. Ecco come:
If (<condizione>) {
<codice>
} else {
<codice>
}
La parola chiave else
, che significa 'altrimenti', deve essere
posizionata subito dopo la parentesi graffa di chiusura del codice previsto per
il caso 'vero' (o dopo l'unica istruzione prevista, se non abbiamo usato le
graffe). Anche per 'else' valgono le stesse regole: niente punto e virgola,
parentesi graffe obbligatorie se dobbiamo esprimere più di un'istruzione,
altrimenti facoltative. Ovviamente il blocco di codice specificato per 'else'
viene ignorato quando la condizione è vera, mentre viene eseguito se la
condizione è falsa.
Le istruzioni if
possono essere nidificate una dentro l'altra,
consentendoci così di creare codice di una certa complessità. Esempio:
$nome = 'Luca';
$cognome = 'Rossi';
if ($nome == 'Luca')
{
if ($cognome == 'Rossi')
{
print "Luca Rossi è di nuovo fra noi";
}
else
{
print "Abbiamo un nuovo Luca!";
}
}
else
{
print "ciao $nome!";
}
In questo caso, abbiamo nidificato un ulteriore test all'interno del primo
caso, quello in cui $nome
ha il valore 'Luca'. Abbiamo infatti
previsto un messaggio diverso, a seconda del valore della variabile
$cognome
.
In questo caso la sintassi generica è:
If (<condizione1>)
{
<codice1>
}
elseif (<condizione2>)
{
<codice2>
}
....
elseif (<condizioneN>)
{
<codiceN>
}
else
{
<codice Default>
}
Attraverso questa
possiamo indicare diverse condizioni, da valutare solo nel caso in cui
quella precedente risulti falsa. Indicheremo quindi, di seguito, il codice da
eseguire nel caso in cui questa condizione sia vera, ed eventualmente, con else
,
il codice previsto per il caso in cui anche la seconda condizione è falsa.
if ($nome == 'Luca')
{
print "bentornato Luca!";
}
elseif ($cognome == 'Verdi')
{
print "Buongiorno, signor Verdi";
}
elseif ($cognome == 'Gialli')
{
print "Bentornata, signora Gialli";
}
else
{
print "ciao $nome!";
}
In questo caso, abbiamo un'istruzione da eseguire quando $nome
vale 'Luca'; nel caso in cui ciò non sia vero, è prevista una seconda istruzione
se $cognome
è 'Verdi'; se nemmeno questo è vero, allora verrà
eseguita la terza istruzione. Da notare che, se $nome
è 'Luca' e
$cognome è 'Verdi', viene comunque eseguita solo la prima istruzione, perchè
dopo avere verificato la condizione, tutti gli altri casi vengono saltati.
Istruzione Switch e operatore ternario
Passiamo ora a verificare una seconda istruzione che ci permette di prevedere diversi valori possibili per un'espressione ed eseguire codice specifico in base al valore:
switch (<variabile>)
{
case <valore 1>:
<codice 1>
break;
case <valore 2>:
<codice 2>
break;
....
case <valore N>:
<codice N>
break;
default:
<codice Default>;
break;
}
L'istruzione switch
prevede che indichiamo, fra parentesi,
un'espressione che verrà valutata per il suo valore (questa volta non si tratta
necessariamente di un valore booleano). Di seguito, tra parentesi graffe,
esprimeremo una serie di espressioni da confrontare con quella indicata prima:
dal momento in cui ne trova una il cui valore è uguale, PHP esegue il codice
indicato di seguito, fino a quando non incontra un'istruzione break
.
Come possiamo vedere dall'esempio, le espressioni da confrontare con la prima
vengono precedute dalla parola chiave case
e seguite dai due punti.
L'istruzione default
può essere indicata come 'ultimo caso', che si
considera verificato quando nessuno dei casi precedenti è risultato vero.
L'indicazione default
può anche essere assente.
È molto importante comprendere la funzione dell'istruzione break
in questa situazione: infatti, quando PHP verifica uno dei casi, esegue non solo
il codice che trova subito dopo, ma anche tutto quello che trova di seguito,
compreso quello relativo ai casi seguenti. Questo fino a quando non trova,
appunto, un'istruzione break
. Se non mettessimo un'istruzione
break
alla fine di un blocco di codice relativo ad un caso particolare,
l'esecuzione continuerebbe eseguendo anche il case successivo. Questo
comportamento ci permette però di prevedere un unico comportamento per più
valori dell'espressione sotto esame:
switch ($nome)
{
case 'Luca':
case 'Giorgio':
case 'Franco':
print "Ciao, vecchio amico!";
break;
case 'Mario':
print "Ciao, Mario!";
break;
case 'Paolo':
print "Finalmente, Paolo!";
break;
default:
print "Benvenuto, chiunque tu sia";
}
In questo caso, abbiamo previsto un unico messaggio per il caso in cui la
variabile $nome
valga 'Luca', 'Giorgio' o 'Franco'.
L'operatore ternario è così chiamato perchè è formato da tre espressioni: il
valore restituito è quello della seconda o della terza di queste espressioni, a
seconda che la prima sia vera o falsa. In pratica, si può considerare, in certi
casi, una maniera molto sintetica di effettuare una if
.
($altezza >= 180) ? 'alto' : 'normale' ;
Questa espressione prenderà il valore 'alto' se la variabile $altezza
è maggiore o uguale a 180, e 'normale' nel caso opposto. Come vediamo,
l'espressione condizionale è contenuta fra parentesi e seguita da un punto
interrogativo, mentre due punti separano la seconda espressione dalla terza.
Questo costrutto può essere utilizzato, ad esempio, per valorizzare velocemente
una variabile senza ricorrere all'if
:
$tipologia = ($altezza >= 180) ? 'alto' : 'normale';
equivale a scrivere
if ($altezza >= 180)
$tipologia = 'alto' ;
else
$tipologia = 'normale';
Come potete vedere, in termini di spazio il risparmio è abbastanza significativo. Bisogna però stare attenti ad abusare di questa forma, perchè a volte può rendere più difficoltosa la leggibilità del nostro script, anche se risulta di indubbia utilità nel caso in cui si necessiti rendere più compatto il codice.
I Cicli
I cicli sono un altro degli elementi fondamentali di qualsiasi linguaggio di programmazione, in quanto ci permettono di eseguire determinate operazioni in maniera ripetitiva. È una necessità che si presenta molto spesso: infatti non è raro che un programma o uno script debbano elaborare quantità anche molto grosse di dati; in questa situazione, si prevederà il trattamento da utilizzare per ogni singolo dato (o gruppo di dati correlati), che sarà poi ripetuto per tutte le ricorrenze di tali dati.
Iniziamo subito con un esempio (come al solito abbastanza banale):
supponiamo di voler mostrare i multipli da 1 a 10 di un numero, ad esempio 5.
La prima soluzione è quella di usare il ciclo for
:
for ($mul = 1; $mul <= 10; ++$mul)
{
$ris = 5 * $mul;
echo "5 * $mul = $ris <br/>";
}
Questo costrutto, simile a quello usato in altri linguaggi, utilizza la
parola chiave for
, seguita, fra parentesi, dalle istruzioni per
definire il ciclo; di seguito, si racchiudono fra parentesi graffe tutte le
istruzioni che devono essere eseguite ripetutamente. Le tre istruzioni
inserite fra le parentesi tonde e separate da punto e virgola vengono trattate
in questo modo: la prima viene eseguita una sola volta,
all'inizio del ciclo; la terza viene eseguita alla fine di
ogni iterazione del ciclo; la seconda deve essere una
condizione, e viene valutata prima di ogni iterazione del ciclo: quando
risulta falsa, l'esecuzione del ciclo viene interrotta, ed il controllo passa
alle istruzioni dopo le parentesi graffe. Quando invece è vera, le istruzioni
fra parentesi graffe vengono eseguite. Ovviamente è possibile che tale
condizione risulti falsa fin dal primo test: in questo caso, le istruzioni
contenute fra le parentesi graffe non saranno eseguite nemmeno una volta.
Il formato standard è quindi quello che abbiamo visto sopra, che utilizza le parentesi tonde per definire un 'contatore': con la prima istruzione lo si inizializza, con la seconda lo si confronta con un valore limite oltre il quale il ciclo deve terminare, con la terza lo si incrementa dopo ogni esecuzione.
Con il ciclo for
, così come con tutti gli altri cicli, è molto
importante stare attenti a non creare una situazione in cui il ciclo
non raggiunge mai una via d'uscita (il cosiddetto 'loop'): in questo
caso, infatti, lo script rieseguirebbe il nostro ciclo all'infinito. Nel
nostro esempio di prima potrebbe succedere, ad esempio, se sbagliassimo a
scrivere il nome della variabile $mul
nell'istruzione di
incremento: se avessimo scritto $mus++
, avremmo incrementato
questa variabile, che non viene utilizzata nel ciclo, dopo ciascuna delle sue
esecuzioni; in questo modo $mul
rimarrebbe sempre uguale ad 1, ed
il nostro ciclo stamperebbe all'infinito "5 * 1 = 5", perchè $mul
non diventerebbe mai maggiore di 10.
In molte situazioni classiche di programmazione, un errore di questo genere
potrebbe costringerci a forzare la chiusura del programma o addirittura a
spegnere la macchina: nel caso di PHP, questo di solito non succede, in quanto
gli script PHP hanno un limite di tempo per la loro esecuzione, oltre il quale
si arrestano. Tale limite è normalmente di 30 secondi, ed è comunque
impostabile attraverso il file php.ini
.
Vediamo ora un altro tipo di ciclo, più semplice nella sua costruzione: il
ciclo while
. Questo si può considerare come una specie di if
ripetuta più volte: infatti la sua sintassi prevede che alla parola chiave while
segua, fra parentesi, la condizione da valutare, e fra parentesi graffe, il
codice da rieseguire fino a quando tale condizione rimane vera. Vediamo con un
esempio come ottenere lo stesso risultato dell'esempio precedente:
$mul = 1;
while ($mul <= 10)
{
$ris = 5 * $mul;
print("5 * $mul = $ris<br>");
$mul++;
}
Il ciclo while
, rispetto al for
, non ci mette a
disposizione le istruzioni per inizializzare e per incrementare il contatore:
quindi dobbiamo inserire queste istruzioni nel flusso generale del codice, per
cui mettiamo l'inizializzazione prima del ciclo, e l'incremento all'interno
del ciclo stesso, in fondo. Anche in questa situazione, comunque, il concetto
fondamentale è che l'esecuzione del ciclo termina quando la condizione fra
parentesi non è più verificata: ancora una volta, quindi, è possibile che il
ciclo non sia eseguito mai, nel caso in cui la condizione risulti falsa fin da
subito.
Esiste invece un'altra forma, simile al while
, con la quale
possiamo assicurarci che il codice indicato tra le parentesi graffe venga
eseguito almeno una volta: si tratta del do...while
$mul = 11;
do
{
$ris = 5 * $mul;
print("5 * $mul = $ris<br>");
$mul++;
}
while ($mul <= 10)
Con questa sintassi, il while
viene spostato dopo il codice da
ripetere, ad indicare che la valutazione della condizione viene eseguita solo
dopo l'esecuzione del codice fra parentesi graffe. Nel caso del nostro
esempio, abbiamo inizializzato la variabile $mul col valore 11, per creare una
situazione nella quale, con i cicli visti prima, non avremmo ottenuto alcun
output, mentre con l'uso del do...while
il codice viene eseguito
una volta nonostante la condizione indicata fra parentesi sia falsa fin
dall'inizio. L'esempio stamperà quindi "5 * 11 = 55".
Abbiamo visto che PHP termina l'esecuzione di un ciclo quando la condizione
a cui è sottoposto non è più verificata. Abbiamo però a disposizione altri
strumenti per modificare il comportamento del nostro script dall'interno del
ciclo: infatti possiamo dire a PHP di non completare la presente iterazione e
passare alla successiva (con continue
) oppure di interrompere
definitivamente l'esecuzione del ciclo (con break
). Vediamo un
esempio:
for ($ind = 1; $ind < 500; $ind++)
{
if ($ind % 100 == 0)
break;
elseif ($ind % 25 == 0)
continue;
echo "valore: $ind <br/>";
}
Questo codice imposta un ciclo per essere eseguito 500 volte, con valori di
$ind che vanno da 1 a 500. In realtà, le istruzioni che abbiamo posto al suo
interno fanno sì che la stampa del valore di $ind non venga eseguita ogni
volta che $ind
corrisponde ad un multiplo di 25 (infatti
l'istruzione 'continue' fa sì che PHP salti la 'print' e passi direttamente
all'iterazione successiva, incrementando la variabile), e che il ciclo si
interrompa del tutto quando $ind raggiunge il valore 100.
Esiste un ultimo tipo di ciclo, ed è un ciclo particolare perchè è
costruito appositamente per il trattamento degli array e di particolari
oggetti chiamati Iteratori: si tratta del foreach
. Questo ci
permette di costruire un ciclo che viene ripetuto per ogni elemento di una
collezione passata come argomento. La sintassi è la seguente:
foreach ($arr as $chiave => $valore)
{
<codice>
}
All'interno delle parentesi graffe avremo a disposizione, nelle due
variabili che abbiamo definito $chiave
e $valore
, l'indice e il contenuto dell'elemento che stiamo trattando. Ad esempio potremmo stampare l'elenco sottostante con questo breve script php
$Elenco = array("one" => 1,
"two" => 2,
"three" => 3,
"seventeen" => 17
);
foreach ($Elenco as $Indice => $Valore)
{
echo "\$Elenco[$Indice] => $Valore <BR>\n";
}
È da notare che, nel caso ci interessi soltanto il valore e non la chiave (ad esempio perchè le chiavi sono numeriche), possiamo anche evitare di estrarre la chiave stessa:
foreach ($arr as $valore)
{
<codice>
}
per cui l'esempio precedente può essere così riscritto
$Elenco = array(1, 2, 3, 17);
$i = 0;
foreach ($Elenco as $Valore)
{
echo "\$Elenco[$i] => $Valore<BR>\n";
$i++;
}
Gli array
Precedentemente abbiamo accennato il tipo di dato array con il seguente esempio:
$colori = array('bianco', 'nero', 'giallo', 'verde', 'rosso');
Usando questo tipo di definizione, PHP associa a ciascuno dei valori che abbiamo elencato un indice numerico, a partire da 0. Quindi, in questo caso, 'bianco' assumerà l'indice 0, 'nero' l'indice 1, e così via fino a 'rosso' che avrà indice 4. Per riferirsi ad un singolo elemento dell'array si indica il nome dell'array seguito dall'indice contenuto fra parentesi quadre:
echo $colori[2]; //stampa 'giallo'
Esiste poi un metodo per aggiungere un valore all'array; questo metodo può essere usato anche, come alternativa al precedente, per definire l'array:
$colori[] = 'blu';
Con questo codice verrà creato un nuovo elemento nell'array $colori
,
che avrà l'indice 5. Questa sintassi infatti può essere "tradotta"
come
"aggiungi un elemento in fondo all'array $colori". Come abbiamo detto, questa
sintassi è valida anche per definire un array, in alternativa a quella usata
prima: infatti, se ipotizziamo che l'array $colori
non fosse ancora
definito, questa istruzione lo avrebbe definito creando l'elemento con indice 0.
È naturalmente possibile anche indicare direttamente l'indice, anche in modo non
consecutivo:
$colori[3] = 'arancio';
$colori[7] = 'viola';
Dopo questa istruzione, l'elemento con indice 3, che prima valeva 'verde', avrà il valore cambiato in 'arancio'. Inoltre avremo un nuovo elemento, con indice 7, con il valore 'viola'. È da notare che, dopo queste istruzioni, il nostro array ha un "buco", perchè dal codice 5 si salta direttamente al codice 7: successivamente, se useremo di nuovo l'istruzione di "incremento" con le parentesi quadre vuote, il nuovo elemento prenderà l'indice 8. Infatti PHP, quando gli proponiamo un'istruzione di quel tipo, va a cercare l'elemento con l'indice più alto, e lo aumenta di 1 per creare quello nuovo. Provate ad eseguire il seguente script per avere conferma di quanto detto:
$colori = array('bianco', 'nero',
'giallo', 'verde', 'rosso');
$colori[] = 'blu';
$colori[7] = 'viola';
foreach ($colori as $i => $colore)
{
echo "\$Colori[$i] => $colore<BR>\n";
}
Ma l'argomento array non si limita a questo: infatti gli indici degli elementi non sono necessariamente numerici. Possono essere anche delle stringhe:
$persona['nome'] = 'Mario';
Con questa istruzione abbiamo definito un array di nome $persona
,
creando un elemento la cui chiave è 'nome' ed il cui valore è 'Mario'. È da
ricordare che le chiavi numeriche ed associative possono coesistere nello stesso
array. Vediamo un esempio banale, ipotizzando la formazione di una squadra di
calcio:
$formazione[1] ='Buffon';
$formazione[2] ='Panucci';
$formazione[3] ='Nesta';
$formazione[4] ='Cannavaro';
$formazione[5] ='Coco';
$formazione[6] ='Ambrosini';
$formazione[7] ='Tacchinardi';
$formazione[8] ='Perrotta';
$formazione[9] ='Totti';
$formazione[10] ='Inzaghi';
$formazione[11] ='Vieri';
$formazione['ct'] = 'Trapattoni';
In questo caso abbiamo creato un array con dodici elementi, di cui undici con chiavi numeriche, ed uno con chiave associativa. Se in seguito volessimo aggiungere un elemento usando le parentesi quadre vuote, il nuovo elemento prenderà l'indice 12. Avremmo potuto creare lo stesso array usando l'istruzione di dichiarazione dell'array, così:
$formazione = array(1 => 'Buffon', 'Panucci', 'Nesta', 'Cannavaro',
'Coco', 'Ambrosini',
'Tacchinardi', 'Perrotta', 'Totti', 'Inzaghi', 'Vieri', 'ct'
=> 'Trapattoni');
Analizziamo il formato di questa istruzione: per prima cosa abbiamo creato il
primo elemento, assegnandogli esplicitamente la chiave 1. Come possiamo vedere,
il sistema per fare ciò è di indicare la chiave, seguita dal simbolo =>
e dal valore dell'elemento. Se non avessimo indicato 1 come indice, PHP avrebbe
assegnato al primo elemento l'indice 0. Per gli elementi successivi, ci siamo
limitati ad elencare i valori, in quanto PHP, per ciascuno di essi, crea la
chiave numerica aumentando di 1 la più alta già esistente. Quindi 'Panucci'
prende l'indice 2, 'Nesta' il 3 e così via. Arrivati all'ultimo elemento,
siccome vogliamo assegnargli una chiave associativa, siamo obbligati ad
indicarla esplicitamente.
È da notare che quando abbiamo usato le chiavi associative le abbiamo indicate fra apici: ciò è necessario per mantenere la 'pulizia' del codice, in quanto, se non usassimo gli apici (come spesso si vede fare), PHP genererebbe un errore di tipo 'notice', anche se lo script funzionerebbe ugualmente (dato che il valore verrebbe convertito automaticamente in una stringa). Vediamo ora qualche esempio di creazione e stampa dei valori di un array:
$persona['nome'] = 'Mario';
//corretto
$persona[cognome] = 'Rossi'; /*funziona, ma genera un
errore 'notice'*/
echo $persona['cognome']; //stampa 'Rossi': corretto
echo "ciao $persona[nome]"; /*stampa 'ciao Mario':
corretto (niente apici fra virgolette)*/
echo "ciao $persona['nome']"; //NON FUNZIONA, GENERA
ERRORE
echo "ciao {$persona['nome']}"; /*corretto: per usare
gli apici fra virgolette dobbiamo comprendere il tutto fra parentesi graffe*/
echo "ciao " . $persona['nome']; /*corretto: come
alternativa, usiamo il punto per concatenare (v. lez.10 sugli operatori)*/
Abbiamo così visto in quale maniera possiamo creare ed assegnare valori agli array, usando indici numerici o associativi, impostando esplicitamente le chiavi o lasciando che sia PHP ad occuparsene. Vediamo ora in che modo possiamo creare strutture complesse di dati, attraverso gli array a più dimensioni.
Un array a più dimensioni è un array nel quale uno o più elementi sono degli array a loro volta. Supponiamo di voler raccogliere in un array i dati anagrafici di più persone: per ogni persona registreremo nome, cognome, data di nascita e città di residenza
$persone = array(
array('nome' => 'Mario', 'cognome' => 'Rossi',
'data_nascita' => '1973/06/15', 'residenza' => 'Roma'),
array('nome' => 'Paolo',
'cognome' => 'Bianchi',
'data_nascita' => '1968/04/05', 'residenza' => 'Torino'),
array('nome' => 'Luca', 'cognome' => 'Verdi',
'data_nascita' => '1964/11/26',
'residenza' => 'Napoli')
);
print $persone[0]['cognome']; // stampa 'Rossi'
print $persone[1]['residenza']; // stampa 'Torino'
print $persone[2]['nome']; // stampa 'Luca'
Con questo codice abbiamo definito un array formato a sua volta da tre array, che sono stati elencati separati da virgole, per cui ciascuno di essi ha ricevuto l'indice numerico a partire da 0. All'interno dei singoli array, invece, tutte le chiavi sono state indicate come associative. Da notare che, sebbene in questo caso ciascuno dei tre array 'interni' abbia la stessa struttura, in realtà è possibile dare a ciascun array una struttura autonoma. Vediamo un altro esempio:
$persone = array(
1 => array('nome' => 'Mario Rossi',
'residenza' => 'Roma',
'ruolo' => 'impiegato'),
2 => array('nome' => 'Paolo
Bianchi', 'data_nascita' => '1968/04/05',
'residenza' => 'Torino'),
'totale_elementi'
=> 2);
print $persone[1]['residenza']; // stampa 'Roma'
print $persone['totale_elementi']; // stampa '2'
In questo caso il nostro array è formato da due array, ai quali abbiamo assegnato gli indici 1 e 2, e da un terzo elemento, che non è un array ma una variabile intera, con chiave associativa 'totale_elementi'. I due array che costituiscono i primi due elementi hanno una struttura diversa: mentre il primo è formato dagli elementi 'nome', 'residenza' e 'ruolo', il secondo è formato da 'nome', 'data_nascita' e 'residenza'.
Le funzioni in PHP: gestire le variabili
Anche se la versione 5 ha portato un grosso supporto per la programmazione ad oggetti le funzioni rimangono comunque la parte fondamentale del linguaggio dato che PHP è nato come linguaggio procedurale, e tutt'oggi molti sviluppatori continuano a seguire questa filosofia di programmazione.
Una funzione è un insieme di istruzioni che hanno lo scopo (la funzione, appunto) di eseguire determinate operazioni. La praticità delle funzioni sta nel fatto che ci consentono di non dover riscrivere tutto il codice ogni volta che abbiamo la necessità di eseguire quelle operazioni comuni: ci basta infatti richiamare l'apposita funzione, fornendole i parametri, cioè i dati/informazioni, di cui ha bisogno per la sua esecuzione.
Le funzioni possono essere incorporate nel linguaggio oppure essere definite dall'utente. In entrambi i casi, il modo di richiamarle è lo stesso.
La sintassi fondamentale con la quale si richiama una funzione è molto semplice:
nome_funzione();
Si tratta semplicemente di indicare il nome della funzione, seguito da parentesi tonde. Queste parentesi devono contenere i parametri da passare alla funzione, ma vanno obbligatoriamente indicate anche se non ci sono parametri, nel qual caso rimangono vuote come nell'esempio che abbiamo visto sopra. Nel caso poi in cui la funzione restituisca un valore, possiamo indicare la variabile in cui immagazzinarlo:
$valore = nome_funzione();
In questo modo, la variabile $valore
riceverà il risultato della
funzione. Le funzioni possono essere utilizzate anche all'interno di
espressioni: in tal caso il valore restituito verrà utilizzato durante la
valutazione dell'espressione:
$prova = (10 * numero_anni()) - numero_casuale();
Abbiamo detto che le funzioni possono essere incorporate nel linguaggio oppure definite dall'utente: in questa lezione passeremo in rassegna alcune fra le funzioni incorporate maggiormente utilizzate in PHP, tenendo però presente che tali funzioni sono numerosissime, rivolte agli scopi più disparati, e che quindi non ne avremo che una visione molto parziale. Consiglio la consultazione del manuale online per una trattazione più completa delle funzionalità e dei casi particolari.
Cominciamo dalle principali funzioni che operano sulle variabili in generale:
empty(valore): verifica se la variabile che le passiamo è vuota oppure no. Per 'vuota' si intende che la variabile può contenere una stringa vuota o un valore numerico pari a 0, ma può anche essere non definita o essere impostata al valore NULL (l'eventuale indicazione di una variabile non definita, in questo caso, non genera errore notice). Restituisce un valore booleano (vero o falso).
isset(valore): verifica se la variabile è definita. Una variabile risulta non definita quando non è stata inizializzata o è stata impostata col valore NULL. Restituisce un valore booleano.
is_null(valore): verifica se la variabile equivale a NULL, ma genera un errore 'notice' se viene eseguito su una variabile non definita. Restituisce un valore booleano.
is_int(valore), is_integer(valore), is_long(valore): verifica se la variabile è di tipo intero. Le tre funzioni sono equivalenti. Restituiscono un valore booleano.
is_float(valore), is_double(valore), is_real(valore): verifica se la variabile è di tipo numerico double (o float). Le tre funzioni sono equivalenti. Restituiscono un valore booleano.
is_string(valore): verifica se la variabile è una stringa. Restituisce un valore booleano.
is_array(valore): verifica se la variabile è un array. Restituisce un valore booleano.
is_numeric(valore): verifica se la variabile contiene un
valore numerico. È molto importante la distinzione fra questa funzione e
is_int()
o is_float()
, perchè queste ultime, nel caso di
una stringa che contiene valori numerici, restituiscono falso, mentre
is_numeric()
restituisce vero. Restituisce un valore booleano.
gettype(valore): verifica quale tipo di dato le abbiamo passato. Restituisce una stringa che rappresenta il tipo di dato, ad esempio: 'boolean', 'integer', 'double', 'string', 'array'. È bene però, in uno script, non fare affidamento su questi valori per dedurre il tipo di dato, perchè in versioni future di PHP alcune di queste stringhe potrebbero essere modificate. Meglio usare le funzioni viste prima.
print_r(valore): stampa (direttamente sul browser) informazioni relative al contenuto della variabile che le abbiamo passato. È utile in fase di debug, quando a seguito di comportamenti 'strani' del nostro script vogliamo verificare il contenuto di certi dati. Se il valore passato è un array, la funzione ne evidenzia le chiavi ed i valori relativi. Restituisce un valore booleano.
unset(valore): distrugge la variabile specificata. In
realtà non si tratta di una funzione, ma di un costrutto del linguaggio, e ne
abbiamo già parlato nella lez. 8. Dopo l'unset()
, l'esecuzione di
empty()
o is_null()
sulla stessa variabile
restituirà vero, mentre isset()
restituirà falso. Non restituisce
valori.
Vediamo ora qualche esempio per chiarire l'utilizzo di queste funzioni:
$b = empty($a); //$a non è ancora
definita, quindi $b sarà vero
$a = 5;
$b = isset($a); //vero
$b = is_float($a); //falso: $a è un intero
$b = is_string($a); //falso
$a = '5';
$b = is_int($a); //falso: $a ora è una stringa
$b = is_string($a); //vero
$b = is_numeric($a); //vero: la stringa ha un contenuto
numerico
$c = gettype($b); //$c prende il valore 'boolean'
unset($a); //eliminiamo la variabile $a;
$b = is_null($a); //vero, ma genera errore
In questi esempi abbiamo sempre assegnato alla variabile $b
i
valori booleani restituiti dalle funzioni. Nella pratica, è più frequente che
tali valori non siano memorizzati in variabili, ma che vengano usati
direttamente come condizioni, ad esempio per delle istruzioni di tipo if
.
Ancora un paio di esempi:
if (empty($a))
{
print ('$a è vuota o non definita!');
}
else
{
print ('$a contiene un valore');
}
if (is_numeric($a))
{
print ('$a contiene un valore numerico');
}
else
{
print ('$a non contiene un numero');
}
Le funzioni relative al test sulle variabili sono diverse. Ecco un elenco preso pari pari dall'help relativo al PHP versione 5:
debug_zval_dump -- Dumps a
string representation of an internal zend value to output
doubleval -- Alias of floatval()
empty -- Determine whether a variable is empty
floatval -- Get float value of a variable
get_defined_vars -- Returns an array of all defined variables
get_resource_type -- Returns the resource type
gettype -- Get the type of a variable
import_request_variables -- Import GET/POST/Cookie variables into the
global scope
intval -- Get the integer value of a variable
is_array -- Finds whether a variable is an array
is_bool -- Finds out whether a variable is a boolean
is_callable -- Verify that the contents of a variable can be called as a
function
is_double -- Alias of is_float()
is_float -- Finds whether a variable is a float
is_int -- Find whether a variable is an integer
is_integer -- Alias of is_int()
is_long -- Alias of is_int()
is_null -- Finds whether a variable is NULL
is_numeric -- Finds whether a variable is a number or a numeric string
is_object -- Finds whether a variable is an object
is_real -- Alias of is_float()
is_resource -- Finds whether a variable is a resource
is_scalar -- Finds whether a variable is a scalar
is_string -- Finds whether a variable is a string
isset -- Determine whether a variable is set
print_r -- Prints human-readable information about a variable
serialize -- Generates a storable representation of a value
settype -- Set the type of a variable
strval -- Get string value of a variable
unserialize -- Creates a PHP value from a stored representation
unset -- Unset a given variable
var_dump -- Dumps information about a variable
var_export -- Outputs or returns a parsable string representation of a
variable
Le funzioni in PHP: gestire le stringhe
Passiamo ora ad esaminare alcune funzioni che operano sulle stringhe (l'eventuale indicazione di un parametro tra parentesi quadre indica che quel parametro è facoltativo, quindi può non essere indicato nel momento in cui si chiama la funzione):
strlen(stringa): verifica la lunghezza della stringa, cioè il numero di caratteri che la compongono. Restituisce un numero intero.
trim(stringa): elimina gli spazi all'inizio e alla fine della stringa. Restituisce la stringa modificata.
ltrim(stringa): elimina gli spazi all'inizio della stringa. Restituisce la stringa modificata.
rtrim(stringa): elimina gli spazi alla fine della stringa. Restituisce la stringa modificata.
substr(stringa, intero [, intero]): restituisce una
porzione della stringa, in base al secondo parametro (che indica l'inizio
della porzione da estrarre), e all'eventuale terzo parametro, che indica
quanti caratteri devono essere estratti. Se il terzo parametro non viene
indicato, viene restituita tutta la parte finale della stringa a partire dal
carattere indicato. Da notare che i caratteri vanno contati a partire da zero,
per cui se si chiama la funzione con substr(stringa, 4) verranno restituiti
tutti i caratteri a partire dal quinto. Si può anche indicare un numero
negativo come carattere iniziale: in questo caso, il carattere iniziale della
porzione di stringa restituita verrà contato a partire dal fondo. Ad esempio,
con substr(stringa, -5, 3) si otterranno tre caratteri a partire dal
quintultimo (da notare che in questo caso il conteggio non inizia da zero, ma
da 1: cioè -1 indica l'ultimo carattere, -2 il penultimo e così via). Se
infine si indica un numero negativo come terzo parametro, tale parametro non
verrà più utilizzato come numero di caratteri restituiti, ma come numero di
caratteri non restituiti a partire dal fondo. Esempio: substr(stringa,
3, -2)
restituisce i caratteri dal quarto al terzultimo. La funzione
restituisce la porzione di stringa richiesta.
str_replace(stringa, stringa, stringa): effettua una
sostituzione della prima stringa con la seconda all'interno della terza. Ad
esempio: str_replace('p', 't', 'pippo')
sostituisce le 'p' con le
't' all'interno di 'pippo', e quindi restituisce 'titto'. Restituisce la terza
stringa modificata. Esiste anche la funzione str_ireplace()
, che
è equivalente ma che cerca la prima stringa nella terza senza tener conto
della differenza fra maiuscole e minuscole.
strpos(stringa, stringa): cerca la posizione della
seconda stringa all'interno della prima. Ad esempio: strpos('Lorenzo', 're')
restituisce 2, ad indicare la terza posizione. Restituisce un intero che
rappresenta la posizione a partire da 0 della stringa cercata. Se la seconda
stringa non è presente nella prima, restituisce il valore booleano FALSE. La
funzione stripos()
fa la stessa ricerca senza tenere conto della
differenza fra maiuscole e minuscole.
strstr(stringa, stringa): cerca la seconda stringa
all'interno della prima, e restituisce la prima stringa a partire dal punto in
cui ha trovato la seconda. strstr('Lorenzo', 're')
restituisce 'renzo'.
Restituisce una stringa se la ricerca va a buon fine, altrimenti il valore
booleano FALSE. La funzione stristr() funziona allo stesso modo ma non tiene
conto della differenza fra maiuscole e minuscole.
strtolower(stringa): converte tutti i caratteri alfabetici nelle corrispondenti lettere minuscole. Restituisce la stringa modificata.
strtoupper(stringa): converte tutti i caratteri alfabetici nelle corrispondenti lettere maiuscole. Restituisce la stringa modificata.
ucfirst(stringa): trasforma in maiuscolo il primo carattere della stringa. Restituisce la stringa modificata.
ucwords(stringa): trasforma in maiuscolo il primo carattere di ogni parola della stringa, intendendo come parola una serie di caratteri che segue uno spazio. Restituisce la stringa modificata.
explode(stringa, stringa [, intero]): trasforma la
seconda stringa in un array, usando la prima per separare gli elementi. Il
terzo parametro può servire ad indicare il numero massimo di elementi che l'array
può contenere (se la suddivisione della stringa portasse ad un numero
maggiore, la parte finale della stringa sarà interamente contenuta nell'ultimo
elemento). Ad esempio: explode(' ', 'ciao Mario')
restituisce un
array di due elementi in cui il primo è 'ciao' e il secondo 'Mario'.
Restituisce un array.
Dobbiamo fare un'annotazione relativa a tutte queste funzioni, in particolare quelle che hanno lo scopo di modificare una stringa: la stringa modificata è il risultato della funzione, che dovremo assegnare ad una variabile apposita. Le variabili originariamente passate alla funzione rimangono invariate. Vediamo alcuni esempi sull'uso di queste funzioni:
$a = 'IERI ERA DOMENICA';
$b = strtolower($a); /* $b diventa 'ieri era domenica',
ma $a rimane 'IERI ERA DOMENICA' */
strlen('abcd'); //restituisce 4
trim(' Buongiorno a tutti '); //restituisce 'Buongiorno a
tutti'
substr('Buongiorno a tutti', 4); /* 'giorno a tutti'
(inizia dal quinto) */
substr('Buongiorno a tutti', 4, 6); /* 'giorno'(6
caratteri a partire dal quinto) */
substr('Buongiorno a tutti', -4); //'utti' (ultimi
quattro)
substr('Buongiorno a tutti', -4, 2); /* 'ut' (2 caratteri
a partire dal quartultimo) */
substr('Buongiorno a tutti, 4, -2); /* 'giorno a tut'
(dal quinto al terzultimo) */
str_replace('Buongiorno', 'Ciao', 'Buongiorno a tutti');
/* 'Ciao a tutti' */
str_replace('dom', 'x', 'Domani è domenica'); //'Domani è
xenica'
str_ireplace('dom', 'x', 'Domani è domenica'); //'xani è
xenica'
strpos('Domani è domenica', 'm'); //2 (prima 'm' trovata)
strstr('Domani è domenica', 'm'); /* 'mani è domenica' (a
partire dalla prima 'm') */
strtoupper('Buongiorno a tutti'); //'BUONGIORNO A TUTTI'
ucfirst('buongiorno a tutti'); //'Buongiorno a tutti';
ucwords('buongiorno a tutti'); //'Buongiorno A Tutti';
explode(',','Alberto,Mario,Giovanni');
/* suddivide la
stringa in un array, separando un elemento ogni volta
che trova una virgola; avremo quindi un array di tre elementi: ('Alberto','Mario','Giovanni')*/
explode(',','Alberto,Mario,Giovanni',2);
/* in questo
caso l'array può contenere al massimo due elementi,
per cui nel primo elemento andrà 'Alberto' e nel secondo il resto della stringa:
'Mario,Giovanni' */
Le funzioni relative alle stringhe sono molte. Ecco un elenco preso pari pari dall'help relativo al PHP versione 5:
addcslashes -- Quote
string with slashes in a C style
addslashes -- Quote string with slashes
bin2hex -- Convert binary data into hexadecimal representation
chop -- Alias of rtrim()
chr -- Return a specific character
chunk_split -- Split a string into smaller chunks
convert_cyr_string -- Convert from one Cyrillic character set to another
convert_uudecode -- Decode a uuencoded string
convert_uuencode -- Uuencode a string
count_chars -- Return information about characters used in a string
crc32 -- Calculates the crc32 polynomial of a string
crypt -- One-way string encryption (hashing)
echo -- Output one or more strings
explode -- Split a string by string
fprintf -- Write a formatted string to a stream
get_html_translation_table -- Returns the translation table used by
htmlspecialchars() and htmlentities()
hebrev -- Convert logical Hebrew text to visual text
hebrevc -- Convert logical Hebrew text to visual text with newline
conversion
html_entity_decode -- Convert all HTML entities to their applicable
characters
htmlentities -- Convert all applicable characters to HTML entities
htmlspecialchars_decode -- Convert special HTML entities back to
characters
htmlspecialchars -- Convert special characters to HTML entities
implode -- Join array elements with a string
join -- Alias of implode()
levenshtein -- Calculate Levenshtein distance between two strings
localeconv -- Get numeric formatting information
ltrim -- Strip whitespace (or other characters) from the beginning of a
string
md5_file -- Calculates the md5 hash of a given file
md5 -- Calculate the md5 hash of a string
metaphone -- Calculate the metaphone key of a string
money_format -- Formats a number as a currency string
nl_langinfo -- Query language and locale information
nl2br -- Inserts HTML line breaks before all newlines in a string
number_format -- Format a number with grouped thousands
ord -- Return ASCII value of character
parse_str -- Parses the string into variables
print -- Output a string
printf -- Output a formatted string
quoted_printable_decode -- Convert a quoted-printable string to an 8 bit
string
quotemeta -- Quote meta characters
rtrim -- Strip whitespace (or other characters) from the end of a string
setlocale -- Set locale information
sha1_file -- Calculate the sha1 hash of a file
sha1 -- Calculate the sha1 hash of a string
similar_text -- Calculate the similarity between two strings
soundex -- Calculate the soundex key of a string
sprintf -- Return a formatted string
sscanf -- Parses input from a string according to a format
str_ireplace -- Case-insensitive version of str_replace().
str_pad -- Pad a string to a certain length with another string
str_repeat -- Repeat a string
str_replace -- Replace all occurrences of the search string with the
replacement string
str_rot13 -- Perform the rot13 transform on a string
str_shuffle -- Randomly shuffles a string
str_split -- Convert a string to an array
str_word_count -- Return information about words used in a string
strcasecmp -- Binary safe case-insensitive string comparison
strchr -- Alias of strstr()
strcmp -- Binary safe string comparison
strcoll -- Locale based string comparison
strcspn -- Find length of initial segment not matching mask
strip_tags -- Strip HTML and PHP tags from a string
stripcslashes -- Un-quote string quoted with addcslashes()
stripos -- Find position of first occurrence of a case-insensitive string
stripslashes -- Un-quote string quoted with addslashes()
stristr -- Case-insensitive strstr()
strlen -- Get string length
strnatcasecmp -- Case insensitive string comparisons using a "natural
order" algorithm
strnatcmp -- String comparisons using a "natural order" algorithm
strncasecmp -- Binary safe case-insensitive string comparison of the
first n characters
strncmp -- Binary safe string comparison of the first n characters
strpbrk -- Search a string for any of a set of characters
strpos -- Find position of first occurrence of a string
strrchr -- Find the last occurrence of a character in a string
strrev -- Reverse a string
strripos -- Find position of last occurrence of a case-insensitive string
in a string
strrpos -- Find position of last occurrence of a char in a string
strspn -- Find length of initial segment matching mask
strstr -- Find first occurrence of a string
strtok -- Tokenize string
strtolower -- Make a string lowercase
strtoupper -- Make a string uppercase
strtr -- Translate certain characters
substr_compare -- Binary safe optionally case insensitive comparison of 2
strings from an offset, up to length characters
substr_count -- Count the number of substring occurrences
substr_replace -- Replace text within a portion of a string
substr -- Return part of a string
trim -- Strip whitespace (or other characters) from the beginning and end
of a string
ucfirst -- Make a string's first character uppercase
ucwords -- Uppercase the first character of each word in a string
vfprintf -- Write a formatted string to a stream
vprintf -- Output a formatted string
vsprintf -- Return a formatted string
wordwrap -- Wraps a string to a given number of characters using a string
break character
Le funzioni in PHP: gestire gli array
Vediamo ora alcune funzioni che operano sugli array:
count(array): conta il numero di elementi dell'array. Restituisce un intero.
array_reverse(array [, booleano]): inverte l'ordine degli elementi dell'array. Se vogliamo mantenere le chiavi dell'array di input, dobbiamo passare il secondo parametro con valore TRUE. Restituisce l'array di input con gli elementi invertiti. Il secondo argomento se omesso vale FALSE.
sort(array): ordina gli elementi dell'array in modo crescente. Bisogna fare attenzione, perchè questa funzione, contrariamente a molte altre, modifica direttamente l'array che le viene passato in input, che quindi andrà perso nella sua composizione originale. I valori vengono disposti in ordine crescente secondo i criteri che abbiamo visto nella lezione 10. Le chiavi vanno perse: dopo il sort, l'array avrà chiavi numeriche a partire da 0 secondo il nuovo ordinamento. Non restituisce nulla.
rsort(array): ordina gli elementi dell'array in ordine decrescente. Anche questa funzione modifica direttamente l'array passato in input e riassegna le chiavi numeriche a partire da 0. Non restituisce nulla.
asort(array): funziona come sort()
, con la
differenza che vengono mantenute le chiavi originarie degli elementi. Non
restituisce nulla.
arsort(array): come rsort()
, ordina in modo
decrescente; mantiene però le chiavi originarie. Non restituisce nulla.
in_array(valore, array): cerca il valore all'interno dell'array. Restituisce un valore booleano: vero o falso a seconda che il valore cercato sia presente o meno nell'array - E' case sensitive.
array_key_exists(valore, array): cerca il valore fra le chiavi (e non fra i valori) dell'array. Restituisce un valore booleano.
array_search(valore, array): cerca il valore nell'array e ne indica la chiave. Restituisce la chiave del valore trovato o, se la ricerca non va a buon fine, il valore FALSE.
array_merge(array, array [, array...]): fonde gli elementi di due o più array. Gli elementi con chiavi numeriche vengono accodati l'uno all'altro e le chiavi rinumerate. Le chiavi associative invece vengono mantenute, e nel caso vi siano più elementi nei diversi array con le stesse chiavi associative, l'ultimo sovrascrive i precedenti. Restituisce l'array risultante dalla fusione.
array_pop(array): estrae l'ultimo elemento dell'array, che viene 'accorciato'. Restituisce l'elemento in fondo all'array e, contemporaneamente, modifica l'array in input togliendogli lo stesso elemento.
array_push(array, valore [,valore...]): accoda i valori indicati all'array. Equivale all'uso dell'istruzione di accodamento $array[]=$valore , con il vantaggio che ci permette di accodare più valori tutti in una volta. Restituisce il numero degli elementi dell'array dopo l'accodamento.
array_shift(array): estrae un elemento come
array_pop()
, ma in questo caso si tratta del primo. Anche in questo
caso l'array viene 'accorciato', ed inoltre gli indici numerici vengono
rinumerati. Rimangono invece invariati quelli associativi. Restituisce
l'elemento estratto dall'array.
array_unshift(array, valore [,valore...]): inserisce i valori indicati in testa all'array. Restituisce il numero degli elementi dell'array dopo l'inserimento.
implode(stringa, array): è la funzione opposta di
explode()
, e serve a riunire in un'unica stringa i valori dell'array.
La stringa indicata come primo parametro viene interposta fra tutti gli
elementi dell'array. Restituisce la stringa risultato dell'aggregazione. Suo
sinonimo è join()
.
explode(stringa, array): è la funzione opposta di
implode()
, e serve a distribuire in un array i valori contenuti in un'unica stringa
(separati da un particolare carattere).
La stringa indicata come primo parametro rappresenta il separatore che viene interposta
tra ogni singolo valore.
Ecco qualche esempio sull'uso di queste funzioni:
$arr = array('Luca', 'Giovanni', 'Matteo',
'Paolo', 'Antonio', 'Marco', 'Giuseppe');
echo "<HR><B>count(\$arr) - in_array('Matteo', \$arr)</B><BR>";
$n = count($arr); // $n vale 7
if (in_array('Matteo', $arr))
echo "Matteo è nell'elenco dei $n nominativi<BR>";
else
echo "Matteo non è nell'elenco dei $n nominativi<BR>";
if (in_array('matteo', $arr))
echo "matteo è nell'elenco dei $n nominativi<BR>";
else
echo "matteo non è nell'elenco dei $n nominativi<BR>";
if (in_array('Francesco', $arr))
echo "Francesco è nell'elenco dei $n nominativi<BR>";
else
echo "Francesco non è nell'elenco dei $n nominativi<BR>";
$arr1 = array_reverse($arr); /* $arr1 avrà gli elementi invertiti, da 'Giuseppe'
a 'Luca' */
echo "<HR><B>array_reverse(\$arr)</B><BR>";
foreach ($arr1 as $i => $p)
{
echo "\$arr1[$i] => $p<BR>\n";
}
$arr2 = array_reverse($arr,false);
echo "<HR><B>array_reverse(\$arr,false)</B><BR>";
foreach ($arr2 as $i => $p)
{
echo "\$arr2[$i] => $p<BR>\n";
}
$arr2 = array_reverse($arr,true);
echo "<HR><B>array_reverse(\$arr,true)</B><BR>";
foreach ($arr2 as $i => $p)
{
echo "\$arr2[$i] => $p<BR>\n";
}
$arr = array('Luca', 'Giovanni', 'Matteo', 'Paolo', 'Antonio', 'Marco', 'Giuseppe');
sort($arr); /* ora $arr sarà: 'Antonio', 'Giovanni', 'Giuseppe', 'Luca', 'Marco',
' Matteo', 'Paolo' */
echo "<HR><B>sort(\$arr)</B><BR>";
foreach ($arr as $i => $p)
{
echo "\$arr[$i] => $p<BR>\n";
}
$ultimo = array_pop($arr); // $ultimo è 'Paolo' (li avevamo ordinati!)
$ultimo = array_pop($arr); /* ora $ultimo è 'Matteo', e in $arr sono rimasti 5
elementi */
$primo = array_shift($arr); // primo è 'Antonio'
$a = array_unshift($arr, $ultimo, $primo); /* 'Matteo' e 'Antonio' vengono
reinseriti */
$stringa = implode(' ', $arr); /* $stringa diventa 'Matteo Antonio ...' */
echo "<HR><B>array_pop(\$arr) - array_shift(\$arr) - array_unshift(\$arr) -
implode(' ', \$arr)</B><BR>";
foreach ($arr as $i => $p)
{
echo "\$arr[$i] => $p<BR>\n";
}
echo $stringa . "<BR>\n";
$new_arr = array_merge($arr, $arr1); /* $new_arr conterrà 13 elementi */
echo "<HR><B>array_merge(\$arr, \$arr1)</B><BR>";
foreach ($new_arr as $i => $p)
{
echo "\$new_arr[$i] => $p<BR>\n";
}
$luoghi = explode(",", "casa,scuola,chiesa,piazza");
echo "<HR><B>\$luoghi=explode(separatore, stringa)</B><BR>";
foreach ($luoghi as $i => $p)
{
echo "\$luoghi[$i] => $p<BR>\n";
}
$arr = array('Luca', 'Giovanni', 'Matteo', 'Paolo', 'Antonio', 'Marco', 'Giuseppe');
rsort($arr); /* ora $arr sarà: 'Antonio', 'Giovanni', 'Giuseppe', 'Luca', 'Marco',
' Matteo', 'Paolo' */
echo "<HR><B>rsort(\$arr)</B><BR>";
foreach ($arr as $i => $p)
{
echo "\$arr[$i] => $p<BR>\n";
}
$arr = array('Luca', 'Giovanni', 'Matteo', 'Paolo', 'Antonio', 'Marco', 'Giuseppe');
asort($arr); /* ora $arr sarà: 'Antonio', 'Giovanni', 'Giuseppe', 'Luca', 'Marco',
' Matteo', 'Paolo' */
echo "<HR><B>asort(\$arr)</B><BR>";
foreach ($arr as $i => $p)
{
echo "\$arr[$i] => $p<BR>\n";
}
Ecco un esempio sull'uso di queste funzioni in presenza di array con chiavi associative:
//Impostiamo ora un array con
chiavi associative:
$famiglia = array('padre' => 'Claudio', 'madre' => 'Paola', 'figlio' => 'Marco',
'figlia' => 'Elisa');
$famiglia2 = array('padre' => 'Marco', 'madre' => 'Elena', 'figlio' => 'Giorgio');
echo "<HR><B>\$famiglia</B><BR>";
foreach ($famiglia as $i => $p)
{
echo "\$famiglia[$i] => $p<BR>\n";
}
$fam1 = $famiglia; /* creiamo una copia del nostro array per poter fare
esperimenti */
rsort($fam1); /* ora $fam1 sarà 'Paola', 'Marco', 'Elisa', 'Claudio', con chiavi
da 0 a 3 */
echo "<HR><B>rsort(\$fam1)</B><BR>";
foreach ($fam1 as $i => $p)
{
echo "\$fam1[$i] => $p<BR>\n";
}
$fam1 = $famiglia; //ripristiniamo l'array originale
arsort($fam1); /* di nuovo $fam1 sarà 'Paola', 'Marco', 'Elisa', 'Claudio', ma
ciascuno con la sua
chiave originale ('madre', 'figlio', 'figlia', 'padre') */
echo "<HR><B>arsort(\$fam1)</B><BR>";
foreach ($fam1 as $i => $p)
{
echo "\$fam1[$i] => $p<BR>\n";
}
$fam1=array_reverse($famiglia);
echo "<HR><B>\$fam1=array_reverse(\$famiglia)</B><BR>";
foreach ($fam1 as $i => $p)
{
echo "\$fam1[$i] => $p<BR>\n";
}
$fam1=array_reverse($famiglia,false);
echo "<HR><B>\$fam1=array_reverse(\$famiglia,false)</B><BR>";
foreach ($fam1 as $i => $p)
{
echo "\$fam1[$i] => $p<BR>\n";
}
$fam1=array_reverse($famiglia,true);
echo "<HR><B>\$fam1=array_reverse(\$famiglia,true)</B><BR>";
foreach ($fam1 as $i => $p)
{
echo "\$fam1[$i] => $p<BR>\n";
}
echo "<HR><B>array_key_exists('figlia', \$famiglia) - array_search('Elena',\$famiglia2)
- \$stringa=implode(' ',\$famiglia)</B><BR>";
if ( array_key_exists('figlia', $famiglia))
echo "La \$famiglia ha figlie<BR>";
else
echo "La \$famiglia non ha figlie<BR>";
if ( array_key_exists('figlia', $famiglia2))
echo "La \$famiglia2 ha figlie<BR>";
else
echo "La \$famiglia2 non ha figlie<BR>";
$parentela = array_search('Claudio', $famiglia); //$a è 'padre'
echo "'Claudio' nella \$famiglia è: $parentela<BR>";
$parentela = array_search('Elena', $famiglia2); //$a è 'padre'
echo "'Elena' nella \$famiglia2 è: $parentela<BR>";
$stringa=implode(' ',$famiglia);
echo $stringa . "<BR>";
Le funzioni relative all'array sono molte. Ecco un elenco preso pari pari dall'help relativo al PHP versione 5:
array_change_key_case --
Returns an array with all string keys lowercased or uppercased
array_chunk -- Split an array into chunks
array_combine -- Creates an array by using one array for keys and another
for its values
array_count_values -- Counts all the values of an array
array_diff_assoc -- Computes the difference of arrays with additional
index check
array_diff_key -- Computes the difference of arrays using keys for
comparison
array_diff_uassoc -- Computes the difference of arrays with additional
index check which is performed by a user supplied
callback function
array_diff_ukey -- Computes the difference of arrays using a callback
function on the keys for comparison
array_diff -- Computes the difference of arrays
array_fill -- Fill an array with values
array_filter -- Filters elements of an array using a callback function
array_flip -- Exchanges all keys with their associated values in an array
array_intersect_assoc -- Computes the intersection of arrays with
additional index check
array_intersect_key -- Computes the intersection of arrays using keys for
comparison
array_intersect_uassoc -- Computes the intersection of arrays with
additional index check, compares indexes by a
callback function
array_intersect_ukey -- Computes the intersection of arrays using a
callback function on the keys for comparison
array_intersect -- Computes the intersection of arrays
array_key_exists -- Checks if the given key or index exists in the array
array_keys -- Return all the keys of an array
array_map -- Applies the callback to the elements of the given arrays
array_merge_recursive -- Merge two or more arrays recursively
array_merge -- Merge one or more arrays
array_multisort -- Sort multiple or multi-dimensional arrays
array_pad -- Pad array to the specified length with a value
array_pop -- Pop the element off the end of array
array_product -- Calculate the product of values in an array
array_push -- Push one or more elements onto the end of array
array_rand -- Pick one or more random entries out of an array
array_reduce -- Iteratively reduce the array to a single value using a
callback function
array_reverse -- Return an array with elements in reverse order
array_search -- Searches the array for a given value and returns the
corresponding key if successful
array_shift -- Shift an element off the beginning of array
array_slice -- Extract a slice of the array
array_splice -- Remove a portion of the array and replace it with
something else
array_sum -- Calculate the sum of values in an array
array_udiff_assoc -- Computes the difference of arrays with additional
index check, compares data by a callback function
array_udiff_uassoc -- Computes the difference of arrays with additional
index check, compares data and indexes
by a callback function
array_udiff -- Computes the difference of arrays by using a callback
function for data comparison
array_uintersect_assoc -- Computes the intersection of arrays with
additional index check, compares
data by a callback function
array_uintersect_uassoc -- Computes the intersection of arrays with
additional index check,
compares data and indexes by a callback functions
array_uintersect -- Computes the intersection of arrays, compares data by
a callback function
array_unique -- Removes duplicate values from an array
array_unshift -- Prepend one or more elements to the beginning of an
array
array_values -- Return all the values of an array
array_walk_recursive -- Apply a user function recursively to every member
of an array
array_walk -- Apply a user function to every member of an array
array -- Create an array
arsort -- Sort an array in reverse order and maintain index association
asort -- Sort an array and maintain index association
compact -- Create array containing variables and their values
count -- Count elements in an array, or properties in an object
current -- Return the current element in an array
each -- Return the current key and value pair from an array and advance
the array cursor
end -- Set the internal pointer of an array to its last element
extract -- Import variables into the current symbol table from an array
in_array -- Checks if a value exists in an array
key -- Fetch a key from an associative array
krsort -- Sort an array by key in reverse order
ksort -- Sort an array by key
list -- Assign variables as if they were an array
natcasesort -- Sort an array using a case insensitive "natural order"
algorithm
natsort -- Sort an array using a "natural order" algorithm
next -- Advance the internal array pointer of an array
pos -- Alias of current()
prev -- Rewind the internal array pointer
range -- Create an array containing a range of elements
reset -- Set the internal pointer of an array to its first element
rsort -- Sort an array in reverse order
shuffle -- Shuffle an array
sizeof -- Alias of count()
sort -- Sort an array
uasort -- Sort an array with a user-defined comparison function and
maintain index association
uksort -- Sort an array by keys using a user-defined comparison function
usort -- Sort an array by values using a user-defined comparison function
Le funzioni in PHP: gestire le date
Concludiamo questa panoramica sulle funzioni di PHP con qualche funzione sulla gestione di date e ore. Prima di cominciare, però, dobbiamo fare un accenno al timestamp, sul quale si basano queste funzioni. Il timestamp è un numero intero, in uso da tempo sui sistemi di tipo UNIX, che rappresenta il numero di secondi trascorsi a partire dal 1° gennaio 1970. Ad esempio, il timestamp relativo alle 15.56.20 del 24 aprile 2003 è 1051192580. Vediamo dunque queste funzioni:
time(): è la più semplice di tutte, perchè fornisce il timestamp relativo al momento in cui viene eseguita. Restituisce un intero (timestamp).
date(formato [,timestamp]): considera il timestamp in input (se non è indicato, prende quello attuale) e fornisce una data formattata secondo le specifiche indicate nel primo parametro. Tali specifiche si basano su una tabella di cui riassumiamo i valori più usati:
Y - anno su 4 cifre
y - anno su 2 cifre
n - mese numerico (1-12)
m - mese numerico su 2 cifre (01-12)
F - mese testuale ('January' - 'December')
M - mese testuale su 3 lettere ('Jan' - 'Dec')
d - giorno del mese su due cifre (01-31)
j - giorno del mese (1-31)
w - giorno della settimana, numerico (0=dom, 6=sab)
l - giorno della settimana, testuale ('Sunday' - 'Saturday' )
D - giorno della settimana su 3 lettere ('Sun' - 'Sat')
H - ora su due cifre (00-23)
G - ora (0-23)
i - minuti su due cifre (00-59)
s - secondi su due cifre (00-59)
La funzione date()
restituisce la stringa formattata che
rappresenta la data.
mktime(ore, minuti, secondi, mese, giorno, anno): è una
funzione molto utile ma che va maneggiata con molta cura, perchè i parametri
che richiede in input (tutti numeri interi) hanno un ordine abbastanza
particolare, che può portare facilmente ad errori. Sulla base di questi
parametri, mktime()
calcola il timestamp, ma l'aspetto più
interessante è che possiamo utilizzarla per fare calcoli sulle date. Infatti,
se ad esempio nel parametro mese passiamo 14, PHP lo interpreterà come 12+2,
cioè "febbraio dell'anno successivo", e quindi considererà il mese come
febbraio ed aumenterà l'anno di 1. Ovviamente lo stesso tipo di calcoli si può
fare su tutti gli altri parametri. Restituisce un intero (timestamp).
checkdate(mese, giorno, anno): verifica se i valori passati costituiscono una data valida. Restituisce un valore booleano.
Vediamo quindi qualche esempio anche per queste funzioni:
$a = mktime(15,56,20,4,24,2003); /* $a riceve il
timestamp del 24/4/2003 alle 15.56.20 */
$b = date('d M y - H:i', $a); //$b sarà "24 Apr 03 -
15:56"
$a = mktime(14,0,0,4,24+60,2003); /* timestamp delle ore
14 di 60 giorni dopo il 24/4/2003 */
$c = checkdate(5,1,2003); //vero
$c = checkdate(19,7,2003); //falso (19 non è un mese)
$c = checkdate(4,31,2003); //falso (31 aprile non esiste)
Le funzioni relative alle date sono diverse. Ecco un elenco preso pari pari dall'help relativo al PHP versione 5:
checkdate -- Validate a
Gregorian date
date_default_timezone_get -- Gets the default timezone used by all
date/time functions in a script
date_default_timezone_set -- Sets the default timezone used by all
date/time functions in a script
date_sunrise -- Returns time of sunrise for a given day and location
date_sunset -- Returns time of sunset for a given day and location
date -- Format a local time/date
getdate -- Get date/time information
gettimeofday -- Get current time
gmdate -- Format a GMT/UTC date/time
gmmktime -- Get Unix timestamp for a GMT date
gmstrftime -- Format a GMT/UTC time/date according to locale settings
idate -- Format a local time/date as integer
localtime -- Get the local time
microtime -- Return current Unix timestamp with microseconds
mktime -- Get Unix timestamp for a date
strftime -- Format a local time/date according to locale settings
strptime -- Parse a time/date generated with strftime()
strtotime -- Parse about any English textual datetime description into a
Unix timestamp
time -- Return current Unix timestamp
Come abbiamo detto nella lezione precedente, oltre alle numerosissime funzioni incorporate in PHP abbiamo la possibilità di definire delle nostre funzioni che ci permettono di svolgere determinati compiti in diverse parti del nostro script, o, meglio ancora, in script diversi, semplicemente richiamando la porzione di codice relativa, alla quale avremo attribuito un nome che identifichi la funzione stessa. Vediamo quindi ora come definire una funzione, fermo restando che, al momento di eseguirla, la chiamata si svolge con le stesse modalità con cui vengono chiamate le funzioni incorporate del linguaggio.
Immaginiamo, facendo il solito esempio banale, di voler costruire una funzione che, dati tre numeri, ci restituisca il maggiore dei tre. Vediamo il codice relativo:
function il_maggiore($num1, $num2, $num3)
{
if (!is_numeric($num1))
return false;
if (!is_numeric($num2))
return false;
if (!is_numeric($num3))
return false;
if ($num1 > $num2)
if ($num1 > $num3)
return $num1;
else
return $num3;
else
if ($num2 > $num3)
return $num2;
else
return $num3;
}
Come vediamo, la definizione della funzione avviene attraverso la
parola chiave function
, seguita dal nome che abbiamo
individuato per la funzione, e dalle parentesi che contengono i parametri (o
argomenti) che devono essere passati alla funzione. Di seguito, contenuto fra
parentesi graffe, ci sarà il codice che viene eseguito ogni volta che la
funzione viene richiamata. Il nome della funzione deve essere necessariamente
univoco, questo significa che non è possibile definire due funzioni aventi lo
stesso nome.
All'interno della funzione noterete l'istruzione return
[...];
questa istruzione è molto importante, perchè termina la funzione
(cioè restituisce il controllo allo script nel punto in cui la funzione è stata
chiamata) e contemporaneamente determina anche il valore restituito dalla
funzione. Nel nostro esempio, i tre dati ricevuti in input vengono controllati,
uno dopo l'altro, per verificare che siano numerici: in caso negativo (il test
infatti viene fatto facendo precedere la funzione is_numeric()
dal
simbolo "!" di negazione), la funzione termina immediatamente, restituendo il
valore booleano FALSE.
Una volta verificato che i tre valori sono numerici, vengono posti a confronto i primi due, e poi quello dei due che risulta maggiore viene posto a confronto col terzo, per ottenere così il maggiore dei tre, che viene infine restituito come risultato della funzione. Quando sarà il momento di eseguire questa funzione potremo quindi usare questo codice:
$a = 9;
$b = 8;
$c = 15;
$m = il_maggiore($a, $b, $c); //$m diventa 15
Avete visto che abbiamo chiamato la funzione usando dei nomi di
variabile diversi da quelli usati nella funzione stessa: la funzione
infatti usa $num1
, $num2
, $num3
, mentre
lo script che la richiama utilizza $a
, $b
, $c
.
È molto importante ricordare che non c'è nessuna relazione definita tra i nomi
degli argomenti che la funzione utilizza e quelli che vengono indicati nella
chiamata. Ciò che determina la corrispondenza fra gli argomenti è, infatti,
semplicemente la posizione in cui vengono indicati: nel nostro caso, quindi,
$a
diventerà $num1
all'interno della funzione,
$b
diventerà $num2
e $c
diventerà $num3
.
Avremmo potuto richiamare la nostra funzione anche passando direttamente i valori interessati, senza utilizzare le variabili:
$m = il_maggiore(9, 8, 15); //$m diventa 15
$m = il_maggiore(9, 8, 'ciao'); /* $m diventa FALSE,
perchè il terzo argomento
non è numerico e quindi i controlli all'inizio della funzione bloccano
l'esecuzione */
Passiamo ora ad un altro argomento molto importante, che è l'ambito (scope)
delle variabili. Infatti, le variabili utilizzate in una funzione esistono solo
all'interno della funzione stessa, mentre non sono definite nè per le altre
funzioni nè nello script principale. Allo stesso modo, le variabili usate dallo
script principale non vengono viste dalle funzioni. Questa è una caratteristica
molto importante del linguaggio, perchè ci permette di definire le funzioni con
la massima libertà nel dare i nomi alle variabili al loro interno, senza doverci
preoccupare che nel nostro script (o in qualche altra funzione) ci siano
variabili con lo stesso nome il cui valore potrebbe risultare alterato. Questo
significa, per tornare all'esempio precedente, che se avessimo scritto
print $num2
all'esterno della funzione il_maggiore()
, non
avremmo ottenuto alcun risultato, e anzi avremmo ricevuto un errore di tipo
notice, in quanto la variabile $num2
, in quell'ambito, non è
definita.
Le variabili utilizzate all'interno di una funzione si chiamano variabili locali. Le variabili utilizzate dallo script principale, invece, sono dette variabili globali.
Normalmente, quindi, se una funzione ha bisogno di un certo dato, è sufficiente includerlo tra i parametri che le dovranno essere passati. Tuttavia, esiste una possibilità per consentire ad una funzione di vedere una variabile globale: si tratta di dichiararla attraverso l'istruzione global.
function stampa($var1, $var2)
{
global $a;
print $a;
}
$a = 'ciao a tutti';
$b = 'buongiorno';
$c = 'arrivederci';
stampa($b, $c);
Questo codice, dopo avere definito la funzione stampa()
, assegna
un valore a tre variabili globali: $a
, $b
e $c
.
Viene poi chiamata la funzione stampa()
, passandole i valori di
$b
e $c
, che nella funzione si chiamano $var1
e $var2
ma che al suo interno non vengono utilizzati. Viene invece
dichiarata la variabile globale $a, che è valorizzata con la stringa 'ciao a
tutti', e quindi questo è ciò che viene stampato a video dall'istruzione print.
Se non ci fosse l'istruzione "global $a", la variabile $a
risulterebbe non definita all'interno della funzione, e quindi la print
genererebbe un errore.
Noi comunque sconsigliamo di utilizzare le variabili globali in questo modo, perchè fanno perdere chiarezza allo script e alla funzione stessa.
Termine della funzione e valore restituito. Abbiamo visto in precedenza che la funzione termina con l'istruzione return, la quale può anche essere utilizzata per restituire un valore. Nel caso in cui non sia scopo della funzione quello di restituire un valore, utilizzeremo semplicemente return. Viceversa, nel caso in cui volessimo restituire più di un valore, siccome la sintassi di PHP ci consente di restituire una sola variabile, potremo utilizzare un array. Vediamo un esempio, immaginando una funzione il cui scopo sia quello di ricevere un numero e di restituire il suo doppio, il suo triplo e il suo quintuplo:
function multipli($num)
{
$doppio = $num * 2;
$triplo = $num * 3;
$quintuplo = $num * 5;
$ris = array($doppio, $triplo, $quintuplo);
return $ris;
}
Con questo sistema siamo riusciti a restituire tre valori da una funzione, pur rispettando la sintassi che ne prevede uno solo. Ovviamente quando richiameremo la funzione dovremo sapere che il risultato riceverà un array:
$a = 7;
$mul = multipli($a); // $mul sarà un array a 3 elementi
Se ci interessa, possiamo anche usare un costrutto del linguaggio per distribuire immediatamente i tre valori su tre variabili distinte:
list($doppio, $triplo, $quintuplo) = multipli($a);
Il costrutto list()
serve ad assegnare i valori di un array
(quello indicato a destra dell'uguale) ad una serie di variabili che gli
passiamo fra parentesi. Ovviamente è possibile utilizzarlo non solo per
"raccogliere" il risultato di una funzione, ma con qualsiasi array:
$arr = array('Marco','Paolo','Luca');
list($primo, $secondo, $terzo) = $arr;
In questo caso, $primo
prenderà il valore 'Marco',
$secondo
il valore 'Paolo', $terzo il valore 'Luca'.
Un'ulteriore precisazione: poco fa abbiamo detto che la funzione termina con
l'istruzione return
. In realtà ciò non è necessario: infatti, nel
caso in cui non ci siano valori da restituire, possiamo anche omettere
l'istruzione return
, e l'esecuzione della funzione terminerà quando
arriverà in fondo al codice relativo, restituendo il controllo allo script
principale (o ad un'altra funzione che eventualmente l'ha chiamata).
In determinate situazioni possiamo prevedere delle funzioni in cui non è obbligatorio che tutti gli argomenti previsti vengano passati al momento della chiamata. Abbiamo visto, infatti, nella lezione precedente, che alcune funzioni di PHP prevedono dei parametri facoltativi. La stessa cosa vale per le funzioni definite da noi: se infatti, al momento in cui definiamo le funzioni, prevediamo un valore di default per un certo parametro, quel parametro diventerà facoltativo in fase di chiamata della funzione, e, nel caso manchi, la funzione utilizzerà il valore di default.
Come esempio consideriamo una funzione che stampa i dati anagrafici di una persona:
function anagrafe($nome, $indirizzo, $cf='non disponibile')
{
print "Nome: $nome<br />";
print "Indirizzo: $indirizzo<br />";
print "Codice fiscale: $cf<br />";
}
Questa funzione prevede tre parametri in input, ma per il terzo è previsto un
valore di default (la stringa 'non disponibile'). Quindi, se la funzione viene
chiamata con soltanto due argomenti, la variabile $cf
avrà proprio
quel valore; se invece tutti e tre gli argomenti vengono indicati, il valore di
default viene ignorato. Vediamo due esempi di chiamata di questa funzione:
anagrafe('Mario Rossi', 'via Roma 2', 'RSSMRA69S12A944X');
anagrafe('Paolo Verdi', 'via Parigi 9');
Nel primo caso otterremo questo output a video:
Nome: Mario Rossi
Indirizzo: via Roma 2
Codice fiscale: RSSMRA69S12A944X
Nel secondo caso:
Nome: Paolo Verdi
Indirizzo: via Parigi 9
Codice fiscale: non disponibile
Nella seconda occasione il codice fiscale non è stato passato, e la funzione ha utilizzato il valore di default.
La principale peculiarità del web dinamico, come abbiamo detto all'inizio di questa guida, è la possibilità di variare i contenuti delle pagine in base alle richieste degli utenti. Questa possibilità si materializza attraverso i meccanismi che permettono agli utenti, oltre che di richiedere una pagina ad un web server, anche di specificare determinati parametri che saranno utilizzati dallo script PHP per determinare quali contenuti la pagina dovrà mostrare. Come esempio, possiamo immaginare una pagina il cui scopo è quello di visualizzare le caratteristiche di un dato prodotto, prelevandole da un database nel quale sono conservati i dati di un intero catalogo. Nel momento in cui si richiama la pagina, si dovrà specificare il codice del prodotto che deve essere visualizzato, per consentire allo script di prelevare dal database i dati di quel prodotto e mostrarli all'utente.
In alcuni casi, i dati che devono essere trasmessi allo script sono piuttosto numerosi: pensiamo ad esempio ad un modulo di registrazione per utenti, nel quale vengono indicati nome, cognome, indirizzo, telefono, casella e-mail ed altri dati personali. In questo caso lo script, dopo averli ricevuti, andrà a salvarli nel database.
In determinate situazioni dobbiamo sapere come in una funzione agiscono le istruzioni di assegnamento ai parametri passati. Ad esempio se considero questo esempio noterò che il parametro $a non viene incrementato ma resta inalterato nonostante all'interno della funzione sia presente l'istruzione di incremento del parametro: $var1++
function Incremento($var1)
{
$var1++; // incremento il parametro
return $var1;
}
$a = 1;
$b = Incremento($a);
echo "\$a=$a - \$b=$b"; // stampa $a=1
- $b=2
Se vogliamo che la nostra funzione Incremento modifichi permanentemente il valore contenuto nel parametro passato è necessario modificare la dichiarazione della funzione in questo modo. Al termine dell'esecuzione della funzione Incremento la variabile $a risulterà incrementata.
function Incremento(&$var1)
{
$var1++; // incremento il parametro
return $var1;
}
$a = 1;
$b = Incremento($a);
echo "\$a=$a - \$b=$b"; // stampa $a=2
- $b=2
Le variabili GET e POST
In questa lezione non ci occuperemo di come vengono salvati o recuperati i dati da un database, ma del modo in cui PHP li riceve dall'utente. Esistono due sistemi per passare dati ad uno script: il metodo GET e il metodo POST.
Il metodo GET consiste nell'accodare i dati all'indirizzo della pagina
richiesta, facendo seguire il nome della pagina da un punto interrogativo e
dalle coppie nome/valore dei dati che ci interessano. Nome e valore sono
separati da un segno di uguale. Le diverse coppie nome/valore sono separate dal
segno '&'. Quindi, immaginando di avere la pagina prodotto.php
che
mostra le caratteristiche di un prodotto passandole il codice e la categoria del
prodotto stesso, diciamo che, per visualizzare i dati del prodotto A7 della
categoria 2, dovremo richiamare la pagina in questo modo:
<a href="prodotto.php?cod=a7&cat=2">
La stringa che si trova dopo il punto interrogativo, contenente nomi e valori
dei parametri, viene detta query string. Quando la pagina prodotto.php viene
richiamata in questo modo, essa avrà a disposizione, al suo interno, le
variabili $_GET['cod']
(con valore 'a7') e $_GET['cat']
(con valore '2'). Infatti i valori contenuti nella query string vengono
memorizzati da PHP nell'array $_GET, che è un array superglobale in quanto è
disponibile anche all'interno delle funzioni.
Quindi, per tornare all'esempio del catalogo, possiamo immaginare di avere
una pagina nella quale mostriamo una tabella con il nome di ogni prodotto su una
riga, e, di fianco, il link che ci permette di visualizzare le caratteristiche
di quel prodotto. In ogni riga, quindi, questo link richiamerà sempre la pagina
prodotto.php
, valorizzando ogni volta i diversi valori di 'cod' e 'cat'.
Il metodo POST viene utilizzato con i moduli: quando una pagina HTML contiene
un tag <form>
, uno dei suoi attributi è method
, che
può valere GET o POST. Se il metodo è GET, i dati vengono passati nella query
string, come abbiamo visto prima. Se il metodo è POST, i dati vengono invece
inviati in maniera da non essere direttamente visibili per l'utente, attraverso
la richiesta HTTP che il browser invia al server.
I dati che vengono passati attraverso il metodo POST sono memorizzati nell'array $_POST. Anche questo array, come $_GET, è un array superglobale. Quindi, per fare un esempio attraverso un piccolo modulo:
<form action="elabora.php" method="post">
<input type="text" name="nome">
<input type="checkbox" name="nuovo" value="si">
<input type="submit" name="submit" value="invia">
</form>
Questo modulo contiene semplicemente una casella di testo che si chiama
'nome' e una checkbox che si chiama 'nuovo', il cui valore è definito come 'sì'.
Poi c'è il tasto che invia i dati, attraverso il metodo POST, alla pagina
elabora.php
.
Questa pagina si troverà a disposizione la variabile $_POST['nome']
,
contenente il valore che l'utente ha digitato nel campo di testo; inoltre, se è
stata selezionata la checkbox, riceverà la variabile $_POST['nuovo']
con valore 'si'. Attenzione però: se la checkbox non viene selezionata
dall'utente, la variabile corrispondente risulterà non definita.
Abbiamo visto quindi, brevemente, in che modo recuperare i dati che gli
utenti ci possono trasmettere. C'è da dire che, modificando l'impostazione
register_globals
su php.ini
, sarebbe possibile anche
recuperare i dati in maniera più semplice. Infatti, se register_globals
è attiva ('on'), oltre agli array visti sopra avremo anche delle variabili
globali che contengono direttamente i valori corrispondenti. Ad esempio, nel
primo esempio avremmo a disposizione la variabile $cod
e la
variabile $cat
, nel secondo avremmo la variabile $nome
e la variabile (eventuale) $nuovo
. Fino a qualche tempo fa, erano
in molti a lavorare in questo modo, perchè il valore di register_globals
,
di default, era attivo, e quindi buona parte dei programmatori PHP, soprattutto
agli inizi, trovavano più naturale utilizzare il sistema più immediato.
A partire dalla versione 4.2.0 di PHP, fortunatamente, il
valore di default di register_globals è stato cambiato in off, e gli
sviluppatori di PHP sconsigliano di rimetterlo ad on per gravi problemi di
sicurezza. Questo perchè, utilizzando gli array superglobali $_GET
e $_POST
, si rende il codice più chiaro e anche più sicuro. Se vi
dovesse capitare di utilizzare degli script già fatti e doveste notare dei
malfunzionamenti, potrebbe dipendere dal fatto che tali script utilizzano le
variabili globali invece degli array superglobali, ed il vostro
register_globals
è a off.
Un'ultima annotazione: gli array $_GET
e $_POST
sono stati introdotti nella versione 4.1.0 di PHP. In precedenza, gli stessi
valori venivano memorizzati negli array corrispondenti $HTTP_GET_VARS
e $HTTP_POST_VARS
, che però non erano superglobali. Questi array
sono disponibili anche nelle versioni attuali di PHP, ma il loro uso è
sconsigliato, ed è presumibile che in futuro scompariranno.
Le variabili superglobali definite automaticamente da PHP non permettono solamente di accedere ai parametri passati alla pagina, ma esistono variabili che permettono di accedere ad altri valori molto importanti.
La variabile $_SERVER
contiene informazioni sul server corrente,
recuperate attraverso Apache o estratte dagli header della pagina valorizzati
dal browser dell'utente che sta navigando. Spesso i valori contenuti in questo
array associativo vengono utilizzati per comprendere da dove proviene una
richiesta, rilevare l'indirizzo IP che identifica il PC da cui l'utente è
acceduto alla nostra pagina oppure conoscere il path di base dell'applicativo.
<?php
foreach ($_SERVER as $Nome => $Valore)
{
echo "\$_SERVER[$Nome] => $Valore<BR>\n";
}
?>
Le variabili $_COOKIE
e $_SESSION
(che verranno
analizzate successivamente in modo più approfondito) contengono rispettivamente
i valori dei cookie e delle sessioni valide per una determinata pagina. I valori
vengono acceduti utilizzando come chiave il nome del cookie/sessione che si
decide interrogare.
La variabile $_FILES
è molto importante perchè contiene
informazioni su tutti i file inviati alla pagina attraverso un form. L'array
$_FILES
ha una struttura (vedere gli esempi sottostanti) che
permette di recuperare il nome del file caricato, le sue dimensioni ed il nome del
file temporaneo salvato su disco sul quale è possibile operare. Vediamo due
esempi: il primo carica un singolo file:
<!-- Il data encoding type,
enctype, DEVE essere specificato così! -->
<?php
if (isset($_FILES["userfile"]))
{
// Costanti di errore:
// UPLOAD_ERR_OK ==> tutto OK
// Valore: 0; Non ci sono errori il file è stato
caricato con successo
// UPLOAD_ERR_INI_SIZE
// Valore: 1; Il file caricato supera il valore
nella direttiva upload_max_filesize nel php.ini.
// UPLOAD_ERR_FORM_SIZE
// Valore: 2; Il file caricato supera il valore
nella direttiva MAX_FILE_SIZE specificata nel form HTML.
// UPLOAD_ERR_PARTIAL
// Valore: 3; Il file è stato caricato solo
parzialmente
// UPLOAD_ERR_NO_FILE
// Valore: 4; nessun file è stato caricato.
// UPLOAD_ERR_NO_TMP_DIR
// Value: 6; Non esiste una cartella per i files
temporanei. Introdotto in PHP 4.3.10 e PHP 5.0.3.
// UPLOAD_ERR_CANT_WRITE
// Value: 7; Non è stato possibile scrivere su
disco. Introdotta in PHP 5.1.0.
if ($_FILES["userfile"]["error"]
== UPLOAD_ERR_OK)
{
$tmp_name = $_FILES["userfile"]["tmp_name"];
$name = $_FILES["userfile"]["name"];
move_uploaded_file($tmp_name, "$name");
$stringa="Ho caricato il file " . $name;
$stringa=$stringa . " di dimensione " . $_FILES["userfile"]["size"];
$stringa=$stringa . " e tipo " . $_FILES["userfile"]["type"];
$stringa=$stringa . " [File temporaneo:" . $tmp_name . "]";
echo $stringa . "<BR>";
}
}
else
{
?>
<!-- The data encoding type, enctype, MUST be
specified as below -->
<form enctype="multipart/form-data" action="" method="POST">
<!-- MAX_FILE_SIZE deve precedere il tipo FILE -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
Invia questo file: <input name="userfile"
type="file" />
<input type="submit" value="Invia il file" />
</form>
<?php
}
?>
Nel secondo vengono caricati 3 files contemporaneamente facendo uso degli array:
<?php
if (isset($_FILES["Immagine"]))
{
foreach ($_FILES["Immagine"]["error"] as $key => $error)
{
if ($error == UPLOAD_ERR_OK)
{
$tmp_name = $_FILES["Immagine"]["tmp_name"][$key];
$name = $_FILES["Immagine"]["name"][$key];
move_uploaded_file($tmp_name, "$name");
$stringa="Il file " . $_FILES["Immagine"]["name"][$key];
$stringa=$stringa . " di
dimensione " . $_FILES["Immagine"]["size"][$key];
$stringa=$stringa . " e
tipo " . $_FILES["Immagine"]["type"][$key];
$stringa=$stringa . "
[File temporaneo:" . $_FILES["Immagine"]["tmp_name"][$key] . "]";
echo $stringa . "<BR>";
}
}
}
else
{
?>
<form action="" method="post" enctype="multipart/form-data">
Immagini:<BR>
File1: <input type="file" name="Immagine[]"><BR>
File1: <input type="file" name="Immagine[]"><BR>
File1: <input type="file" name="Immagine[]"><BR>
<input type="submit" value="Carica i tre files">
</form>
<?php
}
?>
Mantenere lo stato: i cookie
Un cookie è una coppia chiave/valore avente una data di scadenza ed un dominio di validità che viene salvata sul PC dell'utente ed inviata (attraverso appositi header HTTP) ad ogni pagina dalla quale possa essere acceduta.
Grazie ai cookie è possibile identificare con buona sicurezza le credenziali di un utente che accede ad una pagina, oppure salvare dei dati per un successivo recupero. Per esempio si potrebbe salvare su un cookie un valore indicante l'ultima pagina visualizzata, in modo da occuparsi di ridirigere l'utente all'ultima pagina visualizzata nel momento in cui si connettesse nuovamente al nostro sito.
La creazione di un cookie è un'operazione molto semplice, che in PHP può
essere effettuata utilizzando un'unica chiamata alla funzione setcookie()
.
Questa funzione accetta un numero variabile di parametri. Nell'ordine:
Il nome del cookie
Il valore del cookie, che dovrà essere necessariamente un valore scalare (intero o stringa, gli array non possono essere salvati direttamente)
Un numero indicante la data di scadenza del cookie. Nel caso questo numero sia 0 o non specificato, il cookie durerà fino a che l'utente non chiuderà il suo browser. Nel caso in cui il timestamp specificato risulti in una data precedente a quella attuale, il cookie viene cancellato
Il path di validità del cookie
Il dominio di validità del cookie
Un parametro boolean che indica se trasmettere il cookie solamente attraverso una connessione sicura HTTPS
I cookie creati sono disponibili solamente dalla pagina successiva alla loro creazione.
Dato che la funzione setcookie()
genera esplicitamente un header
HTTP, è necessario che prima del suo utilizzo non sia stato stampato (usando
echo
, print
o qualunque altro metodo di output) alcun
valore, altrimenti verrà generato un errore. Anche una riga vuota all'inizio del
file prima del tag di apertura PHP porterà alla generazione di questo errore.
Alcuni esempio di creazione di un cookie:
setcookie('prova_cookie', 'valore cookie', /* dura per un'ora */ time() + 3600);
setcookie('prova_2', 'ciao'); //cookie che dura fino a
che l'utente non chiude il browser
Per cancellare un cookie è necessario utilizzare la stessa funzione specificando gli stessi parametri utilizzati in fase di creazione ma utilizzando una data di scadenza precedente a quella attuale.
setcookie('prova_cookie', '', time() - 3600);
Una volta creato un cookie il suo valore sarà accessibile attraverso $_COOKIE[$nome_cookie]
nelle pagine successive a quella attuale, presupponendo che la data di scadenza
non sia trascorsa e che siano rispettate le restrizioni di dominio e cartella.
Vediamo questo esempio:
// set the cookies
setcookie('prova_2', 'ciao'); //cookie che dura fino a
che l'utente non chiude il browser
setcookie("cookie[three]", "cookiethree");
setcookie("cookie[two]", "cookietwo");
setcookie("cookie[one]", "cookieone");
// dopo il ricaricamento della pagina verrammo stampati
// i valori dei cookies
if (isset($_COOKIE['cookie']))
{
foreach ($_COOKIE['cookie'] as $name => $value)
{
echo "$name : $value <br
/>\n";
}
}
if (isset($_COOKIE['prova_2']))
{
$value=$_COOKIE['prova_2'];
echo "prova_2 : $value <br />\n";
}
È buona norma non creare troppi cookie, dato che i browser hanno un limite
sia relativo ad uno specifico dominio che ad una specifica cartella. In caso
fosse necessario mantenere molti valori, è preferibile salvarli su database o
file e salvare nel cookie una chiave che ne permetta l'accesso nella pagine
successive. I cookie sono facilmente recuperabili e leggibili, quindi è
importante non salvare mai informazioni private o vitali, salvo previa
criptazione.
Mantenere lo stato: le sessioni
Le sessioni permettono anch'esse di mantenere informazioni relative all'utente tra le varie pagine navigate, ma rispetto ai cookie danno la possibilità di salvare arbitrari tipi di dato (non solo stringhe e numeri) e, se PHP è impostato correttamente, di non preoccuparsi dell'identificazione dell'utente.
Quando un utente accede per la prima volta ad una pagina PHP impostata per
creare una sessione, a questi viene associato un ID univoco che verrà utilizzato
da PHP come chiave per recuperare l'array $_SESSION
salvato
specificamente per il determinato utente. L'ID è un codice univoco che, al
momento della creazione della sessione, viene salvato automaticamente da PHP
all'interno di un cookie oppure, se i cookie risultano disabilitati, accodato
agli URL relativi generati dallo script PHP.
In questo modo il programmatore può occuparsi solamente di inizializzare la
sessione e salvare i propri dati. Ovviamente questo comportamento può essere
controllato attraverso le impostazioni del file php.ini
; potrebbe
capitare quindi che il passaggio automatico dell'ID di sessione attraverso gli
URL relativi non sia abilitato. In questo caso PHP ci viene incontro generando
una costante chiamata SID
che contiene la chiave di sessione
preceduta dal nome. Basta accodare questa costante ai nostri URL per avere un
sistema perfettamente funzionante.
L'inizializzazione di una sessione, come già accennato, viene fatta automaticamente da PHP. A noi basterà scrivere:
$_SESSION['nome'] = $valore;
per assicurarci che la variabile di sessione 'nome' abbia il valore assegnato, e che questo valore sia specifico per l'utente che ha appena eseguito la pagina che contiene il codice.
Le sessioni sono un argomento a prima vista molto semplice, ma spesso ci si
trova in situazioni nelle quali è necessario controllare completamente il
comportamento dei processi di salvataggio, lettura, creazione e distruzione
delle sessioni. A questo scopo ci vengono in aiuto una serie di configurazioni
del file php.ini
ed una serie di funzioni aggiuntive che, anche se
non tratterò in questa guida base, consiglio caldamente di studiare ed
analizzare. Ecco un breve esempio:
<?php
session_save_path("."); // cambio la directori di salvataggio dei dati di
sessione
session_start();
// utilizzare $HTTP_SESSION_VARS con PHP 4.0.6 or precedente
if (!isset($_SESSION['count'])) {
$_SESSION['count'] = 0;
} else {
$_SESSION['count']++;
}
echo "La pagina è stata visitata (ID sessione:" . session_id() . ") : " . $_SESSION['count']
. " volte";
?>
Le funzioni relative alle sessioni sono diverse. Ecco un elenco preso pari pari dall'help relativo al PHP versione 5:
session_cache_expire --
Return current cache expire
session_cache_limiter -- Get and/or set the current cache limiter
session_commit -- Alias of session_write_close()
session_decode -- Decodes session data from a string
session_destroy -- Destroys all data registered to a session
session_encode -- Encodes the current session data as a string
session_get_cookie_params -- Get the session cookie parameters
session_id -- Get and/or set the current session id
session_is_registered -- Find out whether a global variable is registered
in a session
session_module_name -- Get and/or set the current session module
session_name -- Get and/or set the current session name
session_regenerate_id -- Update the current session id with a newly
generated one
session_register -- Register one or more global variables with the
current session
session_save_path -- Get and/or set the current session save path
session_set_cookie_params -- Set the session cookie parameters
session_set_save_handler -- Sets user-level session storage functions
session_start -- Initialize session data
session_unregister -- Unregister a global variable from the current
session
session_unset -- Free all session variables
session_write_close -- Write session data and end session
Accedere ai file
Uno degli aspetti fondamentali della programmazione è quello di poter accedere a fonti di dato esterne al fine di recuperare o salvare delle informazioni utili ai fini della nostra applicazione. PHP, come tutti i linguaggi di programmazione, fornisce una ricca libreria per l'accesso ai file ed alle risorse presenti sul server. Con l'avvento di PHP 5, è stato aggiunto anche il supporto a particolari tipi di risorse, chiamate stream, in modo che sia possibile accedere a qualunque tipo di fonte come se si stesse accedendo ad un file (un po' come accade in Linux, dove la maggior parte dei sistemi di input/output hardware possono essere letti e scritti come se fossero file).
Le operazioni principali sui file sono essenzialmente quelle di lettura, scrittura e posizionamento (PHP fornisce moltissime operazioni ausiliarie per gestire completamente i file, come operazioni per l'eliminazione e la prova d'esistenza, che analizzeremo in modo più approfondito in seguito). La maggior parte delle operazioni effettuate sui file avvengono applicando delle funzioni che accettano come parametro una risorsa che rappresenta il file. La risorsa (recuperata con fopen, come vedremo in seguito) è un tipo di dato speciale gestito internamente da PHP, che serve al motore del linguaggio di programmazione come indicativo per delle informazioni a basso livello richieste per il corretto funzionamento della libreria utilizzata.
Vediamo un piccolo esempio:
<?php
//Presuppongo che la directory corrente abbia i
permessi corretti
$fp = fopen('prova.txt', 'w+'); //Apro il file prova.txt
in lettura, lo creo se non esiste
fwrite($fp, "ciao a tutti, come va?"); //Scrivo una
stringa sul file
fclose($fp); //Chiudo il file aperto precedentemente
?>
Il programma precedente è molto semplice: crea un file prova.txt
,
vi scrive dentro "ciao a tutti, come va?" e lo chiude. L'operazione di apertura
di un file avviene attraverso la funzione fopen
che accetta, nella
sua forma base, due parametri: il primo rappresenta il percorso (path) del file
sul quale vorremmo operare. Il secondo è una stringa che indica alla funzione
quali sono le operazioni che si desiderano svolgere sul file. Per una lista
dettagliata di queste rimando alla documentazione ufficiale, ma le più
importanti sono:
'r' Apre in sola lettura. Posiziona il puntatore all'inizio del file.
'r+' Apre in lettura e scrittura. Posiziona il puntatore all'inizio del file.
'w' Apre il file in sola scrittura. Posiziona il puntatore all'inizio del file e tronca il file alla lunghezza zero. Se il file non esiste, tenta di crearlo.
'w+' Apre in lettura e scrittura. Posiziona il puntatore all'inizio del file e tronca il file alla lunghezza zero. Se il file non esiste, tenta di crearlo.
'a' Apre in sola scrittura. Posiziona il puntatore alla fine del file. Se il file non esiste, tenta di crearlo.
'a+' Apre in lettura e scrittura. Posiziona il puntatore alla fine del file. Se il file non esiste, tenta di crearlo.
Come è possibile notare dalla descrizione dei parametri elencati
precedentemente, si fa riferimento al puntatore di un file. Il puntatore non è
altro che un indicatore numerico che specifica la posizione attuale all'interno
del file dalla quale verranno eseguite le operazioni richieste. Il
posizionamento del puntatore avviene tramite la funzione fseek
, che
accetta come parametri la risorsa del file, un numero di byte, ed una costante
che indica se il numero di byte è assoluto (SEEK_SET), se deve essere aggiunto
alla posizione corrente (SEEK_CUR) oppure se deve essere aggiunto alla fine del
file (SEEK_END).
Un semplice esempio per chiarire:
<?php
// Apro il file prova.txt in scrittura e lo riempio con 10 righe di testo
$fp = fopen("prova.txt", "w+");
for($i = 0; $i < 10; ++$i)
{
fwrite($fp, "Stringa di prova numero: " . $i . "\n");
}
fclose($fp);
// Ora apro il file in lettura, mi muovo al suo interno, e stampo parti di
contenuto
$fp = fopen("prova.txt", "r");
fseek($fp, 10, SEEK_SET); //Mi posiziono al 10° carattere
$prova = fread($fp, 20); //Leggo 20 caratteri partendo dalla posizione
corrente
echo "mi sono posizionato sul 10 carattere e ho letto 20 caratteri: <BR>";
echo $prova;
echo "<br />";
echo "La posizione del puntatore all'interno del file è: ".ftell($fp);
fclose($fp);
?>
Nel codice precedente ho aperto in scrittura prova.txt
e l'ho
riempito un file con 10 righe di testo. Poi, dopo averlo chiuso, l'ho nuovamente
aperto in lettura, ho spostato il puntatore di 10 posizioni, ho letto 20
caratteri con la funzione fread ed ho stampato la stringa letta seguita dalla
nuova posizione del puntatore (10 + 20 = 30). La funzione ftell accetta
solamente la risorsa rappresentante il file e restituisce la posizione del
puntatore al suo interno, mentre la funzione fread accetta come secondo
parametro il numero di byte da leggere. Dopo la lettura il puntatore verrà
spostato del numero di byte specificato. Giocate un po' con queste funzioni per
capirne il corretto funzionamento. Le funzioni associate al file system sono
numerose. Ecco l'elenco di quelle presenti in PHP 5 copiate pari pari senza
alcuna traduzione
basename -- Returns
filename component of path
chgrp -- Changes file group
chmod -- Changes file mode
chown -- Changes file owner
clearstatcache -- Clears file status cache
copy -- Copies file
delete -- See unlink() or unset()
dirname -- Returns directory name component of path
disk_free_space -- Returns available space in directory
disk_total_space -- Returns the total size of a directory
diskfreespace -- Alias of disk_free_space()
fclose -- Closes an open file pointer
feof -- Tests for end-of-file on a file pointer
fflush -- Flushes the output to a file
fgetc -- Gets character from file pointer
fgetcsv -- Gets line from file pointer and parse for CSV fields
fgets -- Gets line from file pointer
fgetss -- Gets line from file pointer and strip HTML tags
file_exists -- Checks whether a file or directory exists
file_get_contents -- Reads entire file into a string
file_put_contents -- Write a string to a file
file -- Reads entire file into an array
fileatime -- Gets last access time of file
filectime -- Gets inode change time of file
filegroup -- Gets file group
fileinode -- Gets file inode
filemtime -- Gets file modification time
fileowner -- Gets file owner
fileperms -- Gets file permissions
filesize -- Gets file size
filetype -- Gets file type
flock -- Portable advisory file locking
fnmatch -- Match filename against a pattern
fopen -- Opens file or URL
fpassthru -- Output all remaining data on a file pointer
fputcsv -- Format line as CSV and write to file pointer
fputs -- Alias of fwrite()
fread -- Binary-safe file read
fscanf -- Parses input from a file according to a format
fseek -- Seeks on a file pointer
fstat -- Gets information about a file using an open file pointer
ftell -- Tells file pointer read/write position
ftruncate -- Truncates a file to a given length
fwrite -- Binary-safe file write
glob -- Find pathnames matching a pattern
is_dir -- Tells whether the filename is a directory
is_executable -- Tells whether the filename is executable
is_file -- Tells whether the filename is a regular file
is_link -- Tells whether the filename is a symbolic link
is_readable -- Tells whether the filename is readable
is_uploaded_file -- Tells whether the file was uploaded via HTTP POST
is_writable -- Tells whether the filename is writable
is_writeable -- Alias of is_writable()
lchgrp -- Changes group ownership of symlink
lchown -- Changes user ownership of symlink
link -- Create a hard link
linkinfo -- Gets information about a link
lstat -- Gives information about a file or symbolic link
mkdir -- Makes directory
move_uploaded_file -- Moves an uploaded file to a new location
parse_ini_file -- Parse a configuration file
pathinfo -- Returns information about a file path
pclose -- Closes process file pointer
popen -- Opens process file pointer
readfile -- Outputs a file
readlink -- Returns the target of a symbolic link
realpath -- Returns canonicalized absolute pathname
rename -- Renames a file or directory
rewind -- Rewind the position of a file pointer
rmdir -- Removes directory
set_file_buffer -- Alias of stream_set_write_buffer()
stat -- Gives information about a file
symlink -- Creates a symbolic link
tempnam -- Create file with unique file name
tmpfile -- Creates a temporary file
touch -- Sets access and modification time of file
umask -- Changes the current umask
unlink -- Deletes a file
Utilizzare SQLite
Per molti anni PHP è stato affiancato al database MySQL. Possiamo quasi dire che la loro crescita è stata parallela ed ha portato grossi miglioramenti nel campo delle applicazioni web opensource. Per molto tempo quindi con PHP è stato fornito nativamente il supporto alle librerie per l'accesso a MySQL. Purtroppo il cambio di licenza di quest'ultimo ha obbligato gli sviluppatori a rimuovere il supporto nativo per MySQL (anche se la libreria è sempre in evoluzione e distribuita).
Al fine di aiutare comunque coloro che necessitano di un database ma hanno solamente accesso alla configurazione minima di PHP, gli sviluppatori hanno deciso di implementare nativamente il supporto ad un altro sistema di database: SQLite. Questo sistema, (abbiamo un ampio approfondimento al link: http://database.html.it/articoli/leggi/895/sqlite-miniguida-alluso/, si differenzia molto da MySQL dato che non si basa su un'architettura client server ed è stato sviluppato appositamente per permettere l'accesso molto veloce ai dati. I database creati sono contenuti in un unico file binario (possono anche essere creati database temporanei salvati in memoria) che può essere acceduto tramite le funzioni fornite dalla libreria per eseguirvi query SQL.
La libreria SQLite fornisce un'interfaccia sia ad oggetti sia procedurale. Dato che il compito di questa guida introduttiva non comprende la trattazione delle programmazione ad oggetti, ci occuperemo dell'interfaccia a funzioni. Per chi fosse interessato a MySQL rimandiamo alla guida
Per operare su un database è necessario recuperare una risorsa (un po' come abbiamo visto precedentemente per i file) e lavorare su questa con delle funzioni apposite. La risorsa connessa ad un database può essere recuperata utilizzando sqlite_open:
$sq = sqlite_open("miodb.db", 0666, $sqlite_error);
Il primo parametro è il nome del file che conterrà i nostri dati (se non
esiste verrà creato), il secondo indica i permessi da associare al database
(attualmente il parametro viene ignorato da SQLite anche se l'impostazione
consigliata è 0666) mentre il terzo conterrà eventualmente una stringa con il
messaggio di errore eventualmente riscontrato durante l'apertura della fonte di
dati. In caso sia andato tutto per il verso giusto, $sq
conterrà la
risorsa che ci permetterà di accedere al database miodb.db
,
altrimenti assumerà un valore nullo. Per questo motivo è sempre buona prassi
controllare il valore restituito da sqlite_open
prima di
proseguire.
Per effettuare una query sul database possiamo utilizzare la funzione
sqlite_query
, ed analizzare il risultato eventualmente ottenuto (per
esempio in caso di operazioni di selezione) attraverso sqlite_fetch_array
.
Un semplice esempio:
$sq = sqlite_open("miodb.db", 0666, $sqlite_error);
if(!$sq)
{
die("Errore Sqlite: ".$sqlite_error);
}
sqlite_query($sq, "CREATE TABLE prova_tbl (campo varchar(10))");
for($i = 0; $i < 10; ++$i)
{
sqlite_query($sq, "INSERT INTO prova_tbl VALUES ('Prova ".$i."')");
}
$result = sqlite_query($sq, "SELECT * FROM prova_tbl");
while($data = sqlite_fetch_array($result))
{
echo $data['campo']."<br />";
}
sqlite_close($sq);
Nel codice precedente ci siamo connessi al database, abbiamo controllato che
non ci fossero errori ed abbiamo eseguito delle query sulla risorsa recuperata.
La prima query ha creato una tabella di nome prova_tbl
con un campo
di nome "campo"; la seconda, eseguita all'interno di un ciclo, si è occupata di
inserire dieci valori nella tabella mentre la terza ha recuperato tutti questi
valori. All'interno del ciclo while abbiamo recuperato una dopo l'altra le
singole righe selezionate ed abbiamo stampato i valori del campo "campo". Come
possiamo notare la funzione sqlite_fetch_array restituisce la prossima riga
selezionata oppure FALSE nel caso in cui quella precedente fosse l'ultima.
Come è stato possibile notare da questa breve introduzione, SQLite si comporta in modo molto simile ad un database relazionale, con la differenza che non opera in un'architettura client / server e permette l'esecuzione di query molto semplici e compatte.
Una funzionalità molto interessante della libreria, che mi sento di dover trattare prima di chiudere, è quella che permette di registrare delle funzioni PHP da richiamare all'interno delle proprie query SQL. Vediamo un semplice esempio:
function trim_upper($string)
{
return strtoupper(trim($string));
}
$sq = sqlite_open("miodb.db", 0666, $sqlite_error);
if(!$sq)
{
die("Errore Sqlite: ".$sqlite_error);
}
sqlite_create_function($sq, "trimup", "trim_upper", 1);
$result = sqlite_query($sq, "SELECT trimup(campo) AS campo FROM prova_tbl");
while($data = sqlite_fetch_array($result))
{
echo $data['campo']."<br />";
}
sqlite_close($sq);
Il codice accede al database che abbiamo creato precedentemente e recupera
tutte le righe applicando direttamente da SQL la funzione trim_upper
(che elimina gli spazi all'inizio ed alla fine e rende la stringa maiuscola) al
campo selezionato. La funzione viene registrata attraverso
sqlite_create_function
che accetta come parametri la risorsa
rappresentante il database, il nome da utilizzare all'interno dell'SQL per
richiamare la funzione passata come terzo argomento ed infine il numero di
parametri accettati. Grazie a questa interessante funzionalità si può estendere
il linguaggio SQL utilizzato da SQLite con un insieme di funzioni adatte a
compiere le operazioni più ripetitive sui dati, al fine di rendere il codice più
ordinato e pulito.
Interrogare database MySQL
In PHP 5 abbiamo diverse soluzioni per connetterci ai database. Uno dei database più utilizzati in ambito opensource è sicuramente MySQL, che conta dalla sua una larga schiera di sviluppatori e supporters. In PHP 5 possiamo accedere a MySQL attraverso i layer di astrazione distribuiti nella release standard (PDO ed SDO), ma anche utilizzando la libreria mysql (quella utilizzata anche nella versione precedente di PHP) e la nuova libreria mysqli che fornisce un supporto più completo al linguaggio ed espone un'interfaccia ad oggetti.
Date lo modifiche apportate al linguaggio che puntano a muovere il paradigma di programmazione tipico di PHP da strutturato ad oggetti, mi pare una buona scelta imparare a conoscere la libreria mysqli utilizzando la sua interfaccia a classi piuttosto che basarsi sull'approccio a funzioni.
La connessione ad un database mysql prevede la creazione di un oggetto mysqli tramite il quale effettueremo le nostre operazioni di interrogazione e gestione del database:
<?php
$mysqli = new mysqli('host', 'username', 'password', 'dbname');
// ... eseguiamo le nostre operazioni ...
$mysqli->close();
?>
Una volta istanziato un oggetto mysqli possiamo operare su di esso:
<?php
// ... connessione
$mysqli->autocommit(true);
$mysqli->query("
CREATE TABLE test (
id INT UNSIGNED AUTO_INCREMENT NOT NULL,
title VARCHAR(32) NOT NULL,
content TEXT NOT NULL,
PRIMARY KEY(id)
);
");
// Inseriamo qualche informazione
for($i = 0; $i < 1000; ++$i)
{
$query = sprintf("INSERT INTO test (title, content) VALUES ('%s', '%s')",
"Titolo ".$i, "Contenuto di prova ".$i);
$mysqli->query($query);
}
// Selezioniamo e stampiamo le righe inserite
$result = $mysqli->query("SELECT * FROM test", MYSQLI_USE_RESULT);
while($row = $result->fetch_assoc())
{
printf("<h3>%s</h3><p>%s</p><hr />", $row['title'], $row['content']);
}
$result->close();
// ....
?>
I metodi utilizzati nell'esempio precedente sono i seguenti:
void autocommit(bool): permette di impostare l'oggetto in modo che richiami automaticamente il metodo commit() dopo aver effettuato una query. In caso sia impostato a false e si stia operando su tabelle che supportano le transizioni, è necessario richiamare commit manualmente per applicare le modifiche apportate dalle query;
mixed query(string[, int]): esegue una query SQL sul
database utilizzato. Il risultato restituito dipende dalla tipologia di query
eseguita: nel caso la query SELECT, SHOW, EXPLAIN
o
DESCRIBE
viene restituito un oggetto (di cui analizzeremo le proprietà
successivamente) altrimenti viene restituito true in caso di query eseguita
correttamente, false in caso contrario. Il secondo parametro passato al metodo
può essere la costante MYSQLI_USE_RESULT
o
MYSQLI_STORE_RESULT
: la seconda è quella impostata di default e viene
utilizzata per effettuare il buffering dei dati recuperati attraverso la query;
invece nel caso si utilizzi la prima costante i dati non sono bufferizzati;
Come accennato le chiamate al metodo query possono restituire un oggetto nel caso in cui la query eseguita preveda un risultato diverso dalle informazioni sulla sua corretta esecuzione. Questo oggetto è un'istanza della classe mysqli_result, ed espone metodi per iterare sui risultati. Vediamo i più interessanti:
proprietà num_rows: restituisce il numero delle righe contenute nel buffer o nel risultato SQL;
array fetch_assoc(): restituisce il successivo risultato sotto forma di un array avente come chiavi i nomi dei campi recuperati e come valori i rispettivi valori. In caso l'iterazione sia terminata viene restituito NULL;
array fetch_row(): opera come fetch_assoc ma utilizza indici numerici per identificare i risultati;
array fetch_array(): restituisce un array che contiene sia indici numerici che stringhe per recuperare i valori;
object fetch_field(): restituisce un oggetto che contiene le informazioni sui campi recuperati dalla query;
Nel caso si utilizzi fetch_field l'oggetto restituito espone le seguenti proprietà:
name: il nome della colonna;
orgname: il nome originale della colonna nel caso sia stato specificato un alias;
table: il nome della tabella a cui appartiene il campo, a meno che questo non sia calcolato (come nel caso di "SELECT (1+1) AS test" per esempio);
orgtable: il nome originale della tabella nel caso in cui
sia stato specificato un alias;
def: il valore di default di questo campo, rappresentato come una stringa;
max_length: la lunghezza massima del campo;
flags: un intero che rappresenta i flag associati al campo;
type: il tipo di dato utilizzato per il campo;
decimals: il numero di decimali utilizzati (solo nel caso di campi numerici);
Dopo questa introduzione, possiamo passare ad analizzare uno degli aspetti più interessanti della libreria mysqli, i prepared statement. Normalmente quando il database esegue una query, effettua prima una compilazione di quest'ultima e poi esegue il codice compilato. Questa operazione viene normalmente effettuata ogni volta che una query viene eseguita, anche nel caso di chiamate successive a query molto simili. I prepared statement permettono di precompilare una query lasciando dei campi variabili: quando la query dovrà essere eseguita potranno essere assegnati solo questi campi e non si dovrà procedere con l'intera compilazione, guadagnando molto in performance.
Vediamo come si prepara ed utilizza un prepared statement:
<?php
// ... connessione
$search = '';
$stmt = $mysqli->prepare("SELECT id, title FROM test WHERE title LIKE ?");
$stmt->bind_param('s', $search);
for($i = 0; $i < 5; ++$i)
{
$search = '%'.$i.'%';
$stmt->execute();
$stmt->bind_result($id, $title);
echo "<h3>",$i,"</h3>";
while($stmt->fetch())
{
printf("<strong>%d</strong><span>%s</span><br />", $id, $title);
}
$stmt->free_result();
}
$stmt->close()
// ...
?>
Utilizzando il metodo prepare dell'oggetto mysqli possiamo creare un prepared
statement, rappresentato da un'istanza della classe mysqli_stmt. La query
passata come argomento può contenere una serie di punti di domanda nei posti in
cui successivamente inseriremo i valori. I punti di domanda possono essere
inseriti solamente nelle posizioni in cui la query SQL si aspetterebbe dei
valori (come quelli degli INSERT
, gli assegnamenti di UPDATE
o i valori delle condizioni della clausola WHERE
). Una volta
preparato l'oggetto possiamo operarvi utilizzando i suoi metodi:
void bind_param(string, ...): associa una o più variabili ai singoli placeholder specificati nella query precompilata. Il primo argomento è una stringa di cui ogni singolo carattere rappresenta il tipo di dato in cui convertire i valori contenuti nelle variabili connesse. I caratteri utilizzabili sono i per gli interi, d per i double, s per le stringhe e b per i blob. I restanti parametri sono i nomi delle variabili che vogliamo connettere.
bool execute(): esegue un prepared statement salvando gli eventuali risultati recuperati in un buffer interno ed estraendo i valori dei placeholder dalle variabili connesse;
void bind_result(...): associa i singoli campi recuperati dalla query a delle variabili. I valori di queste variabili saranno aggiornati ad ogni chiamata effettuata al metodo fetch;
bool fetch(): passa al record successivo assegnando i valori dei campi recuperati alle variabili connesse. Se non c'è alcun record restituisce false;
La configurazione di PHP
Come molti altri strumenti di sviluppo PHP può essere configurato attraverso un file di configurazione che definisce e guida il comportamento delle zend engine e delle sue estensioni. Le proprietà di configurazione possono essere assegnate e modificate in vari modi, che analizziamo brevemente; va anticipato che alcune proprietà possono essere modificate solamente in alcuni contesti, solitamente per motivi di sicurezza.
La prima soluzione è apportare manualmente le modifiche al file php.ini presente nella directory di configurazione di PHP. Ogni volta che si apportano modifiche a questo file è necessario riavviare l'interprete (solitamente riavviando il webserver di supporto) e spesso il file, per motivi di sicurezza, risulta protetto da modifiche da parte degli utenti che usufruiscono di servizi hosting.
Il formato del file di configurazione di PHP è molto semplice e segue gli standard utilizzati da altri strumenti opensource:
Vengono saltate tutte le righe vuote o precedute da un punto e virgola;
Le proprietà sono definite da una serie di caratteri senza spazi;
Ogni riga definisce un'operazione di assegnamento (utilizzando l'operatore uguale);
I valori possono essere numeri, costanti interne, stringhe o altre espressioni valide interpretate dal motore;
La seconda soluzione possibile, optabile solamente nel caso in cui PHP giri
come modulo del webserver Apache, è sfruttare gli strumenti di
configurazione del webserver stesso per modificare il comportamento di
PHP. Attraverso la direttiva php_flag
possiamo impostare ad On o
Off i valori di una variabile di configurazione di PHP; in caso i valori di una
variabile siano valori differenti dal booleano è possibile utilizzare php_value:
php_value error_reporting E_ALL
php_flag register_globals Off
Se il webserver e PHP sono preconfigurati correttamente, le direttive possono essere specificate sia in un file .htaccess che all'interno del file http.conf, magari sfruttando la possibilità di definire comandi in base alla directory.
L'ultima opzione possibile è quella di modificare i valori direttamente
all'interno del proprio codice PHP sfruttando la funzione
ini_set
(con ini_get
possiamo recuperare i valori assegnati o specificati
con i parametri di configurazione):
<?php
ini_set('include_path', ini_get('include_path').':../includes:');
?>
Ovviamente alcune direttive non ha senso siano impostate all'interno del codice, come ad esempio quelle che operano sui dati in ingresso.
Vediamo ora alcuni parametri di configurazione che controllano il comportamento del motore di PHP:
allow_call_time_pass_reference(boolean): Abilita o meno la possibilità di forzare gli argomenti delle funzioni ad essere passati per riferimento. Questo parametro non è consigliato e potrebbe non essere più supportato nelle versioni future di PHP/Zend. Si incoraggia il metodo di specificare quale parametro debba essere passato per riferimento al momento della dichiarazione della funzione. Si suggerisce di impostare l'opzione a off per essere certi che lo script funzioni correttamente con questa impostazione, in modo da predisporsi ad eventuali modifiche future del linguaggio (si riceverà un warning ogni volta che si utilizza questa opzione e i valori saranno passati per valore anzichè per riferimento). Passare i valori per riferimento al momento della chiamata della funzione viene sconsigliato per motivi di chiarezza del codice. La funzione può modificare il parametro in modo non previsto se non indica questo come passato per riferimento. Per evitare effetti secondari inattesi, è meglio indicare soltanto al momento della dichiarazione della funzione quali parametri saranno passati per riferimento.
short_open_tag(boolean): Indica se abilitare o meno la forma
abbreviata dei tag di apertura del PHP (<? ?>
). Se si desidera
utilizzare il PHP in combinazione con l'XML, occorre disabilitare questa opzione
per potere abilitare la riga <?xml ?>
. In alternativa occorre
stampare il testo con il PHP, ad esempio: <?php echo '<?xml
version="1.0"'; ?>. Inoltre, se disabilitato, occorre utilizzare la
versione lunga dei tag di apertura del PHP (<?php ?>
). Questo
parametro influisce anche su <?=
, la quale è identica a <?
echo
. L'uso di questa abbreviazione richiede l'abilitazione di
short_open_tag
. È ormai buona norma disabilitare la forma abbreviata ed
utilizzare quella estesa, quindi è consigliabile impostare a Off questo valore.
memory_limit(integer): Questo parametro imposta la dimensione massima in byte di memoria occupabile dallo script. Questo aiuta a impedire che script scritti male utilizzino tutta la memoria del server. Per potere utilizzare questo parametro occorre abilitarlo al momento della compilazione. Pertanto occorrerà includere nella configurazione la linea: --enable-memory-limit. Si noti che occorre impostare il parametro a -1 se non si desidera impostare limiti di memoria.
post_max_size(integer): Imposta la dimensione massima dei dati post. Questa impostazione influenza anche gli upload dei file. Per permettere upload di file di grandi dimensioni, il valore impostato deve essere maggiore di upload_max_filesize. Anche il limite di memoria, memory_limit, se abilitato, può limitare gli upload di file. In termini generali memory_limit dovrebbe essere maggiore di post_max_size. Il valore assegnabile è soggetto alle regole sintattiche del file PHP.ini, quindi è possibile utilizzare delle abbreviazioni per specificare megabyte o gigabyte di dati: 20M o 1G. Se la dimensione dei dati post è maggiore di post_max_size, le variabili superglobale $_POST e $_FILES sono vuote. Questo può essere rilevato in diversi modi, ad esempio passando una variabile $_GET allo script che processa i dati, tipo <form action="edit.php?processed=1">, e verificare se $_GET['processed'] è impostata.
include_path(string): Elenco di directory in cui le funzioni require(), include() e fopen_with_path() cercheranno i files. Il formato è tipo la variabile d'ambiente PATH: una lista di directory separate da due punti in Unix, punto e virgola in Widnows. L'uso di . nel percorso di include indica, negli include relativi, la directory corrente.
extension_dir(string): Directory in cui il PHP cerca i moduli caricabili dinamicamente.
extension(string): Specifica quale modulo dinamico caricare quando viene avviato l'interprete PHP;
upload_tmp_dir(string): Directory temporanea utilizzata per il transito dei file durante l'upload. Deve avere i permessi di scrittura per gli utenti utilizzati dal PHP per girare. Se non indicata il PHP utilizzerà il default di sistema.
upload_max_filesize(integer): La dimensione massima di un file inviato. Il valore assegnabile è soggetto alle regole sintattiche del file PHP.ini, quindi è possibile utilizzare delle abbreviazioni per specificare megabyte o gigabyte di dati: 20M o 1G.
Alcune volte potrebbe capitare di dover specificare opzioni relative alle singole estensioni utilizzate all'interno dell'interprete PHP. Quando una proprietà è specifica di un determinato contesto questa viene preceduta dal nome che identifica questo contesto seguito da un punto. Vediamo alcune delle direttive contestuali utili:
output_buffering(boolean): è possibile abilitare il buffering automatico dell'output per tutti i file settando la direttiva ad On. È possibile anche limitare le dimensioni del buffer ad una dimensione predefinita, impostando la proprietà ad un intero;
output_handler(string): è possibile inviare tutto l'output bufferizzato ad una funzione che si occupi di effettuarne delle trasformazioni. La direttiva output_handler permette di specificare il nome della funzione da utilizzare di default prima di restituire l'output. Per esempio è possibile impostare il valore a ob_gzhandler per comprimere l'output, oppure a mb_output_handler per modificare automaticamente la codifica dei dati in uscita;
SMTP(string): Usato solo sotto Windows: Nome DNS o indirizzo IP del server SMTP che PHP deve usare per spedire posta elettronica con la funzione mail();
smtp_port(int): Usato solo sotto Windows: Numero della porta del server specificato da SMTP al quale connettersi quando si inviano email usando mail(); il valore predefinito è 25.
sendmail_from(string): Quale campo "From:" devono avere i messaggi inviati da PHP sotto Windows.
sendmail_path(string): Dove trovare il programma sendmail, solitamente /usr/sbin/sendmail oppure /usr/lib/sendmail. configure cerca di trovare il file e lo imposta di default, ma se non riesce a localizzarlo, lo si può impostare qui. I sistemi che non usano sendmail devono impostare questa direttiva al wrapper che i rispettivi sistemi di posta offrono, se esistenti. Per esempio, gli utenti di Qmail possono normalmente impostarla a /var/qmail/bin/sendmail o /var/qmail/bin/qmail-inject. qmail-inject non necessita di nessuna opzione al fine di processare correttamente la mail. Questi parametri funzionano anche su Windows. Se si impostate smtp, smtp_port e sendmail_from saranno ignorate e verrà eseguito il comando indicato.
Vi sono moltissime altre proprietà con le quali è possibile ottenere un ottimo controllo del comportamento del motore di PHP, quindi è sempre buona norma consultare la documentazione ufficiale per comprendere come controllare le tecnologie che si intende utilizzare