Skip to content

3. Le basi di PHP

3.1. La struttura ad albero degli script

Image

3.2. Configurazione di PHP

PHP viene fornito preconfigurato tramite un file di testo denominato [php.ini]. Tutte queste impostazioni possono essere modificate tramite programmazione. La configurazione di PHP influisce notevolmente sull’esecuzione degli script. È quindi importante conoscerla. Lo script seguente, [phpinfo.php], lo consente:

1
2
3
<?php

phpinfo();

Commenti

  • riga 3: la funzione [phpinfo] visualizza la configurazione di PHP;

Risultati dell’esecuzione

"C:\myprograms\laragon-lite\bin\php\php-7.2.11-Win32-VC15-x64\php.exe" "C:\Data\st-2019\dev\php7\php5-exemples\exemples\tests\phpinfo.php"
phpinfo()
PHP Version => 7.2.11

System => Windows NT DESKTOP-528I5CU 10.0 build 17134 (Windows 10) AMD64
Build Date => Oct 10 2018 01:57:32
Compiler => MSVC15 (Visual C++ 2017)
Architecture => x64
Configure Command => cscript /nologo configure.js  "--enable-snapshot-build" "--enable-debug-pack" "--with-pdo-oci=c:\php-snap-build\deps_aux\oracle\x64\instantclient_12_1\sdk,shared" "--with-oci8-12c=c:\php-snap-build\deps_aux\oracle\x64\instantclient_12_1\sdk,shared" "--enable-object-out-dir=../obj/" "--enable-com-dotnet=shared" "--without-analyzer" "--with-pgo"
Server API => Command Line Interface
Virtual Directory Support => enabled
Configuration File (php.ini) Path => C:\windows
Loaded Configuration File => C:\myprograms\laragon-lite\bin\php\php-7.2.11-Win32-VC15-x64\php.ini
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)
Done.

La funzione [phpinfo] mostra qui più di 800 righe di configurazione. Non le commenteremo perché la maggior parte riguarda un utilizzo avanzato di PHP. Una riga importante è la riga 13 sopra riportata: indica quale file [php.ini] è stato utilizzato per configurare il PHP che userete per eseguire i vostri script. Se desiderate modificare la configurazione di esecuzione di PHP, è questo il file che dovete modificare. In questo file sono presenti numerosi commenti che spiegano il ruolo delle diverse configurazioni.

3.3. Un primo esempio

3.3.1. Il codice

Di seguito è riportato un programma [bases-01.php] che presenta le prime caratteristiche di PHP.


<?php

