PHP 8.0: Öznitelikler (3/4)
PHP 8.0 sürümü şu anda yayınlanıyor. Daha önce hiçbir sürümde olmadığı kadar yeni şeylerle dolu. Bunların tanıtımı dört ayrı makaleyi hak ediyordu. Üçüncü bölümde özniteliklere bir göz atacağız.
Nitelikler, sınıflar ve tüm üyelerinin yanı sıra işlevler, kapanışlar ve parametreleri için yapılandırılmış meta veriler yazmak için yepyeni bir yol sağlar. PhpDoc yorumları şimdiye kadar bu amaç için kullanıldı, ancak sözdizimleri her zaman o kadar gevşek ve tutarsızdı ki, bunları makine işlemeye başlamak mümkün değildi. Bu nedenle, sözdizimi belirlenmiş ve yansıma sınıflarında desteklenen niteliklerle değiştiriliyorlar.
Bu nedenle, daha önce phpDoc yorumlarını ayrıştırarak meta verileri
alan kütüphaneler bunları özniteliklerle değiştirebileceklerdir. Bunun bir
örneği, Application ve DI'nin son sürümlerinde @persistent
,
@crossOrigin
ve @inject
ek açıklamaları yerine
Persistent
, CrossOrigin
ve Inject
özniteliklerini kullanabileceğiniz Nette'dir.
Ek açıklamalar kullanarak kodlama:
/**
* @persistent(comp1, comp2)
*/
class SomePresenter
{
/** @persistent */
public $page = 1;
/** @inject */
public Facade $facade;
/**
* @crossOrigin
*/
public function handleSomething()
{
}
}
Aynı şey nitelikler için de geçerlidir:
use Nette\Application\Attributes\CrossOrigin;
use Nette\Application\Attributes\Persistent;
use Nette\DI\Attributes\Inject;
#[Persistent('comp1', 'comp2')]
class SomePresenter
{
#[Persistent]
public int $page = 1;
#[Inject]
public Facade $facade;
#[CrossOrigin]
public function handleSomething()
{
}
}
PHP öznitelik isimlerini, isim alanları ve use
cümleleri
bağlamında sınıflar gibi değerlendirir. Bu nedenle, bunları örneğin
aşağıdaki gibi yazmak bile mümkün olacaktır:
use Nette\Application\Attributes;
class SomePresenter
{
#[Attributes\Persistent]
public int $page = 1;
#[\Nette\DI\Attributes\Inject]
public Facade $facade;
Özniteliği temsil eden sınıf var olabilir ya da olmayabilir. Ancak var olması kesinlikle daha iyidir, çünkü o zaman editör yazım sırasında önerebilir, statik analizci yazım hatalarını tanır, vb.
Sözdizimi
PHP'nin 8. sürümünden önce öznitelikleri yalnızca yorum olarak görmesi akıllıcadır, bu nedenle eski sürümlerde çalışması gereken kodlarda da kullanılabilirler.
Bireysel bir niteliğin sözdizimi, new
operatörünü atlarsak
bir nesne örneği oluşturmaya benzer. Yani, sınıfın adı ve ardından
parantez içinde isteğe bağlı argümanlar:
#[Column('string', 32, true, false)]#
protected $username;
Ve işte PHP 8.0'ın yeni sıcak özelliğinin kullanılabileceği yer – adlandırılmış argümanlar:
#[Column(
type: 'string',
length: 32,
unique: true,
nullable: false,
)]#
protected $username;
Her öğe, tek tek yazılabilen veya virgülle ayrılabilen birden fazla özniteliğe sahip olabilir:
#[Inject]
#[Lazy]
public Foo $foo;
#[Inject, Lazy]
public Bar $bar;
Aşağıdaki özellik her üç özellik için de geçerlidir:
#[Common]
private $a, $b, $c;
Derleme sırasında değerlendirilebilen ve özellikler için varsayılan değerler olarak kullanılan basit ifadeler ve sabitler, özniteliklerde bağımsız değişken olarak kullanılabilir:
#[
ScalarExpression(1 + 1),
ClassNameAndConstants(PDO::class, PHP_VERSION_ID),
BitShift(4 >> 1, 4 << 1),
BitLogic(1 | 2, JSON_HEX_TAG | JSON_HEX_APOS),
]
Ne yazık ki, bir argümanın değeri başka bir öznitelik olamaz, yani öznitelikler iç içe geçemez. Örneğin, Doctrine'de kullanılan aşağıdaki ek açıklamanın özniteliklere dönüştürülmesi için doğrudan bir yol yoktur:
/**
* @Table(name="products",uniqueConstraints={@UniqueConstraint(columns={"name", "email"})})
*/
Ayrıca, örneğin Nette Tester tarafından kullanılan phpDoc dosyası, yani bir dosyanın başında bulunan bir yorum için eşdeğer bir öznitelik yoktur.
Öznitelik yansıması
Tek tek öğelerin hangi niteliklere sahip olduğu yansıma kullanılarak
belirlenebilir. Reflection sınıfları, ReflectionAttribute
nesnelerinden oluşan bir dizi döndüren yeni bir getAttributes()
yöntemine sahiptir.
use MyAttributes\Example;
#[Example('Hello', 123)]
class Foo
{}
$reflection = new ReflectionClass(Foo::class);
foreach ($reflection->getAttributes() as $attribute) {
$attribute->getName(); // full attribute name, e.g. MyAttributes\Example
$attribute->getArguments(); // ['Hello', 123]
$attribute->newInstance(); // returns an instance: new MyAttributes\Example('Hello', 123)
}
Döndürülen öznitelikler bir parametre ile filtrelenebilir, örneğin
$reflection->getAttributes(Example::class)
yalnızca
Example
özniteliklerini döndürür.
Öznitelik sınıfları
Öznitelik sınıfı MyAttributes\Example
mevcut olmayabilir.
Yalnızca bir yöntem çağrısı newInstance()
onu örneklediği
için varlığını gerektirir. Öyleyse yazalım. Tamamen sıradan bir sınıf
olacak, sadece Attribute
özniteliğini sağlamamız gerekiyor
(yani küresel sistem ad alanından):
namespace MyAttributes;
use Attribute;
#[Attribute]
class Example
{
public function __construct(string $message, int $number)
{
...
}
}
Hangi dil öğeleri için özniteliğin kullanımına izin verileceği kısıtlanabilir. Örneğin, sadece sınıflar ve özellikler için:
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_PROPERTY)]
class Example
{
...
}
TARGET_CLASS
, TARGET_FUNCTION
,
TARGET_METHOD
, TARGET_PROPERTY
,
TARGET_CLASS_CONSTANT
, TARGET_PARAMETER
ve varsayılan
TARGET_ALL
bayrakları mevcuttur.
Ancak dikkat edin, doğru veya yanlış kullanımın doğrulanması
şaşırtıcı bir şekilde yalnızca newInstance()
yöntemi
çağrıldığında gerçekleşir. Derleyicinin kendisi bu kontrolü yapmaz.
Niteliklerle gelecek
Nitelikler ve yeni türler
sayesinde, PHP dokümantasyon yorumları tarihlerinde ilk kez gerçekten sadece
belgesel yorumlar haline gelecektir. PhpStorm, örneğin
@deprecated
ek açıklamasının yerini alabilecek özel
nitelikler ile zaten geliyor. Ve bu niteliğin bir gün PHP'de varsayılan
olarak yer alacağı varsayılabilir. Benzer şekilde, @throws
vb.
gibi diğer ek açıklamalar da değiştirilecektir.
Nette ilk sürümünden bu yana kalıcı parametreleri ve bileşenleri belirtmek için ek açıklamaları kullanıyor olsa da, bunlar yerel bir dil yapısı olmadıkları için daha yaygın olarak kullanılmadılar, bu nedenle editörler bunları önermedi ve hata yapmak kolaydı. Bu durum editör eklentileri tarafından halihazırda ele alınıyor olsa da, öznitelikler tarafından getirilen gerçekten yerel yol tamamen yeni olasılıkların önünü açmaktadır.
Bu arada, öznitelikler Nette Kodlama Standardında bir istisna
kazanmıştır, bu da sınıf adının özelliğe ek olarak (örn.
Product
, InvalidValue
), bir genellik de içermesini
gerektirir (örn. ProductPresenter
,
InvalidValueException
). Aksi takdirde, kod içinde
kullanıldığında, sınıfın tam olarak neyi temsil ettiği açık
olmayacaktır. Nitelikler için bu arzu edilmez, bu nedenle sınıf
InjectAttribute
yerine Inject
olarak
adlandırılır.
Son bölümde, PHP'de hangi yeni işlevlerin ve sınıfların ortaya çıktığına bakacağız ve Tam Zamanında Derleyici'yi tanıtacağız.
Yorum göndermek için lütfen giriş yapın