Meydan okuma - Reflection uygulaması
Reflection ve özniteliklerle çalışan bir otomatik serileştirme (serializer) yazarsın.
Reflection ve özniteliklerle serileştirme
Bu derste ReflectionSerializer sınıfını yazarsın. ReflectionClass bir sınıfın yapısını okur; getProperties() özellikleri listeler. Her özelliğin getAttributes() çağrısı, o özelliğe iliştirilen öznitelikleri ReflectionAttribute dizisi olarak verir.
Öznitelikler #[Attribute] ile işaretlenmiş sınıflardır. #[Field("id")] gibi bir öznitelik, serileştirme sırasında hangi anahtarın kullanılacağını söyler. newInstance() ile öznitelik örneği üretilip değeri okunur. Böylece hangi özelliğin serileştirileceğini koddan değil, bildirimsel olarak belirlersin.
Öznitelikleri okumak
Öznitelik okumanın tipik akışı şudur: önce $prop->getAttributes(Field::class) ile belirli bir öznitelik sınıfını filtrele, ardından $attrs[0]->newInstance() ile öznitelik örneğini oluştur. Örnek üzerinde name gibi alanları okursun.
Bu desen bildirimseldir: serileştirme davranışını sınıf tanımından ayrı tutmazsın; doğrudan özelliğin üstüne yazarısın. Yeni bir alan eklediğinde tek yapman gereken #[Field("yeni")] yazmak. Serializer'ı değiştirmezsin. Bu, açık-kapalı ilkesinin tipik bir uygulamasıdır.
Uygulama ReflectionSerializer sınıfını yaz
Başlangıç kodunda ETL hattı hazır. Şimdi #[Attribute] ile işaretli Field öznitelik sınıfını tanımla: public string $name = "" yapılandırma özelliği olsun. Ardından Product sınıfını yaz: id ve name özellikleri #[Field("id")] ve #[Field("name")] ile işaretli olsun.
Son olarak ReflectionSerializer::serialize(object $obj): array yöntemini yaz. new ReflectionClass($obj) ile sınıfı oku, getProperties() ile özellikleri gez, her birinin getAttributes(Field::class) çağrısını yap; boşsa atla. newInstance() ile Field örneği üret, name boşsa özellik adını kullan, değilse name değerini. Demo Product(7, "kale") nesnesini json_encode ile yazdırsın.
Örnek çözümü göster
:serialize içinde new ReflectionClass($obj), getProperties() ile özellikleri gez, her birinin getAttributes(Field::class) çağrısıyla özniteliği al, newInstance() ile Field örneği üret, name değerini anahtar yap. Demo Product sınıfını da yaz, sonucu json_encode ile yazdır.
Örnek çözüm:
<?php
// ETL hattı + Reflection: ReflectionSerializer yaz
function readRows(array $rows): Generator {
foreach ($rows as $row) {
yield $row;
}
}
function transform(iterable $rows, callable $fn): Generator {
foreach ($rows as $row) {
yield $fn($row);
}
}
function pipeline(array $rows, callable $fn): Generator {
yield from transform(readRows($rows), $fn);
}
function loadAll(iterable $rows): array {
$out = [];
foreach ($rows as $row) {
$out[] = $row;
}
return $out;
}
#[Attribute]
class Field {
public function __construct(public string $name = "") {}
}
class Product {
public function __construct(
#[Field("id")] public int $id,
#[Field("name")] public string $name,
) {}
}
class ReflectionSerializer {
public function serialize(object $obj): array {
$rc = new ReflectionClass($obj);
$out = [];
foreach ($rc->getProperties() as $prop) {
$attrs = $prop->getAttributes(Field::class);
if (empty($attrs)) continue;
$field = $attrs[0]->newInstance();
$key = $field->name !== "" ? $field->name : $prop->getName();
$out[$key] = $prop->getValue($obj);
}
return $out;
}
}
// Demo:
$p = new Product(7, "kale");
$s = new ReflectionSerializer();
echo json_encode($s->serialize($p), JSON_UNESCAPED_UNICODE) . "\n";
Kendini test et
-
Reflection kavramlarını eşleştir
- ReflectionClass
- Sınıfın yapısını okur
- getAttributes
- Öznitelik listesini verir
- newInstance
- Öznitelik örneği üretir
- getValue
- Özellik değerini döndürür
-
ReflectionProperty::getAttributes ne döndürür?
- Yalnızca özellik adını bir dize olarak
- Özelliğin değerini doğrudan döndürür
- ReflectionAttribute dizisi (boş olabilir)
- Yeni bir ReflectionClass örneği
Cevabı göster
ReflectionAttribute dizisi (boş olabilir) — Doğru. getAttributes bir ReflectionAttribute dizisi döndürür; öznitelik yoksa dizi boş olur.
-
ReflectionClass çağrısını tamamla
$rc = ____($obj);Cevabı göster
$rc = new ReflectionClass($obj);