// questo è un commento
// variabile utilizzata senza essere stata dichiarata
$nom = "dupont";
// un messaggio a schermo
print "nom=$nom\n";
// un array con elementi di tipo diverso
$tableau = array("un", "deux", 3, 4);
// il numero dei suoi elementi
$n = count($tableau);
// un ciclo
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// inizializzazione di 2 variabili con il contenuto di un array
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// concatenazione delle 2 stringhe
$chaine3 = $chaine1 . $chaine2;
// visualizzazione del risultato
print "[$chaine1,$chaine2,$chaine3]\n";
// utilizzo di una funzione
affiche($chaine1);
// il tipo di una variabile può essere noto
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// il tipo di una variabile può cambiare durante l'esecuzione
$n = "a changé";
afficheType("n", $n);
// una funzione può restituire un risultato
$res1 = f1(4);
print "res1=$res1\n";
// una funzione può restituire un array di valori
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// si sarebbero potuti recuperare questi valori in un array
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// test
for ($i = 0; $i < count($t); $i++) {
  // visualizza solo le stringhe
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// operatori di confronto == e ===
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// altri test
for ($i = 0; $i < count($t); $i++) {
  // visualizza solo i numeri interi >10
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// un ciclo while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//mentre
print "somme=$somme\n";

// fine programma
exit;

//----------------------------------
function affiche($chaine) {
  // visualizza $chaine
  print "chaine=$chaine\n";
}

//visualizza
//----------------------------------
function afficheType($name, $variable) {
  // visualizza il tipo di $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}

//afficheType
//----------------------------------
function f1($param) {
  // aggiunge 10 a $param
  return $param + 10;
}

//----------------------------------
function f2() {
  // restituisce 3 valori
  return array("un", 0, 100);
}
?>

I risultati:


nom=dupont
tableau[0]=un
tableau[1]=deux
tableau[2]=3
tableau[3]=4
[chaine1,chaine2,chaine1chaine2]
chaine=chaine1
type[variable $n]=integer
type[variable $chaine1]=string
type[variable $tableau]=array
type[variable $n]=string
res1=14
(res1,res2,res3)=[un,0,100]
t[0]=un
t[1]=0
t[2]=100
t[0]=un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[2]=100
t[0]=8
t[1]=5
somme=13

Commenti

  • riga 5: in PHP non si dichiara il tipo delle variabili. Queste hanno un tipo dinamico che può variare nel corso del tempo. $nom rappresenta la variabile con identificatore "nom";
  • riga 7: per scrivere sullo schermo, è possibile utilizzare l'istruzione print o l'istruzione echo;
  • riga 9: la parola chiave array consente di definire un array. La variabile $nom[$i] rappresenta l'elemento $i dell'array $tableau;
  • riga 11: la funzione count($tableau) restituisce il numero di elementi dell’array $tableau;
  • righe 13-15: un ciclo. Poiché questo ciclo contiene una sola istruzione, le parentesi graffe sono facoltative. Nel prosieguo di questo documento, inseriremo sistematicamente le parentesi graffe indipendentemente dal numero di istruzioni;
  • riga 14: le stringhe di caratteri sono racchiuse tra virgolette " o apostrofi '. All'interno delle virgolette, le variabili $variable vengono valutate, ma non all'interno degli apostrofi;
  • riga 17: la funzione list consente di raggruppare variabili in un elenco e di assegnare loro un valore con un'unica operazione di assegnazione. In questo caso $chaine1="stringa1" e $chaine2="stringa2";
  • riga 19: l'operatore . è l'operatore di concatenazione delle stringhe;
  • righe 83-86: la parola chiave function definisce una funzione. Una funzione restituisce o meno valori tramite l’istruzione return. Il codice chiamante può ignorare o recuperare i risultati di una funzione. Una funzione può essere definita in qualsiasi punto del codice.
  • riga 92: la funzione predefinita getType($variable) restituisce una stringa di caratteri che rappresenta il tipo di $variable. Questo tipo può cambiare nel tempo;
  • riga 45: l’operatore === effettua un confronto rigoroso tra due elementi: affinché possano essere confrontati, devono avere lo stesso tipo. L’operatore == è meno rigoroso: due elementi possono essere uguali pur non essendo dello stesso tipo. È quanto mostrano le istruzioni delle righe 50-60. Nel caso dell’operatore ==, il confronto avviene dopo la conversione di entrambi gli elementi confrontati nello stesso tipo. In tal caso si verificano conversioni implicite. È piuttosto facile «dimenticare» la presenza di queste conversioni implicite e ottenere così risultati imprevisti, come scoprire che una condizione è vera quando ci si aspettava che fosse falsa. Per evitare questa insidia, useremo sistematicamente l’operatore di confronto ===;
  • riga 64: si possono utilizzare anche gli operatori booleani or e !;
  • riga 69: al posto della notazione array(), è possibile utilizzare la notazione [] per inizializzare un array da PHP7;
  • riga 80: la funzione predefinita exit interrompe l’esecuzione dello script;
  • riga 107: il tag ?> segnala la fine dello script PHP. Non è indispensabile. Inoltre, in un contesto web, può causare problemi se seguita da spazi o caratteri di fine riga, difficili da individuare poiché non visibili in un editor di testo. Pertanto, nel prosieguo del documento, ometteremo sistematicamente questo tag;

Nota: in questo documento useremo la parola chiave [print] per visualizzare del testo sulla console. Un altro metodo per ottenere lo stesso risultato consiste nell’utilizzare la parola chiave [echo]. Esistono sottili differenze tra queste due parole chiave, ma nel contesto del presente documento non ne risulteranno. Pertanto, se preferite utilizzare [echo], potete farlo.

3.3.2. Utilizzo di NetBeans

NetBeans genera diversi avvisi che è utile verificare. Prendiamo ad esempio lo script [bases-01.php]:

Image

Alla riga 5, NetBeans emette un avviso in cui si segnala che il file non rispetta la raccomandazione PSR-1 (Raccomandazioni standard PHP n. 1). Le PSR sono raccomandazioni volte a produrre un codice standard e quindi a facilitare l’interoperabilità e la manutenzione dei codici scritti da persone diverse. Può essere fastidioso ricevere avvisi se si desidera violare deliberatamente gli standard, ad esempio perché il team di progetto ne ha di diversi. È possibile configurare ciò che si desidera verificare o meno con NetBeans:

Image

  • in [5] si trovano gli elementi che si desidera controllare con NetBeans;
  • in [6], il livello di gravità assegnato all’errore segnalato da NetBeans;

Image

In [7] si vede che è stato richiesto di verificare che il codice rispetti effettivamente le raccomandazioni PSR-0 e PSR-1. Non vi è alcun obbligo. Durante la fase di apprendimento del linguaggio, si consiglia di verificare il maggior numero possibile di opzioni proposte da NetBeans. In questo modo si imparano molte cose. Successivamente, si adatterà questo controllo di NetBeans agli standard di codifica del team di un progetto.

Vediamo gli standard di codifica PSR-1 e [8, 9]:

Opzione
Controllo
  1. Dichiarazione delle costanti di classe
Le costanti di classe MUST devono essere dichiarate interamente in maiuscolo con separatori sottobarra.
Es.: const TAUX_TVA
  1. Dichiarazione dei metodi
I nomi dei metodi MUST devono essere dichiarati in camelCase().
Esempio: public function executeBatchImpots{}
  1. Nome della proprietà
I nomi delle proprietà SHOULD devono essere dichiarati nel formato $StudlyCaps, $camelCase o $under_score (in modo coerente all’interno di un ambito)
Es.: public SalaireAnnuel (StudlyCaps), public salaireAnnuel (camelCase), public salaire_annuel (under_score)
  1. Effetti collaterali
Un file SHOULD dichiara nuovi simboli e non provoca altri effetti collaterali, oppure SHOULD esegue logica con effetti collaterali, ma SHOULD NOT fa entrambe le cose.
  1. Dichiarazione dei tipi
I nomi dei tipi MUST devono essere dichiarati in StudlyCaps (Il codice scritto per 5.2.x e versioni precedenti a SHOULD utilizza la convenzione di pseudonamespacing che prevede l’aggiunta di prefissi Vendor_ ai nomi dei tipi). Ogni tipo si trova in un file a sé stante e appartiene a uno spazio dei nomi di almeno un livello: un nome di fornitore di primo livello.
Es.: class EtudiantBoursier {}

La raccomandazione PSR-1 / 4 stabilisce che in un file PHP debbano essere presenti:

  • o la dichiarazione di un tipo (classi, interfacce);
  • oppure del codice eseguibile senza dichiarazione di nuovi tipi;

Esistono altre raccomandazioni PHP non controllate da NetBeans: PSR-3, PSR-4, PSR-6, PSR-7 e PSR-13.

Per semplicità, non tutti gli esempi del documento seguono la raccomandazione PSR-1, poiché ciò richiede di distribuire il codice delle classi e delle interfacce in file separati, il che risulta troppo oneroso per esempi di base. È quindi più semplice inserire tutto in un unico file. Per l’esempio dell’applicazione presentata come filo conduttore di questo documento, si è cercato di seguire il più possibile la raccomandazione PSR-1.

Alcuni avvisi di NetBeans segnalano un potenziale errore:

Image

L’avviso [Unitialized Variables] segnala un probabile errore, spesso un errore di battitura nel nome di una variabile. Lo stesso vale per l’avviso [Unused Variables].

Infine, si consiglia di verificare tutti gli avvisi di NetBeans segnalati da un pannello nel margine sinistro del codice e da un trattino giallo nel margine destro:

Image

Image

3.4. L’ambito delle variabili

3.4.1. Esempio 1

Lo script [bases-02.php] è il seguente:


<?php

// ambito delle variabili

function f1() {
  // si utilizza la variabile globale $i
  global $i;
  $i++;
  $j = 10;
  print "f1[i,j]=[$i,$j]\n";
}

function f2() {
  // si utilizza la variabile globale $i
  global $i;
  $i++;
  $j = 20;
  print "f2[i,j]=[$i,$j]\n";
}

function f3() {
  // si utilizza una variabile locale $i
  $i = 4;
  $j = 30;
  print "f3[i,j]=[$i,$j]\n";
}

// test
$i = 0;
$j = 0;  // queste due variabili non sono note a una funzione f
// a meno che questa non le dichiari esplicitamente tramite l'istruzione global
// che intende utilizzarle
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";

I risultati:

1
2
3
4
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[4,30]
test[i,j]=[2,0]

Commenti

  • righe 29-30: definiscono due variabili, $i e $j, del programma principale. Queste variabili non sono note all'interno delle funzioni. Pertanto, alla riga 9, la variabile $j della funzione f1 è una variabile locale della funzione f1 ed è diversa dalla variabile $j del programma principale. Una funzione può accedere a una variabile $variable del programma principale tramite la parola chiave global;
  • alla riga 7, l’istruzione fa riferimento alla variabile globale $i del programma principale;

3.4.2. Esempio 3

Lo script [bases-03.php] è il seguente:


<?php

// l'ambito di una variabile è globale ai blocchi di codice
$i = 0; {
  $i = 4;
  $i++;
}
print "i=$i\n";

I risultati:

i=5

Commenti

In alcuni linguaggi, una variabile definita all'interno di parentesi graffe ha un ambito limitato a queste ultime: non è visibile al di fuori di esse. I risultati sopra riportati dimostrano che in PHP non è così. La variabile $i definita alla riga 5 all'interno delle parentesi graffe è la stessa utilizzata alle righe 4 e 8 al di fuori di esse.

3.5. I cambiamenti di tipo

Le variabili in PHP non hanno un tipo costante. Questo può cambiare durante l’esecuzione a seconda del valore assegnato alla variabile. Nelle operazioni che coinvolgono dati di vari tipi, l’interprete PHP effettua conversioni implicite per riportare gli operandi a un tipo comune. Queste conversioni implicite, se non sono note allo sviluppatore, possono essere fonte di errori difficili da individuare. Di seguito è riportato uno script [bases-04.php] che mostra conversioni implicite ed esplicite:


<?php

// tipi rigorosi nel passaggio dei parametri
declare(strict_types=1);

// conversioni implicite di tipo
// tipo --> bool
print "Conversion vers un booléen------------------------------\n";
showBool("abcd", "abcd");
showBool("", "");
showBool("[1, 2, 3]", [1, 2, 3]);
showBool("[]", []);
showBool("NULL", NULL);
showBool("0.0", 0.0);
showBool("0", 0);
showBool("4.6", 4.6);

function showBool(string $prefixe, $var) : void {
  print "(bool) $prefixe : ";
  // la conversione di $var in booleano avviene automaticamente nel test successivo
  if ($var) {
    print "true";
  } else {
    print "false";
  }
  print "\n";
}

Commenti

  • riga 4: richiede una verifica rigorosa del tipo dei parametri di una funzione quando questo è specificato;
  • riga 18: la funzione [showBool] ha lo scopo di mostrare la trasformazione implicita (automatica) effettuata dall’interprete PHP quando un valore di qualsiasi tipo deve essere trasformato in un valore booleano (riga 21);
  • riga 18: al parametro $var non è assegnato alcun tipo. Il parametro effettivo potrà quindi essere di qualsiasi tipo. Il parametro $prefixe dovrà invece essere di tipo stringa. La funzione showBool non restituisce alcun valore (void);
  • riga 21: nell’istruzione if($var), il valore di $var deve essere convertito in booleano affinché if venga valutato. Sorprendentemente, l'interprete PHP fornisce una risposta per qualsiasi tipo di valore gli venga fornito;
  • righe 9-16: il valore del parametro della funzione [showBool] sarà successivamente:
    • riga 9: una stringa non vuota: risultato TRUE (le maiuscole e le minuscole non fanno differenza, TRUE=true);
    • riga 10: una stringa vuota: risultato FALSE;
    • riga 11: un array non vuoto: risultato TRUE;
    • riga 12: un array vuoto: risultato FALSE;
    • riga 14: il numero reale 0: risultato FALSE;
    • riga 15: il numero intero 0: risultato FALSE;
    • riga 16: il numero reale (o intero) diverso da 0: risultato TRUE;

È quanto mostrano le schermate ottenute:


Conversion vers un booléen------------------------------
(bool) abcd : true
(bool)  : false
(bool) [1, 2, 3] : true
(bool) [] : false
(bool) NULL : false
(bool) 0.0 : false
(bool) 0 : false
(bool) 4.6 : true

Continuiamo con il codice dello script:


//
// conversioni implicite da stringa a tipo numerico
// stringa --> numero
print "Conversion chaîne vers nombre------------------------------\n";
showNumber("12");
showNumber("45.67");
showNumber("abcd");

function showNumber(string $var) : void {
  $nombre = $var + 1;
  var_dump($nombre);
  print "($var): $nombre\n";
}

Commenti

  • riga 9: la funzione [showNumber] accetta un parametro di tipo stringa e non restituisce alcun risultato (void);
  • riga 10: questo parametro viene utilizzato in un'operazione aritmetica, il che costringerà l'interprete PHP a tentare di convertire $var in un numero;
    • riga 5: trasformerà la stringa “12” nel numero intero 12;
    • riga 6: trasformerà la stringa “45.67” nel numero reale 45.67;
    • riga 7: emetterà un avviso ma convertirà comunque la stringa “abcd” nel numero 0;

Ecco i risultati dell’esecuzione:

1
2
3
4
5
6
7
8
9
Conversion chaîne vers nombre------------------------------
int(13)
(12): 13
float(46.67)
(45.67): 46.67

Warning: A non-numeric value encountered in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_031.php on line 37
int(1)
(abcd): 1

Continuiamo con il codice dello script:


// conversioni esplicite di tipo
// verso int
showInt("12.45");
showInt(67.8);
showInt(TRUE);
showInt(NULL);

function showInt($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((int) $var);
  print "\n";
}

Commenti

  • riga 21: la funzione [showInt] accetta un parametro di qualsiasi tipo e non restituisce alcun risultato. Tenta di convertire il parametro $var in un intero alla riga 26. In generale, per convertire una variabile $var in un tipo T, si scrive (T) $var, dove T può essere: int, integer, bool, boolean, float, double, real, string, array, object, unset;
  • riga 16: converte la stringa “12.45” in un intero 12;
  • riga 17: converte il numero reale 67.8 in un numero intero 67;
  • riga 18: converte il valore booleano TRUE nel numero intero 1 (il valore booleano FALSE nel numero intero 0);
  • riga 19: converte il puntatore NULL in un numero intero pari a 0;

Ecco cosa mostrano le schermate:

paramètre : string(5) "12.45"

résultat de la conversion : int(12)

paramètre : float(67.8)

résultat de la conversion : int(67)

paramètre : bool(true)

résultat de la conversion : int(1)

paramètre : NULL

résultat de la conversion : int(0)

Continuiamo l’analisi dello script con la conversione esplicita dei valori in tipo float:


// verso float
showFloat("12.45");
showFloat(67);
showFloat(TRUE);
showFloat(NULL);

function showFloat($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((float) $var);
  print "\n";
}

Commenti

  • riga 35: la funzione [showFloat] riceve un parametro di tipo qualsiasi e non restituisce alcun risultato;
  • riga 40: il valore di questo parametro viene convertito esplicitamente in float;
  • riga 30: la stringa “12.45” viene convertita nel numero reale 12.45;
  • riga 31: il numero intero 67 viene convertito nel numero reale 67;
  • riga 32: il valore booleano TRUE viene convertito nel numero reale 1 (il valore FALSE nel numero 0);
  • riga 33: il puntatore NULL viene convertito nel numero reale 0;

Ecco cosa mostrano i risultati sullo schermo:

paramètre : string(5) "12.45"

résultat de la conversion : float(12.45)

paramètre : int(67)

résultat de la conversion : float(67)

paramètre : bool(true)

résultat de la conversion : float(1)

paramètre : NULL

résultat de la conversion : float(0)

Continuiamo la presentazione dello script esaminando le conversioni verso il tipo stringa:


// verso stringa
showstring(5);
showString(6.7);
showString(FALSE);
showString(NULL);

function showString($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((string) $var);
  print "\n";
}
  • riga 49: la funzione [showString] riceve un parametro di tipo qualsiasi e non restituisce alcun risultato;
  • riga 54: il valore del parametro viene convertito in un tipo stringa;
  • riga 44: il numero intero 5 verrà trasformato nella stringa «5»;
  • riga 45: il numero reale 6.7 verrà convertito nella stringa « 6.7 »;
  • riga 46: il valore booleano FALSE verrà convertito in una stringa vuota;
  • riga 47: il puntatore NULL verrà convertito in una stringa vuota;

Ecco i risultati visualizzati sullo schermo:

paramètre : int(5)

résultat de la conversion : string(1) "5"

paramètre : float(6.7)

résultat de la conversion : string(3) "6.7"

paramètre : bool(false)

résultat de la conversion : string(0) ""

paramètre : NULL

résultat de la conversion : string(0) ""

3.6. Le tabelle

3.6.1. Tabelle classiche unidimensionali

Lo script [bases-05.php] è il seguente:


<?php

// array classici
// inizializzazione
$tab1 = array(0, 1, 2, 3, 4, 5);
// iterazione - 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// scorrimento - 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1)) {
    print "tab1[$clé]=$valeur\n";
}
// aggiunta di elementi
$tab1[] = $i++;
$tab1[] = $i++;
// scorrimento - 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
  print "tab1[$i]=$élément\n";
  $i++;
}
// eliminazione dell'ultimo elemento
array_pop($tab1);
// percorso - 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// eliminazione del primo elemento
array_shift($tab1);
// percorso - 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// aggiunta alla fine della tabella
array_push($tab1, -2);
// percorso - 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// aggiunta all'inizio della tabella
array_unshift($tab1, -1);
// percorso - 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}

I risultati:


tab1 a 6 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 6 éléments

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_04.php on line 14
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 8 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=7
tab1 a 7 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1 a 6 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1 a 7 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1[6]=-2
tab1 a 8 éléments
tab1[0]=-1
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=-2

Commenti

Il programma sopra riportato illustra le operazioni di manipolazione di un array di valori. In PHP esistono due notazioni per gli array:

$tableau=array("un",2,"trois")
$contraires=array("petit"=>"grand", "beau"=>"laid", "cher"=>"bon marché")

L'array 1 è denominato array, mentre l'array 2 è un dizionario o array associativo in cui gli elementi sono indicati come chiave => valore. La notazione $contraires["beau"] indica il valore associato alla chiave "bello". In questo caso si tratta della stringa "brutto". L'array 1 è solo una variante del dizionario e potrebbe essere scritto come segue:

$tableau=array(0=>"un",1=>2,2=>"trois")

Si ottiene così $tableau[2]="tre". In definitiva, esistono solo dizionari. Nel caso di un array classico composto da n elementi, le chiavi sono i numeri interi dell’intervallo [0,n-1].

  • riga 14: la funzione each($tableau) consente di iterare su un dizionario. Ad ogni chiamata, restituisce una coppia (chiave, valore) dello stesso. Come mostra la riga 10 dei risultati, la funzione each è ormai obsoleta in PHP 7;
  • riga 13: la funzione reset($dictionnaire) imposta la funzione each sulla prima coppia (chiave, valore) del dizionario.
  • riga 14: il ciclo while termina quando la funzione each restituisce una coppia vuota alla fine del dizionario. In questo caso interviene una conversione implicita: la coppia vuota viene convertita nel valore booleano FALSE;
  • riga 18: la notazione $tableau[]=valore aggiunge l’elemento valeur come ultimo elemento di $tableau;
  • riga 23: l'array viene iterato con un foreach. Questo elemento sintattico consente di iterare un dizionario, e quindi un array, secondo due sintassi:
foreach($dictionnaire as $clé=>$valeur)
foreach($tableau as $valeur)

La prima sintassi restituisce una coppia (clé,valeur) ad ogni iterazione, mentre la seconda sintassi restituisce solo l'elemento valeur del dizionario.

  • riga 28: la funzione array_pop($tableau) rimuove l’ultimo elemento da $tableau;
  • riga 35: la funzione array_shift($tableau) elimina il primo elemento di $tableau;
  • riga 42: la funzione array_push($tableau,valore) aggiunge valeur come ultimo elemento di $tableau;
  • riga 49: la funzione array_unshift($tableau,valore) aggiunge valeur come primo elemento di $tableau;

3.6.2. Il dizionario o array associativo

Lo script [bases-06.php] è il seguente:


<?php

// dizionari
$conjoints = ["Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => ""];
// percorso - 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
    print "conjoints[$clé]=$valeur\n";
}
// ordinamento del dizionario in base alla chiave
ksort($conjoints);
// percorso - 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
    print "conjoints[$clé]=$valeur\n";
}
// elenco delle chiavi del dizionario
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++) {
    print "clés[$i]=$clés[$i]\n";
}
// elenco dei valori del dizionario
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++) {
    print "valeurs[$i]=$valeurs[$i]\n";
}
// ricerca di una chiave
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// eliminazione di una coppia chiave-valore
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
  print "conjoints[$clé]=$valeur\n";
}
// fine
exit;

