VictoryasHD 1
VictoryasHD
Cancan.1234 1
Cancan.1234
Best Studio 1
Best Studio
mavzermete 1
mavzermete
Reklam vermek için turkmmo@gmail.com

Altın Konu PHP'de Arayüzler (Interface): Kullanımı, Sabitler ve Örnekler

  • Konuyu başlatan Konuyu başlatan Agora Metin2
  • Başlangıç tarihi Başlangıç tarihi
  • Cevaplar Cevaplar 2
  • Görüntüleme Görüntüleme 18

Türkiye'nin ilk Cross-Platform OldSchool MOBİL & PC 1-99 Sunucusu Lamira2 6 Kasım'da Açılıyor! Büyük Açılışı Kaçırma HEMEN TIKLA!

image.jpeg


PHP'de arayüzler, bir sınıfın hangi metotları sunması gerektiğini belirleyen ancak bu metotların gövdesini içermeyen yapılardır: interface Shape { public function area(): float; }. Bir sınıf implements Shape ifadesini kullandığında, area() metodunu tanımlamakla yükümlü olur. Böylece, Shape tür ipucunu kullanan tüm fonksiyonlar, bu arayüzü uygulayan herhangi bir sınıfı kabul edebilir.

PHP:
<?php
interface Shape
{
    public function area(): float;
}

class Square implements Shape
{
    public function __construct(private float $side) {}

    public function area(): float
    {
        return $this->side ** 2;
    }
}

class Circle implements Shape
{
    public function __construct(private float $r) {}

    public function area(): float
    {
        return round(M_PI * $this->r ** 2, 2);
    }
}

function describe(Shape $s): string
{
    return get_class($s) . ' with area ' . $s->area();
}

echo describe(new Square(3)), "\n";
echo describe(new Circle(2)), "\n";
var_dump(new Circle(1) instanceof Shape);

describe() fonksiyonu, parametre olarak gelen nesnenin hangi sınıfa ait olduğunu bilmez ve buna ihtiyaç duymaz. Sadece arayüzün sağladığı sözleşmeye güvenir; bu sayede Triangle implements Shape şeklinde yeni bir sınıf eklediğinizde, mevcut kodda hiçbir değişiklik yapmadan bu yeni sınıfla çalışabilir.

Arayüz Odaklı Programlama

Arayüz kullanmanın temel nedeni, kodun belirli bir sınıfa bağımlı olması yerine, sahip olduğu yeteneklere odaklanmasını sağlamaktır. Örneğin, bir sipariş servisinin herhangi bir Notifier nesnesiyle çalışması sağlanabilir. Böylece aynı kod yapısı, canlı sistemde e-posta gönderirken test ortamında mesajları bir listede toplayabilir:

PHP:
<?php
interface Notifier
{
    public function send(string $to, string $message): bool;
}

class EmailNotifier implements Notifier
{
    public function send(string $to, string $message): bool
    {
        echo "Email to $to: $message\n";
        return true;
    }
}

class FakeNotifier implements Notifier
{
    public array $sent = [];

    public function send(string $to, string $message): bool
    {
        $this->sent[] = [$to, $message];
        return true;
    }
}

class OrderService
{
    public function __construct(private Notifier $notifier) {}

    public function place(string $customer, int $orderId): void
    {
        $this->notifier->send($customer, "Order #$orderId confirmed");
    }
}

(new OrderService(new EmailNotifier()))->place('ada@example.com', 1001);

$fake = new FakeNotifier();
(new OrderService($fake))->place('linus@example.com', 1002);
print_r($fake->sent);

Birden Fazla Arayüz Uygulama

Bir sınıf sadece tek bir üst sınıfı genişletebilirken, ihtiyaç duyduğu kadar farklı arayüzü uygulayabilir. Uygulanacak arayüzler implements anahtar kelimesinden sonra virgülle ayrılarak listelenir ve tüm bu arayüzlerdeki metotların tanımlanması gerekir:

PHP:
<?php
interface HasName
{
    public function name(): string;
}

interface Exportable
{
    public function toArray(): array;
}

class Product implements HasName, Exportable, JsonSerializable
{
    public function __construct(private string $title, private int $priceCents) {}

    public function name(): string
    {
        return $this->title;
    }

    public function toArray(): array
    {
        return ['title' => $this->title, 'price' => $this->priceCents / 100];
    }

    public function jsonSerialize(): array
    {
        return $this->toArray();
    }
}

$p = new Product('Desk lamp', 3490);
echo $p->name(), "\n";
print_r($p->toArray());
echo json_encode($p), "\n";
print_r(class_implements($p));

PHP'nin sunduğu yerleşik arayüzlerden biri olan JsonSerializable uygulandığında, json_encode() fonksiyonunun söz konusu nesne için nasıl bir çıktı üreteceği belirlenmiş olur.

Arayüz Sabitleri

Arayüzler içerisinde sabitler tanımlanabilir. Bu arayüzü uygulayan her sınıf, tanımlanan sabitleri devralır. Bu değerlere hem arayüz ismiyle hem de sınıf ismiyle erişmek mümkündür:

PHP:
<?php
interface HttpStatus
{
    const OK = 200;
    const NOT_FOUND = 404;
}

