Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ

Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ появились Π² PHP 7.4 ΠΊΠ°ΠΊ Π»Π°ΠΊΠΎΠ½ΠΈΡ‡Π½Ρ‹ΠΉ синтаксис для Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹Ρ… Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ.

И Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹Π΅, ΠΈ стрСлочныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π»ΠΈ Ρ‡Π΅Ρ€Π΅Π· класс Closure.

Базовая Ρ„ΠΎΡ€ΠΌΠ° записи стрСлочных Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ: fn (argument_list) => expr.

Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Ρ‚Π°ΠΊ ΠΆΠ΅, ΠΊΠ°ΠΊ Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Π·Π° ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎ доступ ΠΊ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹ΠΌ Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠΉ области стрСлочныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽΡ‚ автоматичСски.

Когда стрСлочная функция Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ с ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Π² Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠΉ области, пСрСмСнная нСявно захватываСтся ΠΏΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ. Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ $fn1 ΠΈ $fn2 Π²Π΅Π΄ΡƒΡ‚ сСбя ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #1 Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π·Π°Ρ…Π²Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ автоматичСски

<?php

$y
= 1;

$fn1 = fn($x) => $x + $y;

// Π­ΠΊΠ²ΠΈΠ²Π°Π»Π΅Π½Ρ‚Π½ΠΎ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΡŽ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ $y ΠΏΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ:
$fn2 = function ($x) use ($y) {
return
$x + $y;
};

var_export($fn1(3));

Π Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ выполнСния ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π°:

4

Π­Ρ‚ΠΎ Ρ‚Π°ΠΊΠΆΠ΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π²ΠΎ Π²Π»ΠΎΠΆΠ΅Π½Π½Ρ‹Ρ… стрСлочных функциях:

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #2 Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π·Π°Ρ…Π²Π°Ρ‚Ρ‹Π²Π°ΡŽΡ‚ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ автоматичСски, Π΄Π°ΠΆΠ΅ ΠΊΠΎΠ³Π΄Π° Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π²Π»ΠΎΠΆΠ΅Π½Ρ‹

<?php

$z
= 1;
$fn = fn($x) => fn($y) => $x * $y + $z;

// Π’Ρ‹Π²Π΅Π΄Π΅Ρ‚ 51
var_export($fn(5)(10));

Как ΠΈ Π² Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹Ρ… функциях, синтаксис стрСлочных Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ допускаСт ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½Ρ‹Π΅ сигнатуры Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Ρ‚ΠΈΠΏΡ‹ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Ρ… Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ, значСния ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Ρƒ ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‚ ΠΏΠΎ ссылкС. ΠšΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ стрСлочных Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ:

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #3 ΠŸΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ опрСдСлСния стрСлочных Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΉ

<?php
fn(array $x) => $x;
static fn(
$x): int => $x;
fn(
$x = 42) => $x;
fn(&
$x) => $x;
fn&(
$x) => $x;
fn(
$x, ...$rest) => $rest;

Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΏΡ€ΠΈΠ²ΡΠ·Ρ‹Π²Π°ΡŽΡ‚ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ. Π­Ρ‚ΠΎ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ эквивалСнтно Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΡŽ конструкции use($x) для ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΠΎΠΉ $x, с ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΉ стрСлочная функция Π±ΡƒΠ΄Π΅Ρ‚ Ρ€Π°Π±ΠΎΡ‚Π°Ρ‚ΡŒ Π²Π½ΡƒΡ‚Ρ€ΠΈ. ΠŸΡ€ΠΈΠ²ΡΠ·ΠΊΠ° ΠΏΠΎ Π·Π½Π°Ρ‡Π΅Π½ΠΈΡŽ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ Π²Π½ΡƒΡ‚Ρ€ΠΈ стрСлочной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ значСния ΠΈΠ· внСшнСй области видимости. ВмСсто этого для привязок ΠΏΠΎ ссылкам ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ Π°Π½ΠΎΠ½ΠΈΠΌΠ½Ρ‹ΠΌΠΈ функциями.

ΠŸΡ€ΠΈΠΌΠ΅Ρ€ #4 Π‘Ρ‚Ρ€Π΅Π»ΠΎΡ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π½Π΅ ΡƒΠΌΠ΅ΡŽΡ‚ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒ значСния ΠΈΠ· внСшнСй области видимости

<?php

