PHP 8.4.0 RC4 available for testing

Dichiarazioni di tipo

Le dichiarazioni di tipo possono essere aggiunte agli argomenti delle funzioni, ai valori restituiti e, a partire da PHP 7.4.0, alle proprietà di classe. Assicurano che il valore sia del tipo specificato al momento della chiamata, altrimenti viene generato un TypeError.

Nota:

Quando si sovrascrive un metodo genitore, il metodo del figlio deve corrispondere a qualsiasi dichiarazione del tipo restituito sul genitore. Se il genitore non definisce un tipo restituito, allora il metodo figlio può farlo.

Tipi singoli

Tipo Descrizione Versione
Nome di classe/interfaccia Il valore deve essere un'instanceof della classe o dell'interfaccia data.  
self Il valore deve essere un'instanceof della stessa classe di quella in cui viene utilizzata la dichiarazione del tipo. Può essere utilizzato solo nelle classi.  
parent Il valore deve essere un'instanceof del genitore della classe in cui viene utilizzata la dichiarazione del tipo. Può essere utilizzato solo nelle classi.  
array Il valore deve essere un array.  
callable Il valore deve essere una callable valida. Non può essere utilizzato come dichiarazione del tipo di proprietà della classe.  
bool Il valore deve essere un valore booleano.  
float Il valore deve essere un numero in virgola mobile.  
int Il valore deve essere un numero intero.  
string Il valore deve essere una string.  
iterable Il valore deve essere un array o un'instanceof Traversable. PHP 7.1.0
object Il valore deve essere un object. PHP 7.2.0
mixed Il valore può essere qualsiasi valore. PHP 8.0.0
Avviso

Gli alias per i tipi scalari di sopra non sono supportati. Vengono invece trattati come nomi di classi o interfacce. Ad esempio, usando boolean come dichiarazione di tipo richiederà che il valore sia un instanceof della classe o dell'interfaccia boolean, invece che di tipo bool:

<?php
function test(boolean $param) {}
test(true);
?>

Output of the above example in PHP 8:

Warning: "boolean" will be interpreted as a class name. Did you mean "bool"? Write "\boolean" to suppress this warning in /in/9YrUX on line 2

Fatal error: Uncaught TypeError: test(): Argument #1 ($param) must be of type boolean, bool given, called in - on line 3 and defined in -:2
Stack trace:
#0 -(3): test(true)
#1 {main}
  thrown in - on line 2

mixed

mixed è equivalente al tipo union object|resource|array|string|int|float|bool|null. Disponibile a partire da PHP 8.0.0.

Esempi

Example #1 Dichiarazione di base del tipo classe

<?php
class C {}
class
D extends C {}

// Questa non estende C.
class E {}

function
f(C $c) {
echo
get_class($c)."\n";
}

f(new C);
f(new D);
f(new E);
?>

Output of the above example in PHP 8:

C
D

Fatal error: Uncaught TypeError: f(): Argument #1 ($c) must be of type C, E given, called in /in/gLonb on line 14 and defined in /in/gLonb:8
Stack trace:
#0 -(14): f(Object(E))
#1 {main}
  thrown in - on line 8

Example #2 Dichiarazione di base del tipo interfaccia

<?php
interface I { public function f(); }
class
C implements I { public function f() {} }

// Questa non implementa I.
class E {}

function
f(I $i) {
echo
get_class($i)."\n";
}

f(new C);
f(new E);
?>

Output of the above example in PHP 8:

C

Fatal error: Uncaught TypeError: f(): Argument #1 ($i) must be of type I, E given, called in - on line 13 and defined in -:8
Stack trace:
#0 -(13): f(Object(E))
#1 {main}
  thrown in - on line 8

Example #3 Dichiarazione di base del tipo restituito

<?php
function sum($a, $b): float {
return
$a + $b;
}

// Notare che verrà restituito un float.
var_dump(sum(1, 2));
?>

Il precedente esempio visualizzerà:

float(3)

Example #4 Restituzione di un oggetto

<?php
class C {}

function
getC(): C {
return new
C;
}

var_dump(getC());
?>

Il precedente esempio visualizzerà:

object(C)#1 (0) {
}

Tipo nullable

A partire da PHP 7.1.0, le dichiarazioni di tipo possono essere contrassegnate come nullable anteponendo al nome del tipo un punto interrogativo (?). Ciò significa che il valore può essere del tipo specificato o null.

Example #5 Dichiarazione del tipo di argomento nullable

<?php
class C {}

function
f(?C $c) {
var_dump($c);
}

f(new C);
f(null);
?>

Il precedente esempio visualizzerà:

