Cos'è il type hinting, la sua evoluzione nelle varie versioni di PHP, ed il controllo sulla tipologia di dato con la modalità strict_mode.
Type Hinting è una funzionalità introdotta da PHP a partire dalla versione 5, che consente di specificare il tipo di oggetto/dato passato, come argomento, ad una funzione o ad un metodo.
Possiamo tradurlo come "suggerimento del tipo". Stiamo quindi dicendo al metodo (o alla funzione), che tipo di valore stiamo passando, come argomento, al metodo stesso (o alla funzione).
PHP, è un linguaggio a "tipizzazione dinamica" (o a "tipizzazione debole"): significa che non è necessario specificare il tipo di dati per le variabili o per i parametri delle funzioni, infatti PHP cerca di interpretarlo da solo, senza dichiararlo. Ed una variabile è in grado di cambiare, durante l’esecuzione del programma, la sua proprio tipologia (ad esempio una variabile da stringa diventa numerico).
A partire dalla versione 5, PHP ha introdotto la possibilità di dichiarare il tipo di dato assegnato ad un variabile e passato al metodo o alla funzione.
Possiamo dire al metodo, o alla funzione, che stiamo passando un dato di tipo array o class (a partire dalla versione 5 di PHP), o un tipo int, float, string, bool (dalla versione 7), o un object (dalla versione 7.2).
Forzando, con il type hinting, il tipo di dato in ingresso, PHP considererà valido il dato solo se è della tipologia indicata, in caso contrario avremo un "fatal error".
Esempio di Type Hinting: dato di tipo stringa
Vediamo un esempio in cui la funzione "printHello" accetta in ingresso solo valori di tipo stringa:
<?php
function printHello(string $name)
{
echo "Hello $name";
}
printHello('Elisa');
?>
Se lanciamo questo script, la funzione restituità "Hello Elisa".
Adesso modifichiamo la funzione affinchè accetti in ingresso solo dati di tipo numero intero (int)
<?php
function printHello(int $name)
{
echo "Hello $name";
}
printHello('Elisa');
?>
Rilanciamo lo script e riceveremo un errore fatale perchè PHP si aspetta di ricevere un dato di tipo int.
Fatal error: Uncaught TypeError: Argument 1 passed to printHello() must be of the type integer, string given, called in /var/www/whtml/test/index.php on line 6
Esempio di Type Hinting: dato di tipo array
Facciamo un nuovo esempio con un dato di tipo array.
<?php
function test(array $param) {
foreach($param as $a){
echo $a."<br>";
}
}
$ar=array("mario","elisa","luca");
test($ar);
?>
Questa funzione ricevere un array e quindi risponde con
mario
elisa
luca
Se invece passiamo alla funzione un dato con tipologia diversa, ad esempio una stringa, avremo un errore
<?php
function test(array $param) {
foreach($param as $a){
echo $a."<br>";
}
}
$ar="luca";
test($ar);
?>
L'errore sarà il seguente
Fatal error: Uncaught TypeError: Argument 1 passed to test() must be of the type array, string given, called in /var/www/html/test/index.php on line 9
Esempio di Type Hinting: le classi
Vediamo ancora un esempio con una funzione chiamata "infoStudent" che si aspetta in ingresso una istanza di una classe.
<?php
class Student {
public $name;
public function __construct($name){
$this->name = $name;
}
}
// la funzione accetta solo oggetti di tipo Student
function infoStudent(Student $student) {
echo "Ciao " . $student->name;
}
// istanzio un oggetto di classe Student
$obj = new Student("Mario");
// risponde con "Ciao Mario"
$info = infoStudent($obj);
// genera un errore fatale
$info = infoStudent("ciao");
?>
In questo esempio, abbiamo una classe chiamata "Student" che contiene un metodo costruttore, cioè un metodo che viene invocato automaticamente quando viene istanziato un oggetto di quella classe.
Istanziamo un oggetto $obj di classe "Student", e lo diamo in pasto alla funzione "infoStudent" che si aspetta di ricevere una istanza di una classe, per cui risponderà "Ciao Mario".
Abbiamo poi tentato di istanziare un nuovo oggetto di quella classe, passando una stringa: otteniamo questo errore
Fatal error: Uncaught TypeError: Argument 1 passed to infoStudent() must be an instance of Student, null given, called in /var/www/html/test/index.php on line 17
Controllo sui tipi: strict_type e wake_mode
Acquisita la logica di funzionamento, torniamo alla prima versione del nostro script in cui abbiamo dichiarato che in ingresso vogliamo ricevere una stringa, e proviamo a passare alla funzione un numero
<?php
function printHello(string $name)
{
echo "Hello $name";
}
printHello(3);
?>
Lanciamo lo script, e non riceviamo un errore bensì
Hello 3
Questo perchè di default, in PHP, è attiva la modalità "weak mode" (modalità debole): PHP proverà a "forzare" l'argomento e a trasformarlo nel tipo che la funzione sia aspetta di ricevere. Per cui PHP ha trasformato il numero 3 in una stringa.
Dalla versione 7 di PHP, in alternativa alla "weak mode" esiste la "strict mode" (modalità rigorosa): impostando questa modalità questa forzatura non ci sarà, ed otterremo un errore fatale.
Per cui, se vogliamo essere più restrittivi, e vogliamo accettare solo il formato string e non altri, come l'integer, dovrò dichiararlo in testa a tutto il codice php, tramite l'istruzione "declare" seguito da "strict_types=1"
<?php
declare(strict_types=1);
function printHello(string $name)
{
echo "Hello $name";
}
printHello(3);
?>
Adesso quel numero 3 resta un intero, e PHP rende un errore
Fatal error: Uncaught TypeError: Argument 1 passed to printHello() must be of the type string, integer given, called in /var/www/html/test/index.php on line 7
Nota: se avessimo passato in printHello il numero 3 tra virgolette, questo numero sarebbe stato passato come stringa e quindi accettata, perchè i numeri non vasso passati alla funzione, o al metodo, con apici o virgolette.
Type hinting in uscita
Dalla versione 7 di PHP è possibile dichiarare anche il tipo di dato restituito dai metodi / funzioni, quindi non solo il tipo di dato in ingresso.
Vediamo un esempio in cui la funzione "sum" deve restiuire un dato di tipo integer.
<?php
declare(strict_types=1);
function sum(int $a, int $b): int
{
return $a + $b;
}
echo sum(4, 6);
?>
Se lanciamo questo script il risultato sarà 10, mentre se lo modifichiamo in modo da restituire un numero con la virgola, cioè un float, avremo un fatal error
<?php
declare(strict_types=1);
function sum(int $a, int $b): int
{
return 4.4 + $b;
}
echo sum(4, 6);
?>
Rilanciamo il codice, ed ecco il fatal error.
Fatal error: Uncaught TypeError: Return value of sum() must be of the type integer, float returned in /var/www/html/test/index.php:6
Conclusioni
Possiamo concludere dicendo che l'utilizzo del Type Hinting ci consente di scrivere del codice più robusto ed anche più facile da leggere.
Potrebbe interessarti
- Le interfacce in PHP
- Le classi astratte e i metodi astratti, in PHP
- Le costanti di una classe in PHP
- Come estendere una classe in PHP ed il concetto di ereditarietà.
- Le proprietà e i metodi STATICI in PHP
- Il metodo costruttore in PHP
- Autoloading classi in PHP, con un occhio ai namespace ed allo standard di programmazione psr-4.
- I metodi magici in PHP.
- Cosa sono i namespace in PHP. La guida completa, con esempi.
- Cosa sono i trait in PHP. La guida completa con esempi.
- Le classi in PHP. introduzione alla programmazione in stile OOP, metodi e proprietà di una classe.