$x
= 1;
$fn = fn() => $x++; // Ѐункция Π½ΠΈΡ‡Π΅Π³ΠΎ Π½Π΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚
$fn();
var_export($x); // Ѐункция Π²Ρ‹Π²Π΅Π΄Π΅Ρ‚ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ 1

Бписок измСнСний

ВСрсия ОписаниС
7.4.0 Появились стрСлочныС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ

Π—Π°ΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: Из стрСлочной Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ΡΡ Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ func_num_args(), func_get_arg() ΠΈ func_get_args().

οΌ‹Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΡ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅ΠΉ 5 notes

up
50
InvisibleSmiley ΒΆ
5 years ago
Unlike anonymous functions, arrow functions cannot have a void return type declaration.

May seem obvious, but if you thought you could make use of the benefits of arrow functions (using variables from the parent scope) to simplify a function or method call, keep in mind that this is only possible if you do NOT tell PHP that the arrow function does indeed return void.
up
44
Koushil Mankali ΒΆ
5 years ago
In example 4  (Values from the outer scope cannot be modified by arrow functions)

<?php

$x = 1;
$fn = fn() => $x++; // Has no effect
$fn();
var_export($x);  // Outputs 1

?>

Here we can use reference variable in fn(&$x) and pass the value from function call $fn($x) so that we will get the output as expected with out using Anonymous functions.

Example:

<?php

$x = 1;
$fn = fn(&$x) => $x++; 
$fn($x);
var_export($x); 

?>

Output : 2 (as expected)

But here it will not take values from parent scope automatically but we have to pass them explicitly.
up
13
aaronw at catalyst dot net dot nz ΒΆ
1 year ago
If you're a JavaScript developer, here are the similarities and differences to JS arrow functions:

Same:
-  Makes an anonymous function
-  Binds the value of "$this" to its value in the parent scope.
    - (along with all other variables of the parent scope. See note below)

Different:
- You must write "fn()" instead of just "()"
- The function body is limited to just ONE expression
    - So no multi-line function bodies with "{" and "}"

Same and Different at the same time:
- Binds ALL the variables of the parent scope
    - In JavaScript all functions are closures, binding to the variables in their parent scope (except for "this").
    - But in PHP, normal anonymous functions (defined with "function() {}") do NOT get access to the parent scope, unless they explicitly declare a closure with keyword "use"
    - PHP arrow functions, on the other hand, automatically bind to ALL variables in the parent scope. So, this makes them behave the same as JS functions, but be aware that in PHP this is special behavior unique to arrow functions.
up
24
itsunclexo at gmail dot com ΒΆ
5 years ago
As you already know, variable bindings occur in arrow functions by "by-value".  That means, an arrow function returns a copy of the value of the variable used in it from the outer scope.

Now let us see an example of how a arrow function returns a reference instead of a copy of a value.

<?php

$x = 0;

$fn = fn &(&$x) => $x;  // Returns a reference

$y = &$fn($x);  // Now $y represents the reference

var_dump($y);  // Outputs: 0

$y = 3;  // Changing value of $y affects $x

var_dump($x);  // Ouputs: 3

?>
up
15
dexen dot devries at gmail dot com ΒΆ
5 years ago
Beware compact() not being able to access (import) variables from external scope (known in versions: 7.4.0, 7.4.8) (bug: https://bugs.php.net/bug.php?id=78970).

A workaround is available - use the variable directly; this will cause it to be imported into the arrow function's namespace and make it available to the compact() too.

<?php
$aa = 111;
$accessing_variable_works = fn($bb) => [ $aa, $bb ];
$compact_is_broken = fn($bb) => compact('aa', 'bb');
$compact_can_work_with_workaround = fn($bb) => compact('aa', 'bb') + ['workaround' => $aa];
var_dump($accessing_variable_works(333));
var_dump($compact_is_broken(555));
var_dump($compact_can_work_with_workaround(777));
?>

result:
array(2) {
  [0]=>
  int(111)
  [1]=>
  int(333)
}
PHP Notice:  compact(): Undefined variable: aa in /home/m/vlt/guitar/tlb/s/public_html/index.php on line 9
array(1) {
  ["bb"]=>
  int(555)
}
array(3) {
  ["aa"]=>
  int(111)
  ["bb"]=>
  int(777)
  ["workaround"]=>
  int(111)
}