phpday 2025 - Call For Papers

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 1 note

up
15
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.
To Top