function existe($conjoints, $mari) {
  // verifica se la chiave $mari esiste nel dizionario $conjoints
  if (isset($conjoints[$mari])) {
        print "La clé [$mari] existe associée à la valeur [$conjoints[$mari]]\n";
    } else {
        print "La clé [$mari] n'existe pas\n";
    }
}

I risultati:


Nombre d'éléments du dictionnaire : 4

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_05.php on line 8
conjoints[Pierre]=Gisèle
conjoints[Paul]=Virginie
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
clés[0]=Jacques
clés[1]=Jean
clés[2]=Paul
clés[3]=Pierre
valeurs[0]=Lucette
valeurs[1]=
valeurs[2]=Virginie
valeurs[3]=Gisèle
La clé [Jacques] existe associée à la valeur [Lucette]
La clé [Lucette] n'existe pas
La clé [Jean] existe associée à la valeur []
Nombre d'éléments du dictionnaire : 3
conjoints[Jacques]=Lucette
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle

Commenti

Il codice precedente applica a un dizionario quanto visto in precedenza per un semplice array. Commentiamo solo le novità:

  • riga 12: la funzione ksort (key sort) consente di ordinare un dizionario secondo l'ordine naturale delle chiavi;
  • riga 19: la funzione array_keys($dictionnaire) restituisce l'elenco delle chiavi del dizionario sotto forma di tabella;
  • riga 24: la funzione array_values($dictionnaire) restituisce l’elenco dei valori del dizionario sotto forma di tabella;
  • riga 43: la funzione isset($variable) restituisce TRUE se la variabile $variable è stata definita, altrimenti FALSE;
  • riga 33: la funzione unset($variable) elimina la variabile $variable.