object(C)#1 (0) {
}
NULL

Example #6 Dichiarazione del tipo restituito nullable

<?php
function get_item(): ?string {
if (isset(
$_GET['item'])) {
return
$_GET['item'];
} else {
return
null;
}
}
?>

Nota:

È possibile ottenere argomenti nullable rendendo null il valore predefinito. Questo non è raccomandato in quanto si interrompe durante l'eredità.

Example #7 Vecchio modo per rendere gli argomenti nullable

<?php
class C {}

function
f(C $c = null) {
var_dump($c);
}

f(new C);
f(null);
?>

Il precedente esempio visualizzerà:

object(C)#1 (0) {
}
NULL

Tipi compositi

È possibile combinare tipi semplici in tipi compositi. PHP consente di combinare i tipi nei seguenti modi:

  • Union di tipi semplici. A partire da PHP 8.0.0.
  • Intersezione di tipi di classi (interfacce e nomi di classi). A partire da PHP 8.1.0.
Attenzione

Non è possibile combinare i tipi di intersezione con i tipi union.

Tipi union

Una dichiarazione di tipo union accetta valori di più tipi semplici diversi, anziché uno solo. I tipi union vengono specificati utilizzando la sintassi T1|T2|.... I tipi union sono disponibili a partire da PHP 8.0.0.

Tipi union nullable

Il tipo null è supportato come parte delle union, in modo tale che T1|T2|null possa essere utilizzato per creare una union nullable. La notazione ?T esistente è considerata una scorciatoia per il caso comune di T|null.

Attenzione

null non può essere utilizzato come tipo autonomo.

Lo pseudotipo false

Il tipo letterale false è supportato come parte delle union ed è incluso poiché per ragioni storiche molte funzioni interne restituiscono false invece di null per gli errori. Un classico esempio di tale funzione è strpos().

Attenzione

false non può essere utilizzato come tipo autonomo (incluso il tipo autonomo nullable). Pertanto, false, false|null e ?false non sono consentiti.

Attenzione

Il tipo letterale true non esiste.

Tipi intersezione

Una dichiarazione di tipo intersezione accetta valori che soddisfano più dichiarazioni di tipo classe, anziché una singola. I tipi intersezione sono specificati utilizzando la sintassi T1&T2&.... I tipi intersezione sono disponibili a partire da PHP 8.1.0.

Tipi duplicati e ridondanti

Per rilevare semplici bug nelle dichiarazioni di tipo composito, i tipi ridondanti che possono essere rilevati senza eseguire il caricamento della classe risulteranno in un errore in fase di compilazione. Ciò comprende:

  • Ogni tipo risolto dal nome può verificarsi solo una volta. Tipi come int|string|INT o Countable&Traversable&COUNTABLE generano un errore.
  • L'utilizzo di mixed genera un errore.
  • Per i tipi union:
    • Se viene usato bool, false non può essere utilizzato in aggiunta.
    • Se viene usato object, i tipi di classe non possono essere utilizzati in aggiunta.
    • Se viene usato iterable, array e Traversable non possono essere utilizzati in aggiunta.
  • Per i tipi intersezione:
    • L'utilizzo di un tipo che non è un tipo di classe genera un errore.
    • L'utilizzo di self, parent o static genera un errore.

Nota: Ciò non garantisce che il tipo sia “minimo”, poiché ciò richiederebbe il caricamento di tutti i tipi di classe utilizzati.

Ad esempio, se A e B sono alias di classe, A|B rimane un tipo di union legale, anche se potrebbe essere ridotto a A o B. Allo stesso modo, se la classe B extends A {}, anche A|B è un tipo di union legale, anche se potrebbe essere ridotta solo a A.

<?php
function foo(): int|INT {} // Non consentito
function foo(): bool|false {} // Non consentito
function foo(): int&Traversable {} // Non consentito
function foo(): self&Traversable {} // Non consentito

use A as B;
function
foo(): A|B {} // Non consentito ("use" fa parte della risoluzione dei nomi)
function foo(): A&B {} // Non consentito ("use" fa parte della risoluzione dei nomi)

class_alias('X', 'Y');
function
foo(): X|Y {} // Consentito (la ridondanza è nota solo in fase di esecuzione)
function foo(): X&Y {} // Consentito (la ridondanza è nota solo in fase di esecuzione)
?>

Tipi di solo ritorno

void

void è un tipo di ritorno che indica che la funzione non restituisce un valore. Pertanto non può essere parte di una dichiarazione di tipo union. Disponibile da PHP 7.1.0.

Nota:

