Birinci sınıf çağrılabilir sözdizimi

PHP 8.1.0 itibariyle kullanılabilen birinci sınıf çağrılabilir sözdizimi çağrılabilir anonim işlevler oluşturmanın bir yoludur. Dizgeleri ve dizileri kullanan mevcut çağrılabilir sözdiziminin yerini alır. Bu sözdiziminin getirisi statik analiz için erişilebilir olması ve çağrılabilirin elde edildiği etki alanın kullanılabilmesidir.

Çağrılabilirden Closure nesne oluşturmakta CallableExpr(...) sözdizimi kullanılır. CallableExpr PHP dil yapısı içinde doğrudan çözümlenebilen her ifadeyi kabul eder:

Örnek 1 - Basit birinci sınıf çağrılabilir sözdizimi

<?php

class Foo {
public function
yöntem() {}
public static function
statikyöntem() {}
public function
__invoke() {}
}

$obj = new Foo();
$sınıfDizgesi = 'Foo';
$yöntemDizgesi = 'method';
$statikYöntemDizgesi = 'staticmethod';


$f1 = strlen(...);
$f2 = $obj(...); // çağrılabilir nesne
$f3 = $obj->yöntem(...);
$f4 = $obj->$yöntemDizgesi(...);
$f5 = Foo::statikyöntem(...);
$f6 = $sınıfDizgesi::$statikYöntemDizgesi(...);

// dizi, dizge kullanan geleneksel çağrılabilir
$f7 = 'strlen'(...);
$f8 = [$obj, 'method'](...);
$f9 = [Foo::class, 'staticmethod'](...);
?>

Bilginize:

... sözdiziminin bir parçası olup ihmal edilmemelidir.

CallableExpr(...) sözdizimi Closure::fromCallable() ile aynı yapıdadır. Yani, dizi ve dizge kullanan çağrılabilirlerin tersine CallableExpr(...) oluşturulduğu etki alanına bağlıdır:

Örnek 2 - Geleneksel çağrılabilir ile CallableExpr(...) karşılaştırması

<?php

class Foo {
public function
getPrivateMethod() {
return [
$this, 'privateMethod'];
}

private function
privateMethod() {
echo
__METHOD__, "\n";
}
}

$foo = new Foo;
$privateMethod = $foo->getPrivateMethod();
$privateMethod();
// Ölümcül hata: private yöntem Foo::privateMethod() küresel etki alanında çağrılıyor.
// Bunun nedeni, çağrının Foo dışında yapılması ve
// görünürlüğün bu noktadan denetlenmesidir.

class Foo1 {
public function
getPrivateMethod() {
// Çağrılabilirin oluşturulduğu etki alanı kullanılıyor.
return $this->privateMethod(...); // Closure::fromCallable([$this, 'privateMethod']); ile eşdeğer
}

private function
privateMethod() {
echo
__METHOD__, "\n";
}
}

$foo1 = new Foo1;
$privateMethod = $foo1->getPrivateMethod();
$privateMethod(); // Foo1::privateMethod
?>

Bilginize:

Bu sözdizimini kullanarak nesne oluşturmak (new Foo(...) gibi) desteklenmemektedir. Bunun sebebi new Foo() sözdiziminin bir işlev/yöntem çağrısı olarak ele alınmamasıdır.

Bilginize:

Basit birinci sınıf çağrılabilir sözdizimi ile güvenli null işleci ?-> birlikte kullanılmamalıdır. Aşağıdakilerin her biri bir derleme hatasıyla sonuçlanır:

<?php
$obj
?->method(...);
$obj?->prop->method(...);
?>

add a note

User Contributed Notes 2 notes

up
14
bienvenunet at yahoo dot com
1 year ago
There's a major gotcha with this syntax that may not be apparent until you use this syntax and find you're getting "Cannot rebind scope of closure created from method" exceptions in some random library code.

As the documentation indicates, the first-class callable uses the scope at the point where the callable is acquired. This is fine as long as nothing in your code will attempt to bind the callable with the \Closure::bindTo method.

I found this the hard way by changing callables going to Laravel's Macroable functionality from the array style to the first-class callable style. The Macroable functionality \Closure::bindTo calls on the callable.

AFAIK, the only workaround is to use the uglier array syntax.
up
0
koalay at gmail dot com
12 days ago
As of PHP 8.2, the first class callable syntax of a class method cannot be serialized like the old array callables.

For example,

<?php

class Bird {
public function
fly() {
}
}

$bird = new Bird();
$callable1 = [$bird, 'fly'];
$callable2 = $bird->fly(...);

// This is fine
serialize($callable1);

// This will cause a fatal error
// "PHP Fatal error: Uncaught Exception: Serialization of 'Closure' is not allowed"
serialize($callable2);

?>

So if your callable is used across session and need to be serialized, you should not use the first class callable syntax (until this is somehow fixed in the future).
To Top