3.6.3. Le tabelle multidimensionali

Lo script [bases-07.php] è il seguente:


<?php

// tabelle multidimensionali classiche
// inizializzazione
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// scorrimento
for ($i1 = 0; $i1 < count($multi); $i1++) {
  for ($i2 = 0; $i2 < count($multi[$i1]); $i2++) {
    print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
  }
}
// dizionari multidimensionali
// inizializzazione
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// scorrimento
foreach ($multi as $clé => $valeur) {
    for ($i2 = 0; $i2 < count($valeur); $i2++) {
        print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
    }
}

Risultati:


multi[0][0]=0
multi[0][1]=1
multi[0][2]=2
multi[1][0]=10
multi[1][1]=11
multi[1][2]=12
multi[1][3]=13
multi[2][0]=20
multi[2][1]=21
multi[2][2]=22
multi[2][3]=23
multi[2][4]=24
multi[zéro][0]=0
multi[zéro][1]=1
multi[zéro][2]=2
multi[un][0]=10
multi[un][1]=11
multi[un][2]=12
multi[un][3]=13
multi[deux][0]=20
multi[deux][1]=21
multi[deux][2]=22
multi[deux][3]=23
multi[deux][4]=24

Commenti

  • riga 5: gli elementi dell'array $multi sono a loro volta array;
  • riga 14: l'array $multi diventa un dizionario (clé,valeur) in cui ogni valeur è un array;

3.7. Le stringhe di caratteri

3.7.1. Notazione

Lo script [bases-08.php] è il seguente:


<?php

// notazione delle stringhe
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>

Risultati:

[un,un]

3.7.2. Confronto

Lo script [bases-09.php] è il seguente:


<?php

// rigoroso rispetto del tipo dei parametri delle funzioni
declare(strict_types=1);

// funzione di confronto
function compareModele2Chaine(string $chaine1, string $chaine2): void {
  // confronta stringa1 e stringa2
  if ($chaine1 === $chaine2) {
    print "[$chaine1] est égal à [$chaine2]\n";
  } else {
    print "[$chaine1] est différent de [$chaine2]\n";
  }
}

// test di confronto tra stringhe
compareModele2Chaine("abcd", "abcd");
compareModele2Chaine("", "");
compareModele2Chaine("1", "");
exit;

Risultati:


[abcd] est égal à [abcd]
[] est égal à []
[1] est différent de []

Commenti

  • riga 9 del codice: si sarebbe potuto utilizzare l'operatore di confronto == anziché ===. Quest'ultimo operatore è più restrittivo, in quanto impone che i due operandi siano dello stesso tipo. Da notare che in questo caso avrebbe potuto essere sostituito dall'operatore ==, poiché il tipo dei due parametri è definito come string nella firma della funzione;

3.7.3. Collegamenti tra stringhe e array

Lo script [bases-10.php] è il seguente:


<?php

// da stringa a tabella
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// iterazione su un array
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
}
// da array a stringa
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// aggiungiamo un campo vuoto
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// iterazione su un array
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
} // ora abbiamo 5 elementi, l'ultimo dei quali è vuoto
// aggiungiamo nuovamente un campo vuoto
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// iterazione dell'array
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
} // ora abbiamo 6 elementi, gli ultimi due dei quali sono vuoti