Il ritorno per riferimento da una funzione void è deprecato a partire da PHP 8.1.0, perché tale funzione è contraddittoria. In precedenza, emetteva già il seguente E_NOTICE quando chiamata: Only variable references should be returned by reference.

<?php
function &test(): void {}
?>

never

never è un tipo di ritorno che indica che la funzione non ha un ritorno. Ciò significa che chiama exit(), genera un'eccezione o è un ciclo infinito. Pertanto non può essere parte di una dichiarazione di tipo union. Disponibile a partire da PHP 8.1.0.

never è, nel gergo della teoria dei tipi, il tipo inferiore. Significa che è il sottotipo di ogni altro tipo e può sostituire qualsiasi altro tipo di ritorno durante l'ereditarietà.

static

Il valore deve essere un'instanceof della stessa classe di quella in cui è chiamato il metodo. Disponibile da PHP 8.0.0.

Tipizzazione strict

Per impostazione predefinita, PHP costringerà i valori del tipo sbagliato nella dichiarazione del tipo scalare previsto, se possibile. Ad esempio, una funzione a cui viene assegnato un int per un parametro che prevede una string otterrà una variabile di tipo string.

È possibile abilitare la modalità strict per file. In modalità strict, sarà accettato solo un valore corrispondente esattamente alla dichiarazione del tipo, altrimenti verrà lanciato un TypeError. L'unica eccezione a questa regola è che un valore int passerà una dichiarazione di tipo float.

Avviso

Le chiamate di funzione dall'interno delle funzioni interne non saranno influenzate dalla dichiarazione strict_types.

Per abilitare la modalità rigorosa, il declare viene utilizzato con la dichiarazione strict_types:

Nota:

La tipizzazione strict si applica alle chiamate di funzione effettuate all'interno del file con la tipizzazione strict abilitata, non alle funzioni dichiarate all'interno di quel file. Se un file senza la tipizzazione strict abilitata effettua una chiamata a una funzione che è stata definita in un file con la tipizzazione strict, la preferenza del chiamante (tipizzazione coercitiva) verrà rispettata e il valore verrà forzato.

Nota:

La tipizzazione strict è definita solo per le dichiarazioni di tipo scalare.

Example #8 Tipizzazione strict per i valori degli argomenti

<?php
declare(strict_types=1);

function
sum(int $a, int $b) {
return
$a + $b;
}

var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
?>

Output of the above example in PHP 8:

int(3)

Fatal error: Uncaught TypeError: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 9 and defined in -:4
Stack trace:
#0 -(9): sum(1.5, 2.5)
#1 {main}
  thrown in - on line 4

Example #9 Tipizzazione coercitiva per i valori degli argomenti

<?php
function sum(int $a, int $b) {
return
$a + $b;
}

var_dump(sum(1, 2));

// Questi verranno convertiti in numeri interi: nota l'output qui sotto!
var_dump(sum(1.5, 2.5));
?>

Il precedente esempio visualizzerà:

int(3)
int(3)

Example #10 Tipizzazione strict per i valori di ritorno

<?php
declare(strict_types=1);

function
sum($a, $b): int {
return
$a + $b;
}

var_dump(sum(1, 2));
var_dump(sum(1, 2.5));
?>

Il precedente esempio visualizzerà:

int(3)

Fatal error: Uncaught TypeError: sum(): Return value must be of type int, float returned in -:5
Stack trace:
#0 -(9): sum(1, 2.5)
#1 {main}
  thrown in - on line 5

Tipizzazione coercitiva con tipi union

Quando strict_types non è abilitato, le dichiarazioni di tipo scalare sono soggette a limitate coercizioni di tipo implicito. Se il tipo esatto del valore non fa parte della union, il tipo di destinazione viene scelto nel seguente ordine di preferenza:

  1. int
  2. float
  3. string
  4. bool
Se il tipo esiste nella union e il valore può essere forzato al tipo sotto la semantica di controllo del tipo esistente di PHP, viene scelto il tipo. Altrimenti viene provato il tipo successivo.

Attenzione

In via eccezionale, se il valore è una stringa e sia int che float fanno parte della union, il tipo preferito è determinato dalla semantica “stringa numerica” esistente. Ad esempio, per "42" viene scelto int, mentre per "42.0" viene scelto float.

Nota:

I tipi che non fanno parte dell'elenco di preferenze di cui sopra non sono obiettivi ammissibili per la coercizione implicita. In particolare non si verificano coercizioni implicite ai tipi null e false.

Example #11 Esempio di tipi che vengono forzati in un tipo parte della union

