Una funzione può essere definita usando la seguente sintassi:
Pseudo codice per dimostrare l'uso delle funzioni <?php function foo($arg_1, $arg_2, /* ..., */ $arg_n) { echo "Funzione di esempio.\n"; return $retval; } ?>
All'interno di una funzione può apparire qualunque codice PHP valido, persino altre funzioni e definizioni di classe.
I nomi di funzione seguono le stesse regole delle altre etichette PHP. Un
nome di funzione valido comincia con una lettera o un underscore, seguito
da un qualsiasi numero di lettere, numeri o underscore. Come espressione
regolare, questo viene rappresentato così:
^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$.
Le funzioni devono essere definite prima di essere referenziate tranne quando una funzione è definita condizionalmente come illustrato nei due esempi seguenti.
Quando una funzione è definita in modo condizionale, come illustrato nei seguenti esempi, occorre che ne venga processata prima la definizione poi venga chiamata la funzione stessa.
Funzioni condizionali <?php $makefoo = true; /* Qui non possiamo chiamare foo() poiché non esiste ancora, ma possiamo chiamare bar() */ bar(); if ($makefoo) { function foo() { echo "Io non esisto sino a quando il programma non mi raggiunge.\n"; } } /* Ora possiamo chiamare foo() poiché $makefoo vale true */ if ($makefoo) foo(); function bar() { echo "Io esco immediatamente dopo l'avvio del programma.\n"; } ?>
Funzioni dentro a funzioni <?php function foo() { function bar() { echo "Io non esiste fino a quando non si esegue foo().\n"; } } /* Non possiamo chiamare bar() poiché non esiste ancora. */ foo(); /* Ora si può eseguire bar(), l'elaborazione di foo() l'ha resa accessibile. */ bar(); ?>
Tutte le funzioni e le classi, in PHP, hanno visibilità globale - possono essere chiamate dall'esterno di una funzione anche se sono definite all'interno di questa e vice-versa.
PHP non supporta l'overloading di funzioni, non è possibile indefinire o ridefinire funzioni precedentemente dichiarate.
A a Z, ma, solitamente, è
buona norma richiamare le funzioni nel modo con cui sono state definite.
Sia un numero variabile di argomenti che gli argomenti di default sono ammessi nelle funzioni. Vedere anche i riferimenti alle funzioni func_num_args, func_get_arg e func_get_args per maggiori informazioni.
In PHP è possibile utilizzare le chiamate a funzioni ricorsive. Funzioni ricorsive <?php function recursion($a) { if ($a < 20) { echo "$a\n"; recursion($a + 1); } } ?> Funzioni/metodi ricorsivi con oltre 100-200 livelli di ricorsione possono riempire lo stack e causare la terminazione dello script corrente. In particolare, la ricorsione infinita è considerata un errore di programmazione.
L'informazione può essere passata alle funzioni tramite la lista degli argomenti, che sono liste di espressioni delimitati dalla virgola. Gli argomenti sono valutati da sinistra a destra, prima che la funzione venga effettivamente chiamata (valutazione eager).
PHP supporta il passaggio di argomenti per valore (comportamento di default), il passaggio per riferimento, e i valori di default degli argomenti. Le liste di argomenti di lunghezza varabile e i Named Arguments sono ugualmente supportati.
Passaggio di array a funzioni <?php function prende_array($input) { echo "$input[0] + $input[1] = ", $input[0]+$input[1]; } ?>
A partire da PHP 8.0.0, l'elenco degli argomenti della funzione può includere una virgola finale, che verrà ignorata. Ciò è particolarmente utile nei casi in cui l'elenco di argomenti è lungo o contiene nomi di variabili lunghi, rendendo conveniente elencare gli argomenti verticalmente.
Elenco degli Argomenti della Funzione con Virgola finale
<?php
function takes_many_args(
$first_arg,
$second_arg,
$a_very_long_argument_name,
$arg_with_default = 5,
$again = 'a default string', // Questa virgola finale non era consentita prima della 8.0.0.
)
{
// ...
}
?>
A partire da PHP 8.0.0, dichiarare argomenti obbligatori dopo argomenti opzionali
è deprecato. Questo può essere generalmente risolto eliminando il valore predefinito.
Un'eccezione a questa regola sono gli argomenti nella forma
Type $param = null, dove il default null rende il tipo implicitamente
annullabile. Questo utilizzo rimane consentito, sebbene si consiglia di utilizzare invece
un tipo nullable esplicito.
Dichiarazione di argomenti facoltativi dopo argomenti obbligatori
<?php
function foo($a = [], $b) {} // Prima
function foo($a, $b) {} // Dopo
function bar(A $a = null, $b) {} // Ancora consentito
function bar(?A $a, $b) {} // Consigliato
?>
Passare argomenti per riferimento
Di default, gli argomenti della funzione sono passati per valore (così se cambiate il valore dell'argomento all'interno della funzione , esso non cambierà fuori della funzione). Se volete permettere ad una funzione di modificare i suoi argomenti, dovete passarli per riferimento.
Se volete che una argomento sia passato sempre per riferimento ad una funzione, dovete anteporre un ampersand (Amp) al nome dell'argomento nella definizione della funzione:
Passaggio di parametri per riferimento <?php function aggiungi_qualcosa(&$string) { $string .= 'e qualche altra cosa.'; } $str = 'Questa è una stringa, '; aggiungi_qualcosa($str); echo $str; // l'output sarà 'Questa è una stringa, e qualche altra cosa.' ?>
È un errore passare un valore come argomento che dovrebbe essere passato per riferimento.
Valori predefiniti degli argomenti
Una funzione può definire valori predefiniti in stile C++ per argomenti scalari come segue:
Utilizzo dei parametri default in una funzione <?php function fare_il_caffe($tipo = "cappuccino") { return "Sto facendo una tazza di $tipo.\n"; } echo fare_il_caffe(); echo fare_il_caffe(null); echo fare_il_caffe("espresso"); ?> Example outputs Sto facendo una tazza di cappuccino. Sto facendo una tazza di. Sto facendo una tazza di espresso.
Anche il PHP permette di utilizzare array ed il tipo speciale null
come valore di default, ad esempio:
Utilizzo di tipi non scalari come valori di default <?php function makecoffee($types = array("cappuccino"), $coffeeMaker = NULL) { $device = is_null($coffeeMaker) ? "hands" : $coffeeMaker; return "Making a cup of ".join(", ", $types)." with $device.\n"; } echo makecoffee(); echo makecoffee(array("cappuccino", "lavazza"), "teapot"); ?>
Il valore predefinito deve essere un'espressione costante, non (per esempio) una variabile, un membro di classe o una chiamata ad una funzione.
Da notare che quando vengono usati argomenti predefiniti, qualunque argomento predefinito dovrebbe essere a destra degli argomenti non-predefiniti; diversamente, le cose non funzioneranno come ci si aspetti. Si consideri il seguente frammento di codice:
Utilizzo incorretto degli argomenti di default <?php function fare_lo_yogurt($tipo = "yogurt", $gusto) { return "Fare una vaschetta di $tipo a $gusto.\n"; } echo fare_lo_yogurt("fragola"); // non funziona come si aspetta ?> Example outputs Warning: Missing argument 2 in call to fare_lo_yogurt() in /usr/local/etc/httpd/htdocs/phptest/functest.html on line 41 Fare una vaschetta di fragola a.
Ora, si confronti il codice di sopra con questo:
Utilizzo corretto degli argomenti di default <?php function fare_lo_yogurt($gusto, $tipo = "yogurt") { return "Fare una vaschetta di $tipo a $gusto.\n"; } echo fare_lo_yogurt("fragola"); // funziona come si aspetta ?> Example outputs Fare una vaschetta di yogurt a fragola.
Liste di argomenti a lunghezza variabile
PHP ha il supporto per le liste di argomenti a lunghezza variabile nelle
funzioni definite dall'utente utilizzando il
token ....
....
Le liste dei parametri possono includere il token
... per denotare che la funzione accetta un
numero variabile di parametri. I parametri saranno passati nella
variabile data come un array; per esempio:
Utilizzo di ... per accedere ai parametri variabili
<?php
function sum(...$numbers) {
$acc = 0;
foreach ($numbers as $n) {
$acc += $n;
}
return $acc;
}
echo sum(1, 2, 3, 4);
?>
Example outputs
10
Si può anche usare ... quando vengono chiamate funzioni per spacchettare
un array o una variabile Traversable o
literal all'interno della lista degli argomenti:
Uso di ... per fornire parametri
<?php
function add($a, $b) {
return $a + $b;
}
echo add(...[1, 2])."\n";
$a = [1, 2];
echo add(...$a);
?>
Example outputs
3
3
Si possono specificare parametri con posizione normale prima del
token .... In questo caso, solo i parametri seguenti
che non corrispondono ad un parametro posizionale saranno aggiunti all'array
generato da ....
È anche possibile aggiungere una
dichiarazione di tipo prima del
token .... Se questa è presente, allora tutti i parametri
catturati da ... devono corrispondere a quel tipo di parametro.
Parametri variabili con tipo dichiarato
<?php
function total_intervals($unit, DateInterval ...$intervals) {
$time = 0;
foreach ($intervals as $interval) {
$time += $interval->$unit;
}
return $time;
}
$a = new DateInterval('P1D');
$b = new DateInterval('P2D');
echo total_intervals('d', $a, $b).' days';
// Questo fallirà, dato che null non è un oggetto DateInterval.
echo total_intervals('d', null);
?>
Example outputs
3 days
Catchable fatal error: Argument 2 passed to total_intervals() must be an instance of DateInterval, null given, called in - on line 14 and defined in - on line 2
Infine, si possono anche passare parametri variabili
per riferimento
anteponendo ... con un ampersand
(Amp).
Non è richiesta una sintassi speciale per annotare che una funzione è variadica; tuttavia per accedere ai parametri della funzione bisogna usare func_num_args, func_get_arg e func_get_args.
Il primo esempio di sopra sarebbe implementato come segue in vecchie versioni di PHP: Accesso ai parametri variabili in vecchie versioni di PHP <?php function sum() { $acc = 0; foreach (func_get_args() as $n) { $acc += $n; } return $acc; } echo sum(1, 2, 3, 4); ?> Example outputs 10
Argomenti Nominali
PHP 8.0.0 ha introdotto argomenti nominali come estensione dei parametri posizionali esistenti. Gli argomenti nominali consentono di passare argomenti ad una funzione in base al nome del parametro, piuttosto che alla posizione del parametro. Ciò rende il significato dell'argomento auto-documentante, rende gli argomenti indipendenti dall'ordine e consente di saltare arbitrariamente i valori predefiniti.
Gli argomenti nominali vengono passati anteponendo al valore il nome del parametro seguito da due punti. È consentito l'utilizzo di parole chiave riservate come nomi di parametri. Il nome del parametro deve essere un identificatore, non è consentito specificarlo dinamicamente.
Sintassi dell'argomento denominato
<?php
myFunction(paramName: $value);
array_foobar(array: $value);
// NON supportato.
function_name($variableStoringParamName: $value);
?>
Argomenti posizionali contro argomenti nominali
<?php
// Utilizzo di argomenti posizionali:
array_fill(0, 100, 50);
// Utilizzo di argomenti nominali:
array_fill(start_index: 0, count: 100, value: 50);
?>
L'ordine in cui vengono passati gli argomenti nominali non ha importanza.
Stesso esempio di sopra con un diverso ordine dei parametri
<?php
array_fill(value: 50, count: 100, start_index: 0);
?>
Gli argomenti nominali possono essere combinati con argomenti posizionali. In questo caso, gli argomenti nominali devono venire dopo gli argomenti posizionali. È anche possibile specificare solo alcuni degli argomenti opzionali di una funzione, indipendentemente dal loro ordine.
Combinazione di argomenti nominali con argomenti posizionali
<?php
htmlspecialchars($string, double_encode: false);
// Uguale a
htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401, 'UTF-8', false);
?>
Il passaggio multiplo dello stesso parametro genera un'eccezione Error.
Eccezione Error durante il passaggio multiplo dello stesso parametro
<?php
function foo($param) { ... }
foo(param: 1, param: 2);
// Error: Named parameter $param overwrites previous argument
foo(1, param: 2);
// Error: Named parameter $param overwrites previous argument
?>
I valori vengono restituiti usando l'istruzione opzionale return. Può essere restituito qualsiasi tipo, incluse liste ed oggetti. Ciò provoca l'interruzione dell'esecuzione della funzione immediatamente e la restituzione del controllo alla linea da cui è stata chiamata. Vedere return per maggiori informazioni.
null.
Uso di return
Uso di return <?php function quadrato ($num) { return $num * $num; } echo quadrato(4); // L'output è '16'. ?>
Una funzione non può restituire valori multipli, ma risultati simili possono essere ottenuti restituendo un array.
Restituzione di un array per ottenere più valori <?php function numeri_piccoli() { return [0, 1, 2]; } // La destrutturazione dell'array raccoglierà ogni membro dell'array individualmente [$zero, $one, $two] = small_numbers(); // Prima della 7.1.0, l'unica alternativa equivalente è usare il costrutto list() list($zero, $one, $two) = small_numbers(); ?>
Per restituire un riferimento da una funzione, è necessario usare l'operatore di passaggio per riferimento Amp in entrambe le dichiarazioni di funzioni e quando viene assegnato il valore restituito ad una variabile:
Restituzione di un riferimento da una funzione <?php function &restituisce_riferimento() { return $un_riferimento; } $nuovo_riferimento =& restituisce_riferimento(); ?>
Per maggiori informazioni sui riferimenti, consultare iRiferimenti Spiegati.
PHP supporta il concetto di funzioni variabili. Ciò significa che se un nome di variabile ha le parentesi accodate ad esso, PHP cercherà una funzione con lo stesso nome del valore della variabile, e cercherà di eseguirla. Tra le altre cose, ciò puo essere usato per implementare delle callbacks, tabelle di funzioni e così via.
Le funzioni variabili non funzionano con costrutti di linguaggio come echo, print, unset, isset, empty, include, require e simili. Occorre costruire una propria funzione per utilizzare questi costrutti come variabili per funzioni.
Esempio di funzioni variabili <?php function foo() { echo "In foo()<br />\n"; } function bar($arg = '') { echo "In bar(); l'argomento era '$arg'.<br />\n"; } // Questa è la funzione per usare echo function echoit($string) { echo $string; } $func = 'foo'; $func(); // questa chiama foo() $func = 'bar'; $func('test'); // questa chiama bar() $func = 'echoit'; $func('test'); // questa chiama echoit() ?>
Tramite le funzioni variabili si possono eseguire anche metodi di oggetti. Esempio di un metodo variabile <?php class Foo { function Variable() { $name = 'Bar'; $this->$name(); // Questo esegue il metodo Bar() } function Bar() { echo "This is Bar"; } } $foo = new Foo(); $funcname = "Variable"; $foo->$funcname(); // Questo esegue $foo->Variable() ?>
Quando si chiamano dei metodi statici, la chiamata a funzione ha la precedenza sull'operatore di proprietà statica: Esempio di metodo variabile con proprietà statiche <?php class Foo { static $variable = 'static property'; static function Variable() { echo 'Method Variable called'; } } echo Foo::$variable; // Questo stampa 'static property'. Non ha bisogno di una $variable in questo ambito. $variable = "Variable"; Foo::$variable(); // Questo chiama $foo->Variable() leggendo $variable da questo ambito. ?>
Callable complesse <?php class Foo { static function bar() { echo "bar\n"; } function baz() { echo "baz\n"; } } $func = array("Foo", "bar"); $func(); // stampa "bar" $func = array(new Foo, "baz"); $func(); // stampa "baz" $func = "Foo::bar"; $func(); // stampa "bar" ?>
is_callable call_user_func function_exists varabili di variabile
Il PHP possiede diverse funzioni e costrutti standard. Esistono, inoltre, funzioni che richiedono la compila di specifici moduli del PHP, altrimenti si ottiene l'errore "undefined function" errors. Ad esempio, per utilizzare le funzioni image, tipo imagecreatetruecolor, occorre che il PHP sia compilato con il supporto GD. Oppure, per utilizzare mysqli_connect occorre che il PHP sia compilato con il supporto per MySQL. Esistono anche diverse funzioni di base incluse in ogni versione del PHP tipo le funzioni stringa e per variabili. L'esecuzione di phpinfo o di get_loaded_extensions visualizzerà quali moduli sono caricati nel PHP. Inoltre si noti che diverse estensioni sono abilitate per default e che il manule PHP è suddiviso per estensione. Vedere i capitoli configurazione, installazione, ed i capitoli dei singoli moduli per avere maggiori dettagli su come configurare il PHP.
Come leggere e comprendere il prototipo di una funzione è spiegato nella sezione del manuale intitolata come leggere la definizione di una funzione. E' importante comprendere che cosa restituisce una funzione o se una funzione lavora direttamente sui dati passati. Ad esempio str_replace restituisce la stringa modificata, mentre usort lavora sulla variabile passata. Ciascuna pagina del manuale fornisce informazioni specifiche per ogni funzione tipo notizie sui parametri, modifiche di funzionamento, valori restituiti in caso di successo o di errore, ed altre informazioni disponibili. La conoscenza di queste differenze importanti è cruciale per la scrittura di codice PHP corretto.
null ma questa è solo una convenzione, e non ci si può fare
affidamento.
A partire da PHP 8.0.0, in questo caso dovrebbe essere generata un'eccezione
TypeError.
function_exists the function reference get_extension_funcs dl
Le funzioni anonime, chiamate anche chiusure o closures, permettono la
creazione di funzioni che non possiedono un nome. Sono molto utili come
valore dei parametri callable,
ma hanno molti altri utilizzi.
Le funzioni anonime sono implementate usando la classe Closure.
Esempio di funzione anonima
<?php
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
// stampa helloWorld
?>
Le chiusure possono essere usate anche come valore di una variabile; il PHP converte automaticamente queste espressioni in istanze della classe interna Closure. L'assegnazione di una chiusura a una variabile usa la stessa sintassi di un qualsiasi altro assegnazione, incluso il punto e virgola alla fine:
Esempio di assegnazione di funzione anonima
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
Le chiusure possono anche ereditare le variabili dal contesto del genitore. Ognuna di queste
variabili deve essere passata al costrutto del linguaggio use.
A partire da PHP 7.1, queste variabili non devono includere Link superglobals,
$this, o variabili con lo stesso nome di un parametro.
Una dichiarazione del tipo di ritorno della funzione deve essere posta
dopo la clausola use.
Ereditare variabili dal contesto del genitore
<?php
$message = 'hello';
// Nessun "use"
$example = function () {
var_dump($message);
};
$example();
// Eredita $message
$example = function () use ($message) {
var_dump($message);
};
$example();
// Il valore della variabile ereditata è da quando la funzione
// è definita, non quando chiamata
$message = 'world';
$example();
// Resetta il messaggio
$message = 'hello';
// Eredita per riferimento
$example = function () use (&$message) {
var_dump($message);
};
$example();
// Il valore cambiato nel contesto del genitore
// è riflesso all'interno della chiamata della funzione
$message = 'world';
$example();
// Le closure possono anche accettare argomenti regolari
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello");
// La dichiarazione del tipo di ritorno viene dopo la clausola use
$example = function () use ($message): string {
return "hello $message";
};
var_dump($example());
?>
Notice: Undefined variable: message in /example.php on line 6
NULL
string(5) "hello"
string(5) "hello"
string(5) "hello"
string(5) "world"
string(11) "hello world"
string(11) "hello world"
A partire da PHP 8.0.0, l'elenco delle variabili ereditate dallo scope può includere una virgola finale, che verrà ignorata.
Ereditare le variabili dall'ambito genitore non è la stessa cosa che usare variabili globali. Le variabili globali esistono nell'ambito globale, che è lo stesso, indipendentemente da quale funzione è in esecuzione. L'ambito genitore di una chiusura è la funzione nella quale la chiusura è stata dichiarata (non necessariamente la funzione da cui è stata chiamata). Si veda l'esempio seguente:
Chiusure e ambiti di visibilità
<?php
// Un semplice paniere che contiene una lista di prodotti aggiunti
// e la quantità di ciascun prodotto. Include un metodo che
// calcola il prezzo totale degli articoli nel paniere utilizzando
// una chiusura come callback.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$my_cart = new Cart;
// Aggiunta di un elemento nel paniere
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Stampa del totale con una tassa aggiuntiva del 5%.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>
Binding automatico di
<?php
class Test
{
public function testing()
{
return function() {
var_dump($this);
};
}
}
$object = new Test;
$function = $object->testing();
$function();
?>
object(Test)#1 (0) {
}
Quando dichiarata all'interno del contesto di una classe, la classe corrente è
automaticamente legata ad essa, rendendo $this disponibile
all'interno dello scope di una funzione. Se questo binding automatico della classe
corrente non è voluto, allora
possono essere invece usate le
funzioni anonime statiche.
Funzioni anonime statiche
Le funzioni anonime possono essere dichiarate staticamente. Questo impedisce loro di avere la classe corrente automaticamente legata ad esse. Gli oggetti possono anche non essere legati a loro in fase di esecuzione.
Tentativo di utilizzo di $this all'interno di una funzione anonima statica
<?php
class Foo
{
function __construct()
{
$func = static function() {
var_dump($this);
};
$func();
}
};
new Foo();
?>
Example outputs
Notice: Undefined variable: this in %s on line %d
NULL
Tentativo di legare un oggetto ad una funzione anonima statica <?php $func = static function() { // function body }; $func = $func->bindTo(new StdClass); $func(); ?> Example outputs Warning: Cannot bind an instance to a static closure in %s on line %d
Version Description 7.1.0 Le funzioni anonime non possono catturare Link superglobals, $this, o qualsiasi variabile con lo stesso nome di un parametro nel contesto in cui sono definite.
Le arrow function sono state introdotte in PHP 7.4 come sintassi più concisa per le funzioni anonime.
Sia le funzioni anonime che le arrow function sono implementate usando la classe Closure.
Le arrow function hanno la forma base
fn (argument_list) =Gt expr.
Le arrow function supportano le stesse funzionalità delle funzioni anonime, eccetto che l'uso delle variabili dallo scope padre è sempre automatico.
Quando una variabile usata nell'espressione è definita nello scope padre essa sarà implicitamente catturata per valore. Nel seguente esempio, le funzioni $fn1 e $fn2 si comportano allo stesso modo.
Le arrow function catturano variabili per valore automaticamente <?php $y = 1; $fn1 = fn($x) => $x + $y; // equivalent all'utilizzo di $y per valore: $fn2 = function ($x) use ($y) { return $x + $y; }; var_export($fn1(3)); ?> Example outputs 4
Questo funziona anche se le arrow function sono nidificate:
Le arrow function catturano variabili per valore automaticamente, anche quando nidificate <?php $z = 1; $fn = fn($x) => fn($y) => $x * $y + $z; // Produce 51 var_export($fn(5)(10)); ?>
Analogamente alle funzioni anonime, la sintassi delle arrow function permette firme di funzioni arbitrarie, inclusi parametri e tipi di ritorno, valori di default, variadiche, così come passaggio di parametri e ritorno per riferimento. Tutti i seguenti sono esempi validi di arrow function:
Esempi di arrow function <?php fn(array $x) => $x; static fn(): int => $x; fn($x = 42) => $x; fn(&$x) => $x; fn&($x) => $x; fn($x, ...$rest) => $rest; ?>
Le arrow function usano il binding della variabili per valore.
Questo è grossomodo equivalente ad eseguire uno use($x) per ogni
variabile $x usata all'interno della arrow function.
Un binding per valore significa che non è possibile modificare qualsiasi valore
dallo scope esterno.
Le funzioni anonime
possono invece essere usate per il binding per riferimento.
I valori dello scope esterno non possono essere modificati dalle arrow function <?php $x = 1; $fn = fn() => $x++; // Non ha effetto $fn(); var_export($x); // Produce 1 ?>
Version Description 7.4.0 Le arrow function sono diventate disponibili.
La sintassi delle callable di prima classe è stata introdotta a partire da PHP 8.1.0, come un modo per creare funzioni anonime da callable. Sostituisce la sintassi delle callable esistente utilizzando stringhe ed array. Il vantaggio di questa sintassi è che è accessibile dall'analisi statica e utilizza lo scope nel punto in cui viene acquisita la callable.
La sintassi CallableExpr(...) viene utilizzata per creare un oggetto Closure dalla callable. CallableExpr accetta qualsiasi espressione che puó essere richiamata direttamente nella grammatica PHP:
Sintassi della callable di prima classe semplice
<?php
class Foo {
public function method() {}
public static function staticmethod() {}
public function __invoke() {}
}
$obj = new Foo();
$classStr = 'Foo';
$methodStr = 'method';
$staticmethodStr = 'staticmethod';
$f1 = strlen(...);
$f2 = $obj(...); // oggetto invocabile
$f3 = $obj->method(...);
$f4 = $obj->$methodStr(...);
$f5 = Foo::staticmethod(...);
$f6 = $classStr::$staticmethodStr(...);
// callable tradizionale usando string, array
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>
... fanno parte della sintassi e non sono un'omissione.
CallableExpr(...) ha la stessa semantica di Closure::fromCallable.
Ovvero, a differenza di callable che utilizzano stringhe e array, CallableExpr(...) rispetta lo scope nel punto in cui viene creato:
Confronto dello scope tra CallableExpr(...) e callable tradizionale
<?php
class Foo {
public function getPrivateMethod() {
return [$this, 'privateMethod'];
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Fatal error: Call to private method Foo::privateMethod() from global scope
// Questo perché la chiamata viene eseguita all'esterno di Foo e la visibilità verrà controllata da questo punto.
class Foo1 {
public function getPrivateMethod() {
// Utilizza lo scope in cui viene acquisita la callable.
return $this->privateMethod(...); // uguale a Closure::fromCallable([$this, 'privateMethod']);
}
private function privateMethod() {
echo __METHOD__, "\n";
}
}
$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>
new Foo(...)) non è supportata, perché la sintassi new Foo() non è considerata una chiamata.