Risultati:


tab a 4 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
chaine2=1:2:3:4
chaîne=1:2:3:4:
tab a 5 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
chaîne=1:2:3:4::
tab a 6 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
tab[5]=

Commenti

  • riga 5: la funzione explode($séparateur,$chaine) consente di recuperare i campi di $chaine separati da $séparateur. Pertanto, la funzione explode(":",$chaine) consente di recuperare sotto forma di tabella gli elementi di $chaine separati dalla stringa ":";
  • riga 12: la funzione implode($séparateur,$tableau) esegue l'operazione inversa rispetto alla funzione explode. Restituisce una stringa composta dagli elementi di $tableau separati da $séparateur;

3.7.4. Le espressioni regolari

Lo script [bases-11.php] è il seguente:


<?php

// tipo rigoroso per i parametri delle funzioni
declare (strict_types=1);

// espressioni regolari in PHP
// recuperare i diversi campi di una stringa
// il modello: una sequenza di cifre racchiusa tra caratteri qualsiasi
// si desidera estrarre solo la sequenza di cifre
$modèle = "/(\d+)/";
// si confronta la stringa con il modello
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");

// il modello: una sequenza di cifre circondata da caratteri qualsiasi
// si desidera la sequenza di cifre insieme ai campi che la precedono e la seguono
$modèle = "/^(.*?)(\d+)(.*?)$/";
// si confronta la stringa con il modello
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");

// il modello: una data nel formato gg/mm/aa
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
compareModele2Chaine($modèle, "10/05/97");
compareModele2Chaine($modèle, "  04/04/01  ");
compareModele2Chaine($modèle, "5/1/01");

// il modello: un numero decimale
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
compareModele2Chaine($modèle, "187.8");
compareModele2Chaine($modèle, "-0.6");
compareModele2Chaine($modèle, "4");
compareModele2Chaine($modèle, ".6");
compareModele2Chaine($modèle, "4.");
compareModele2Chaine($modèle, " + 4");

// fine
exit;

// --------------------------------------------------------------------------
function compareModele2Chaine(string $modèle, string $chaîne): void {
  // confronta la stringa $chaîne con il modello $modèle
  // si confronta la stringa con il modello
  $champs = [];
  $correspond = preg_match($modèle, $chaîne, $champs);
  // visualizzazione dei risultati
  print "\nRésultats($modèle,$chaîne)\n";
  if ($correspond) {
    for ($i = 0; $i < count($champs); $i++) {
      print "champs[$i]=$champs[$i]\n";
    }
  } else {
    print "La chaîne [$chaîne] ne correspond pas au modèle [$modèle]\n";
  }
}

Risultati:


Résultats(/(\d+)/,xyz1234abcd)
champs[0]=1234
champs[1]=1234

Résultats(/(\d+)/,12 34)
champs[0]=12
champs[1]=12

Résultats(/(\d+)/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/(\d+)/]

Résultats(/^(.*?)(\d+)(.*?)$/,xyz1234abcd)
champs[0]=xyz1234abcd
champs[1]=xyz
champs[2]=1234
champs[3]=abcd

Résultats(/^(.*?)(\d+)(.*?)$/,12 34)
champs[0]=12 34
champs[1]=
champs[2]=12
champs[3]= 34

Résultats(/^(.*?)(\d+)(.*?)$/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/^(.*?)(\d+)(.*?)$/]

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,10/05/97)
champs[0]=10/05/97
champs[1]=10
champs[2]=05
champs[3]=97

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,  04/04/01  )
champs[0]=  04/04/01  
champs[1]=04
champs[2]=04
champs[3]=01

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,5/1/01)
La chaîne [5/1/01] ne correspond pas au modèle [/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/]

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,187.8)
champs[0]=187.8
champs[1]=
champs[2]=187.8

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,-0.6)
champs[0]=-0.6
champs[1]=-
champs[2]=0.6

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4)
champs[0]=4
champs[1]=
champs[2]=4

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,.6)
champs[0]=.6
champs[1]=
champs[2]=.6

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4.)
champs[0]=4.
champs[1]=
champs[2]=4.

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/, + 4)
champs[0]= + 4
champs[1]=+
champs[2]=4

Commenti

  • Qui utilizziamo le espressioni regolari per estrarre i vari campi da una stringa di caratteri. Le espressioni regolari consentono di superare i limiti della funzione implode. Il principio consiste nel confrontare una stringa di caratteri con un'altra stringa denominata modèle utilizzando la funzione preg_match:

$correspond = preg_match($modèle, $chaîne, $champs);

La funzione preg_match restituisce un valore booleano TRUE se la stringa modèle è presente nella stringa chaîne. In tal caso, $champs[0] rappresenta la sottostringa corrispondente al modello. Inoltre, se modèle contiene sottomodelli tra parentesi, $champs[1] è la parte di $chaîne corrispondente al primo sottomodello, $champs[2] è la parte di $chaîne corrispondente al secondo sottomodello, ecc…

Consideriamo il primo esempio. Il modello è definito alla riga 10: indica una sequenza di una o più (+) cifre (\d) posizionate in qualsiasi punto di una stringa. Inoltre, il modello definisce un sottomodello racchiuso tra parentesi;

  • riga 12: il modello /(\d+)/ (sequenza di una o più cifre in qualsiasi punto della stringa) viene confrontato con la stringa "xyz1234abcd". Si nota che la sottostringa 1234 corrisponde al modello. Si avrà quindi $champs[0] uguale a "1234". Inoltre, il modello contiene sottomodelli tra parentesi. Si avrà $champs[1] = "1234";
  • riga 13: il modello /(\d+)/ viene confrontato con la stringa "12 34". Si nota che le sottostringhe 12 e 34 corrispondono al modello. Il confronto si interrompe alla prima sottostringa che corrisponde al modello. Si avrà quindi $champs[0]=12 e $champs[1]=12;
  • riga 14: il modello /(\d+)/ viene confrontato con la stringa "abcd". Non viene trovata alcuna corrispondenza;

Spieghiamo i modelli utilizzati nel resto del codice:


$modèle = "/^(.*?)(\d+)(.*?)$/";

corrisponde all’inizio della stringa (^), seguito da 0 o più (*) caratteri qualsiasi (.), poi da 1 o più (+) cifre, e infine di nuovo da 0 o più (*) caratteri qualsiasi (.). Il modello (.*) indica 0 o più caratteri qualsiasi. Un modello di questo tipo corrisponderà a qualsiasi stringa. Pertanto, il modello /^(.*)(\d+)(.*)$/ non verrà mai trovato poiché il primo sottomodello (.*) assorbirà l’intera stringa. Il modello (.*?)(\d+) indica invece 0 o più caratteri qualsiasi fino al sottomodello successivo (?), in questo caso \d+. Pertanto, le cifre non vengono più assorbite dal modello (.*). Il modello sopra riportato corrisponde quindi a [début de chaîne (^), une suite de caractères quelconques (.*?), une suite d'un ou plusieurs chiffres (\d+), une suite de caractères quelconques (.*?), la fin de la chaîne ($)].


$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";

corrisponde a [début de chaîne (^), 2 chiffres (\d\d), le caractère / (\/), 2 chiffres, /, 2 chiffres, une suite de 0 ou plusieurs espaces (\s*), la fin de chaîne ($)].


$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";

corrisponde all’inizio della stringa (^), 0 o più spazi (\s*), un segno + o - [+|-] presente 0 o 1 volta (?), una sequenza di 0 o più spazi (\s*), 1 o più cifre seguite da un punto decimale seguito da zero o più cifre (\d+\.\d*) oppure (|) un punto decimale (\.) seguito da una o più cifre (\d+) oppure (|) una o più cifre (\d+), una sequenza di 0 o più spazi (\s*)].