<?php
// int|string
42 --> 42 // tipo esatto
"42" --> "42" // tipo esatto
new ObjectWithToString --> "Risultato di __toString()"
// oggetto mai compatibile con int, ripiega su string
42.0 --> 42 // float compatibile con int
42.1 --> 42 // float compatibile con int
1e100 --> "1.0E+100" // float troppo grande per il tipo int, ripiega su string
INF --> "INF" // float troppo grande per il tipo int, ripiega su string
true --> 1 // bool compatibile con int
[] --> TypeError // array non compatibile con int o string

// int|float|bool
"45" --> 45 // stringa numerica intera
"45.0" --> 45.0 // stringa numerica float

"45X" --> true // non una stringa numerica, ripiega su bool
"" --> false // non una stringa numerica, ripiega su bool
"X" --> true // non una stringa numerica, ripiega su bool
[] --> TypeError // array non compatibile con int, float o bool
?>

Misc

Example #12 Parametri passati per referenza Tipizzati

I tipi dichiarati di parametri di referenza vengono controllati all'immissione della funzione, ma non quando la funzione ritorna, quindi dopo che la funzione ritorna, il tipo dell'argomento potrebbe essere cambiato.

<?php
function array_baz(array &$param)
{
$param = 1;
}
$var = [];
array_baz($var);
var_dump($var);
array_baz($var);
?>

Output of the above example in PHP 8:

int(1)

Fatal error: Uncaught TypeError: array_baz(): Argument #1 ($param) must be of type array, int given, called in - on line 9 and defined in -:2
Stack trace:
#0 -(9): array_baz(1)
#1 {main}
  thrown in - on line 2

Example #13 Cattura TypeError

<?php
declare(strict_types=1);

function
sum(int $a, int $b) {
return
$a + $b;
}

try {
var_dump(sum(1, 2));
var_dump(sum(1.5, 2.5));
} catch (
TypeError $e) {
echo
'Error: ', $e->getMessage();
}
?>

Output of the above example in PHP 8:

int(3)
Error: sum(): Argument #1 ($a) must be of type int, float given, called in - on line 10
add a note

User Contributed Notes 2 notes

up
22
toinenkayt (ta at ta) [iwonderr] gmail d
3 years ago
While waiting for native support for typed arrays, here are a couple of alternative ways to ensure strong typing of arrays by abusing variadic functions. The performance of these methods is a mystery to the writer and so the responsibility of benchmarking them falls unto the reader.

PHP 5.6 added the splat operator (...) which is used to unpack arrays to be used as function arguments. PHP 7.0 added scalar type hints. Latter versions of PHP have further improved the type system. With these additions and improvements, it is possible to have a decent support for typed arrays.

<?php
declare (strict_types=1);

function
typeArrayNullInt(?int ...$arg): void {
}

function
doSomething(array $ints): void {
(function (?
int ...$arg) {})(...$ints);
// Alternatively,
(fn (?int ...$arg) => $arg)(...$ints);
// Or to avoid cluttering memory with too many closures
typeArrayNullInt(...$ints);

/* ... */
}

function
doSomethingElse(?int ...$ints): void {
/* ... */
}

$ints = [1,2,3,4,null];
doSomething ($ints);
doSomethingElse (...$ints);
?>

Both methods work with all type declarations. The key idea here is to have the functions throw a runtime error if they encounter a typing violation. The typing method used in doSomethingElse is cleaner of the two but it disallows having any other parameters after the variadic parameter. It also requires the call site to be aware of this typing implementation and unpack the array. The method used in doSomething is messier but it does not require the call site to be aware of the typing method as the unpacking is performed within the function. It is also less ambiguous as the doSomethingElse would also accept n individual parameters where as doSomething only accepts an array. doSomething's method is also easier to strip away if native typed array support is ever added to PHP. Both of these methods only work for input parameters. An array return value type check would need to take place at the call site.

If strict_types is not enabled, it may be desirable to return the coerced scalar values from the type check function (e.g. floats and strings become integers) to ensure proper typing.
up
13
crash
3 years ago
The documentation lacks the information, that it's possible to change the return type of a method defined in an interface when the interface's methods return type is defined as `mixed`.

From the RFC:

"The mixed return type could be narrowed in a subclass as this is covariant and is allowed in LSP." (https://wiki.php.net/rfc/mixed_type_v2)

This means the following code is valid in PHP 8.0:

<?php

interface ITest
{
public function
apfel(): mixed; // valid as of 8.0
}

class
Test implements ITest
{
public function
apfel(): array // more explicit
{
return [];
}
}

var_dump((new Test())->apfel());
?>

You can see the result here: https://3v4l.org/PXDB6
To Top