class Response implements HttpStatus
{
    public function __construct(public int $status = self::OK) {}

    public function isError(): bool
    {
        return $this->status >= 400;
    }
}

echo HttpStatus::NOT_FOUND, "\n";
echo Response::OK, "\n";

$r = new Response(Response::NOT_FOUND);
var_dump($r->isError());

PHP 8.3 sürümünde arayüzlerin özellikleri (property) olamaz; yalnızca metotlar ve sabitler tanımlanabilir. Metotlar statik olarak belirlenebilir: Örneğin arayüzdeki public static function fromArray(array $data): static; tanımı, bu arayüzü kullanan her sınıfın ilgili statik metodu oluşturmasını zorunlu kılar. Sabit bir değerler kümesi oluşturmak için genellikle enum yapıları, arayüz sabitlerine göre daha uygun bir tercihtir.

Arayüzlerin Birbirini Genişletmesi

Arayüzler de extends anahtar kelimesini kullanır ve sınıflardan farklı olarak aynı anda birden fazla arayüzü genişletebilirler. Alt arayüzü uygulayan bir sınıf, zincirleme olarak gelen tüm metotları tanımlamak zorundadır:

PHP:
<?php
interface Readable
{
    public function read(): string;
}

interface Writable
{
    public function write(string $data): void;
}

interface Stream extends Readable, Writable
{
    public function close(): void;
}

class MemoryStream implements Stream
{
    private string $buffer = '';

    public function read(): string { return $this->buffer; }
    public function write(string $data): void { $this->buffer .= $data; }
    public function close(): void { $this->buffer = ''; }
}

$s = new MemoryStream();
$s->write('Hello, ');
$s->write('stream');
echo $s->read(), "\n";
var_dump($s instanceof Readable, $s instanceof Writable);

Yerleşik Arayüzler: Countable, IteratorAggregate, Stringable

PHP, nesnelerin dilin temel özellikleriyle entegre çalışmasını sağlayan bazı hazır arayüzler sunar:
• Countable arayüzü, nesnenin count($obj) şeklinde sayılabilmesini sağlar.
• IteratorAggregate arayüzü, nesnenin foreach döngüsüyle kullanılabilmesine olanak tanır.
• Stringable arayüzü ise __toString() metoduna sahip olan her sınıf tarafından otomatik olarak uygulanmış sayılır.

PHP:
<?php
class Playlist implements Countable, IteratorAggregate
{
    private array $songs = [];

    public function add(string $song): static
    {
        $this->songs[] = $song;
        return $this;
    }

    public function count(): int
    {
        return count($this->songs);
    }

    public function getIterator(): Iterator
    {
        return new ArrayIterator($this->songs);
    }

    public function __toString(): string
    {
        return implode(' / ', $this->songs);
    }
}

$list = (new Playlist())->add('Intro')->add('Blue')->add('Outro');

echo count($list), " songs\n";
foreach ($list as $i => $song) {
    echo "$i: $song\n";
}
var_dump($list instanceof Stringable);
echo "$list\n";

Metot Tanımlamayı Unutmak

Bir sınıf bir arayüzü uygulayacağını beyan edip gerekli metotlardan birini tanımlamazsa, kodu çalıştırdığınızda PHP hangi metodun eksik olduğunu belirten kritik bir hata verir:

PHP:
<?php
// This fails on purpose: Invoice does not define total()
interface Billable
{
    public function total(): float;
    public function currency(): string;
}

class Invoice implements Billable
{
    public function currency(): string
    {
        return 'EUR';
    }
}

echo (new Invoice())->currency();

Eksik olan total() metodunu eklediğinizde kod sorunsuz çalışacaktır. Eğer metotların tanımlanmasını istemiyorsanız, soyut sınıflar kullanarak bu metotları tanımsız bırakabilirsiniz; hata mesajı da genellikle bu yöntemi önermektedir.

Arayüz ve Soyut Sınıf Karşılaştırması

Hem arayüzler hem de soyut sınıflar, bir sınıfın sahip olması gereken metotları belirler ve tür ipucu olarak kullanılabilirler. Ancak aralarındaki temel fark, içerik kapasiteleri ve bir sınıfın bunları kaç adet kullanabildiği üzerinedir:

ArayüzSoyut sınıf
Metot gövdeleriyok (yalnızca imzalar)soyut ve tamamlanmış metotlar
Özelliklerhayırevet
Yapıcıtanımlayabilir, nadiren işe yararevet, kodla
Metotların görünürlüğüyalnızca publicpublic, protected, private
Sabitlerevetevet
Sınıf başına kaç taneistenen sayıda (implements A, B, C)bir (extends Base)
Tipik kullanımbir yetenek: Exportable, Countablebir aile için paylaşılan kod: Model, Controller

Bu iki yapı birlikte verimli bir şekilde kullanılabilir: Tür belirleme işlemleri için arayüzü tanımlayabilir, ortak kodları paylaşmak için ise bu arayüzü uygulayan soyut bir temel sınıf oluşturabilirsiniz. Farklı bir temel yapıya ihtiyaç duyan sınıflar, yine de arayüzü doğrudan uygulayarak sistemle uyumlu hale gelebilir.
 

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)

Geri
Üst