Nota: il termine [espace] nelle espressioni regolari indica un insieme di caratteri: spazio, salto di riga \n, tabulazione \t, ritorno a capo \r, salto di pagina \f…

3.8. Le funzioni

3.8.1. Modalità di passaggio dei parametri

Lo script [base-12.php] è il seguente:


<?php

// modalità di passaggio dei parametri di una funzione
// rigoroso rispetto del tipo dei parametri
declare(strict_types=1);

function f(int &$i, int $j): void {
  // $i verrà passato per riferimento
  // $j verrà passato per valore
  $i++;
  $j++;
  print "f[i,j]=[$i,$j]\n";
}

// test
$i = 0;
$j = 0;
// $i e $j vengono passati alla funzione f
f($i, $j);
print "test[i,j]=[$i,$j]\n";

Risultati:

f[i,j]=[1,1]
test[i,j]=[1,0]

Commenti

Il codice sopra riportato illustra le due modalità di passaggio dei parametri a una funzione. Prendiamo il seguente esempio:

1
2
3
4
5
6
7
function f(&$a,$b){

}

// programma principale
$i=10; $j=20;
f($i,$j);
  • riga 1: definisce i parametri formali $a e $b della funzione f. Quest'ultima elabora questi due parametri formali e restituisce un risultato;
  • riga 7: chiamata della funzione f con due parametri effettivi $i e $j. Le associazioni tra i parametri formali ($a, $b) e i parametri effettivi ($i, $j) sono definite dalle righe 1 e 7:
  • &$a: il simbolo & indica che il parametro formale $a assumerà come valore l'indirizzo del parametro effettivo $i. In altre parole, $a e $i sono due riferimenti alla stessa posizione di memoria. Modificare il parametro formale $a equivale a modificare il parametro effettivo $i. È quanto dimostra l’esecuzione del codice. Questa modalità di passaggio è adatta ai parametri di output e a dati di grandi dimensioni come array e dizionari. Questa modalità di passaggio è denominata «passaggio per riferimento».
  • $b: il parametro formale $b assumerà il valore del parametro effettivo $j. Si tratta di un passaggio per valore. I parametri formali e effettivi sono due variabili diverse. La modifica del parametro formale $b non ha alcuna incidenza sul parametro effettivo $j. È quanto dimostra l’esecuzione del codice. Questa modalità di passaggio è adatta ai parametri di ingresso.
  • Si consideri la funzione échange che accetta due parametri formali $a e $b. La funzione scambia il valore di questi due parametri. Pertanto, in caso di chiamata di scambio ($i,$j), il codice chiamante si aspetta che i valori dei due parametri effettivi vengano scambiati. Si tratta quindi di parametri di uscita (vengono modificati). Si scriverà quindi:
function échange(&$a,&$b){.}

Il seguente script [base-13.php] mostra altri esempi:


<?php

// tipi in modalità rigorosa
// declare(strict_types = 1);

// modalità di passaggio dei parametri

function f(&$i, $j) {
  // $i sarà ottenuto per riferimento
  // $j sarà ottenuto per valore
  $i++;
  $j++;
  print "f[i,j]=[$i,$j]\n";
}

function g(int &$i, int $j) : void {
  // $i sarà ottenuto per riferimento
  // $j sarà ottenuto per valore
  $i++;
  $j++;
  print "g[i,j]=[$i,$j]\n";
}

// test
$i = 0;
$j = 0;
// $i e $j sono stati passati alla funzione f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
// $i e $j vengono passati alla funzione g
g($i, $j);
print "test[i,j]=[$i,$j]\n";
// vengono passati parametri errati alla funzione f
$a=5.3;
$b=6.2;
f($a, $b);
print "test[a,b]=[$a,$b]\n";
// si stanno passando parametri non corretti alla funzione f
$a=5.3;
$b=6.2;
g($a, $b);
print "test[a,b]=[$a,$b]\n";

Commenti

  • righe 8-14: la funzione f analizzata nel paragrafo precedente, ma senza specificare il tipo dei parametri;
  • righe 16-22: la funzione g fa la stessa cosa della funzione f, ma si specifica il tipo dei parametri attesi – questa è una novità PHP 7. Si attendono due parametri di tipo int. Vogliamo vedere cosa succede quando il parametro effettivo passato alla funzione non ha il tipo atteso da quest'ultima;
  • righe 25-26: $i e $j sono due numeri interi;
  • righe 28-29: chiamata alla funzione f con parametri del tipo previsto;
  • righe 31-32: chiamata alla funzione g con parametri del tipo previsto;
  • righe 34-35: le variabili $a e $b sono di tipo float;
  • righe 36-37: chiamata alla funzione f con parametri che non sono del tipo previsto;
  • righe 41-42: chiamata alla funzione g con parametri che non sono del tipo previsto;

Risultati

1
2
3
4
5
6
7
8
f[i,j]=[1,1]
test[i,j]=[1,0]
g[i,j]=[2,1]
test[i,j]=[2,0]
f[i,j]=[6.3,7.2]
test[a,b]=[6.3,6.2]
g[i,j]=[6,7]
test[a,b]=[6,6.2]
  • le righe 5-6 mostrano che la funzione f ha accettato entrambi i parametri di tipo float e li ha elaborati;
  • le righe 7-8 mostrano che la funzione g ha accettato entrambi i parametri di tipo float ma li ha convertiti in tipo int (riga 7);

Ora rimuoviamo il commento dalla riga 4:

declare(strict_types = 1);

Questa istruzione indica che i tipi dei parametri formali devono essere rispettati. In caso contrario, viene segnalato un errore. I risultati dell’esecuzione diventano quindi:

f[i,j]=[1,1]
test[i,j]=[1,0]
g[i,j]=[2,1]
test[i,j]=[2,0]
f[i,j]=[6.3,7.2]
test[a,b]=[6.3,6.2]

Fatal error: Uncaught TypeError: Argument 1 passed to g() must be of the type integer, float given, called in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php on line 40 and defined in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php:15
Stack trace:
#0 C:\Data\st-2019\dev\php7\php5-esempi\esempi\exemple_111.php(40): g(5.3, 6.2)
#1 {main}
  thrown in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php on line 15
  • righe 9-10: l’interprete PHP 7 ha generato un’eccezione per segnalare che il primo parametro passato alla funzione g non era del tipo corretto. Si raccomanda di essere rigorosi sui tipi dei parametri, ogni volta che è possibile, per individuare gli errori nelle chiamate alle funzioni;

3.8.2. Risultati restituiti da una funzione

Lo script [base-15.php] è il seguente:


<?php

// tipi in modalità rigorosa
declare(strict_types=1);

// risultati restituiti da una funzione
// una funzione può restituire più valori in un array
list($res1, $res2, $res3) = f1(10);
print "[$res1,$res2,$res3]\n";
$res = f1(10);
for ($i = 0; $i < count($res); $i++) {
  print "f1 : res[$i]=$res[$i]\n";
}

// una funzione può restituire un oggetto
$res = f2(10);
print "f2 : [$res->res1,$res->res2,$res->res3]\n";
// oggetto di che tipo?
print "nature de l'objet : ";
var_dump($res);
print "\n";

// si fa la stessa cosa con la funzione f3
$res = f3(10);
print "f3 : [$res->res1,$res->res2,$res->res3]\n";
// di che tipo di oggetto si tratta?
print "nature de l'objet : ";
var_dump($res);
print "\n";

// fine
exit;

// funzione f1
function f1(int $valeur): array {
  // restituisce un array ($valeur+1,$valeur+2,$valeur+3)
  return array($valeur + 1, $valeur + 2, $valeur + 3);
}

// funzione f2
function f2(int $valeur): object {
  // restituisce un oggetto ($valeur+1,$valeur+2,$valeur+3)
  $res->res1 = $valeur + 1;
  $res->res2 = $valeur + 2;
  $res->res3 = $valeur + 3;
  // restituisce l'oggetto
  return $res;
}

// funzione f3 - fa la stessa cosa della funzione f2
function f3(int $valeur): object {
  // restituisce un oggetto ($valeur+1,$valeur+2,$valeur+3)
  $res = new stdclass();
  $res->res1 = $valeur + 1;
  $res->res2 = $valeur + 2;
  $res->res3 = $valeur + 3;
  // restituisce l'oggetto
  return $res;
}

Risultati


[11,12,13]
f1 : res[0]=11
f1 : res[1]=12
f1 : res[2]=13

Warning: Creating default object from empty value in C:\Data\st-2019\dev\php7\php5-exemples\exemples\bases\base-15.php on line 43
f2 : [11,12,13]
nature de l'objet : object(stdClass)#1 (3) {
  ["res1"]=>
  int(11)
  ["res2"]=>
  int(12)
  ["res3"]=>
  int(13)
}

f3 : [11,12,13]
nature de l'objet : object(stdClass)#2 (3) {
  ["res1"]=>
  int(11)
  ["res2"]=>
  int(12)
  ["res3"]=>
  int(13)
}

Commenti

  • il programma precedente mostra che una funzione PHP può restituire un insieme di risultati e non uno solo, sotto forma di array o di oggetto. Il concetto di oggetto viene spiegato più avanti;
  • righe 35-38: la funzione f1 restituisce più valori sotto forma di array;
  • righe 41-48: la funzione f2 restituisce più valori sotto forma di oggetto (object);
  • righe 51-59: la funzione f3 è identica alla funzione f2, tranne per il fatto che crea esplicitamente un oggetto, riga 53;
  • la riga 6 dei risultati emette un avviso (warning) che indica che PHP è stato costretto a creare un oggetto predefinito alla riga 43 del codice, ovvero durante l’utilizzo della notazione [$res→res1]. La funzione var_dump alla riga 20 del codice consente di accedere al tipo dell’oggetto e al suo contenuto. Nei risultati si osserva che:
    • riga 8: l’oggetto creato per impostazione predefinita è di tipo stdClass;
    • righe 9-10: la proprietà res1 è di tipo entier e ha il valore 11;
    • ecc…
    • per evitare l’avviso riportato alla riga 6 dei risultati, si crea esplicitamente, alla riga 53 della funzione f3, un oggetto di tipo stdClass;

3.9. I file di testo

Lo script [bases-16.php] è il seguente:


<?php

// rigoroso rispetto del tipo dei parametri delle funzioni
declare (strict_types=1);

// elaborazione sequenziale di un file di testo
// quest'ultimo è un insieme di righe della forma login:pwd:uid:gid:infos:dir:shell
// ogni riga viene inserita in un dizionario nella forma login => uid:gid:infos:dir:shell
// si imposta il nome del file
$INFOS = "infos.txt";
// lo si apre in modalità di creazione
if (!$fic = fopen($INFOS, "w")) {
  print "Erreur d'ouverture du fichier $INFOS en écriture\n";
  exit;
}
// si genera un contenuto arbitrario
for ($i = 0; $i < 100; $i++) {
  fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
}
// si chiude il file
fclose($fic);

// lo si sfrutta - fgets mantiene il carattere di fine riga
// questo permette di non recuperare una stringa vuota durante la lettura di una riga vuota
// si apre in lettura
if (!$fic = fopen($INFOS, "r")) {
  print "Erreur d'ouverture du fichier $INFOS en lecture\n";
  exit;
}

// le righe contengono meno di 1000 caratteri
// la lettura della riga si interrompe al segno di fine riga
// o su quella di fine file
while ($ligne = fgets($fic, 1000)) {
  // si elimina il carattere di fine riga, se presente
  $ligne = cutNewLineChar($ligne);
  // si inserisce la riga in una tabella
  $infos = explode(":", $ligne);
  // si recupera il login
  $login = array_shift($infos);
  // si ignora la password
  array_shift($infos);
  // si crea una voce nel dizionario
  $dico[$login] = $infos;
}
// si chiude
fclose($fic);

// utilizzo del dizionario
afficheInfos($dico, "login10");
afficheInfos($dico, "X");

// fine
exit;

// --------------------------------------------------------------------------
function afficheInfos(array $dico, string $clé): void {
  // visualizza il valore associato alla chiave nel dizionario $dico se esiste
  if (isset($dico[$clé])) {
    // il valore esiste - è un array?
    $valeur = $dico[$clé];
    if (is_array($valeur)) {
      print "[$clé," . join(":", $valeur) . "]\n";
    } else {
      // $valeur non è un array
      print "[$clé,$valeur]\n";
    }
  } else {
    // $clé non è una chiave del dizionario $dico
    print "la clé [$clé] n'existe pas\n";
  }
}

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // si rimuove il carattere di fine riga da $ligne, se presente
  $L = strlen($ligne);  // lunghezza riga
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // fine
  return($ligne);
}

Il file infos.txt:

1
2
3
4
5
6
login0:pwd0:uid0:gid0:infos0:dir0:shell0
login1:pwd1:uid1:gid1:infos1:dir1:shell1
login2:pwd2:uid2:gid2:infos2:dir2:shell2
login98:pwd98:uid98:gid98:infos98:dir98:shell98
login99:pwd99:uid99:gid99:infos99:dir99:shell99

I risultati:


[login10,uid10:gid10:infos10:dir10:shell10]
la clé [X] n'existe pas

Commenti

  • riga 12: fopen(nom_fichier,"w") apre il file nom_fichier in modalità di scrittura (w=write). Se il file non esiste, viene creato. Se esiste, viene svuotato. Se la creazione non va a buon fine, fopen restituisce il valore false. Nell’istruzione if (!$fic = fopen($INFOS, "w")) {…}, sono presenti due operazioni successive: 1) $fic = fopen(..) 2) if( ! $fic) {…} ;
  • riga 18: fputs($fic,$chaîne) scrive chaîne nel file $fic. $chaine viene scritto con il carattere di fine riga \n alla fine;
  • riga 21: fclose($fic) chiude il file $fic;
  • riga 26: fopen(nom_fichier,"r") apre il file nom_fichier in lettura (r=read). Se l'apertura non va a buon fine (ad esempio, se il file non esiste), fopen restituisce il valore false;
  • riga 34: fgets($fic, 1000) legge la riga successiva del file entro il limite di 1000 caratteri. Nell’istruzione while ($ligne = fgets($fic, 1000)) {…}, sono presenti due operazioni successive: 1) $ligne = fgets(…) 2) while ( ! $ligne). Dopo che è stato letto l’ultimo carattere del file, la funzione fgets restituisce il valore false e il ciclo while si interrompe. La funzione fgets cerca qui di leggere al massimo 1000 caratteri, ma si interrompe non appena incontra un carattere di fine riga. Poiché in questo caso tutte le righe contengono meno di 1000 caratteri, [fgets] legge una riga di testo, compreso il carattere di fine riga. La funzione cutNewLineChar alle righe 75-84 elimina eventuali caratteri di fine riga;
  • riga 77: la funzione strlen($chaîne) restituisce il numero di caratteri di $chaîne;
  • riga 78: la funzione substr($ligne, $position, $taille) restituisce $taille caratteri di $ligne, a partire dal carattere n. $position, dove il primo carattere ha il numero 0. Sui sistemi Windows, il carattere di fine riga è "\r\n". Sui sistemi Unix, è la stringa "\n";
  • riga 40: la funzione array_shift($tableau) elimina il primo elemento di $tableau e lo restituisce come risultato. In questo caso si trascura il risultato restituito da array_shift;
  • riga 62: la funzione is_array($variable) restituisce true se $variable è un array, altrimenti restituisce false;
  • riga 63: la funzione join fa la stessa cosa della funzione implode già vista;

3.10. Codifica / decodifica jSON

Image

La codifica / decodifica jSON (JavaScript Object Notation) è un argomento che utilizzeremo ampiamente nell'esercizio che funge da filo conduttore del documento. Gli script [json-01.php, json-02.php, json-03.php] spiegano ciò che è necessario sapere per proseguire.

Lo script [json-01.php] è il seguente:


<?php

$array1 = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34];
// codifica JSON dell'array array1 con caratteri Unicode con escape
print "encodage json du tableau array1 avec caractères Unicode échappés\n";
$json1 = json_encode($array1);
print "json1=$json1\n";
// codifica JSON dell'array array1 con caratteri Unicode non con caratteri di escape
print "encodage json du tableau array1 avec caractères Unicode non échappés\n";
$json2 = json_encode($array1, JSON_UNESCAPED_UNICODE);
print "json2=$json2\n";
// decodifica di jSON in array associativo
print "décodage jSON de json2 dans tableau associatif\n";
$array2 = json_decode($json2, true);
var_dump($array2);
foreach ($array2 as $key => $value) {
  print "$key:$value\n";
}
// decodifica di jSON in oggetto
print "décodage jSON de json2 dans objet stdClass\n";
$array2 = json_decode($json2);
var_dump($array2);
print "prénom=$array2->prénom\n";
print "nom=$array2->nom\n";
print "âge=$array2->âge\n";

Risultati

encodage json du tableau array1 avec caractères Unicode échappés
json1={"nom":"s\u00e9l\u00e9n\u00e9","pr\u00e9nom":"b\u00e9n\u00e9dicte","\u00e2ge":34}
encodage json du tableau array1 avec caractères Unicode non échappés
json2={"nom":"séléné","prénom":"bénédicte","âge":34}
décodage jSON de json2 dans tableau associatif
array(3) {
  ["nom"]=>
  string(9) "séléné"
  ["prénom"]=>
  string(11) "bénédicte"
  ["âge"]=>
  int(34)
}
nom:séléné
prénom:bénédicte
âge:34
décodage jSON de json2 dans objet stdClass
object(stdClass)#1 (3) {
  ["nom"]=>
  string(9) "séléné"
  ["prénom"]=>
  string(11) "bénédicte"
  ["âge"]=>
  int(34)
}
prénom=bénédicte
nom=séléné
âge=34

Commenti

  • riga 6 del codice: la funzione [json_encode] trasforma il proprio parametro nella stringa jSON;
  • riga 2 dei risultati: la stringa jSON generata. I caratteri Unicode éâ sono stati sostituiti dal loro codice Unicode che inizia con \u;
  • riga 10 del codice: si ripete la stessa operazione, questa volta specificando che i caratteri Unicode vengano mantenuti così come sono;
  • riga 4 dei risultati: la stringa risultante jSON. È molto più leggibile;
  • righe 14-18 del codice: si esegue l'operazione inversa. Si trasforma una stringa jSON in un array associativo;
  • righe 6-13 dei risultati: si vede che è stato recuperato un array associativo;
  • righe 19-25 del codice: si trasforma una stringa jSON in un oggetto di tipo [stdClass];
  • righe 18-25 dei risultati: si vede che è stato recuperato un oggetto di tipo [stdClass];
  • righe 23-25 del codice: l’attributo A di un oggetto O è indicato come [O→A];

È possibile codificare in jSON tabelle a più livelli, come mostra il seguente script [json-02.php]:


<?php

$array = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34,
  "mari" => ["nom" => "icariù", "prénom" => "ignacio", "âge" => 35],
  "enfants" => [
    ["prénom" => "angèle", "age" => 8],
    ["prénom" => "andré", "age" => 2],
  ]];
// codifica in formato jSON dell'array a più livelli
print "encodage jSON d'un tableau à plusieurs niveaux\n";
$json = json_encode($array, JSON_UNESCAPED_UNICODE);
print "json=$json\n";

Risultati


encodage jSON d'un tableau à plusieurs niveaux
json={"nom":"séléné","prénom":"bénédicte","âge":34,"mari":{"nom":"icariù","prénom":"ignacio","âge":35},"enfants":[{"prénom":"angèle","age":8},{"prénom":"andré","age":2}]}

Commenti

Nella stringa jSON:

  • gli array non associativi sono racchiusi tra parentesi quadre [] ;
  • gli array associativi sono racchiusi tra parentesi graffe {};

Lo script [json-03.php] mostra come utilizzare il seguente file jSON [famille.json]:


{
    "épouse": {
        "nom": "séléné",
        "prénom": "bénédicte",
        "âge": 34
    },
    "mari": {
        "nom": "icariù",
        "prénom": "ignacio",
        "âge": 35
    },
    "enfants": [
        {
            "prénom": "angèle",
            "age": 8
        },
        {
            "prénom": "andré",
            "age": 2
        }
    ]
}

Lo script [json-03.php] è il seguente:


<?php

// lettura del file jSON
$json = file_get_contents("famille.json");
// decodifica JSON in oggetto
$famille1 = json_decode($json);
print "----famille1\n";
var_dump($famille1);
// decodifica JSON in tabella associativa
print "----famille2\n";
$famille2 = json_decode($json, true);
var_dump($famille2);

Commenti

  • riga 4: la funzione [file_get_contents] legge il contenuto del file denominato [famille.json] e lo assegna alla variabile [$json];
  • la variabile viene quindi decodificata in un oggetto (righe 5-8) e in un array associativo (righe 9-12);

Risultati


----famille1
object(stdClass)#2 (3) {
  ["épouse"]=>
  object(stdClass)#1 (3) {
    ["nom"]=>
    string(9) "séléné"
    ["prénom"]=>
    string(11) "bénédicte"
    ["âge"]=>
    int(34)
  }
  ["mari"]=>
  object(stdClass)#3 (3) {
    ["nom"]=>
    string(7) "icariù"
    ["prénom"]=>
    string(7) "ignacio"
    ["âge"]=>
    int(35)
  }
  ["enfants"]=>
  array(2) {
    [0]=>
    object(stdClass)#4 (2) {
      ["prénom"]=>
      string(7) "angèle"
      ["age"]=>
      int(8)
    }
    [1]=>
    object(stdClass)#5 (2) {
      ["prénom"]=>
      string(6) "andré"
      ["age"]=>
      int(2)
    }
  }
}
----famille2
array(3) {
  ["épouse"]=>
  array(3) {
    ["nom"]=>
    string(9) "séléné"
    ["prénom"]=>
    string(11) "bénédicte"
    ["âge"]=>
    int(34)
  }
  ["mari"]=>
  array(3) {
    ["nom"]=>
    string(7) "icariù"
    ["prénom"]=>
    string(7) "ignacio"
    ["âge"]=>
    int(35)
  }
  ["enfants"]=>
  array(2) {
    [0]=>
    array(2) {
      ["prénom"]=>
      string(7) "angèle"
      ["age"]=>
      int(8)
    }
    [1]=>
    array(2) {
      ["prénom"]=>
      string(6) "andré"
      ["age"]=>
      int(2)
    }
  }
}

Commenti

  • righe 1-38: l’oggetto risultante dalla decodifica del file jSON [famille.json];
  • righe 39-76: l'array associativo risultante dalla decodifica del file jSON [famille.json];