---
title: Arayüzler
source: 'https://academia.sh/tr/kurslar/php-nesne-modeli/arayuzler'
course: 'Nesneye Dayalı PHP ve Standartlar'
language: tr
updated: '2026-10-21T05:03:34+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir arayüz tanımlar, birden çok arayüzü bir sınıfta gerçekleştirir ve arayüzü parametre tipi olarak kullanır'
    - 'instanceof ile bir nesnenin hangi arayüzü gerçekleştirdiğini sorgular'
    - 'Arayüze yöntem eklenmesinin gerçekleştiren sınıfı durdurduğunu çıkış koduyla ölçer'
    - 'Aynı ekleme gövdeli bir soyut sınıfta yapılınca değişikliğin yerinde kaldığını ve bunun bedelini gösterir'
---

# Arayüzler

Bir arayüze yöntem eklendiğinde onu gerçekleştiren sınıfın bildirilememesi, tip olarak arayüz ve instanceof, ve aynı eklemenin gövdeli bir soyut sınıfta yerinde kalması.

Kalıtım dersinde soyut sınıfa yeni bir `abstract` yöntem eklemek alt sınıfı durdurmuştu ve bunun nedeni sözleşmenin gövdesiz olmasıydı. Arayüz bu sözleşmenin yalın hâlidir: yalnız imza taşır, hiçbir gövde taşımaz. Soru, bir sözleşmeye yöntem eklenince onu gerçekleştiren sınıfların ne yaşadığıdır.

## Arayüz ve Gerçekleştirim

Arayüz (interface), bir sınıfın hangi yöntemleri sunması gerektiğini bildirir ve hiçbirini yazmaz. Arayüzü uygulayan sınıf `implements` ile bildirimde bulunur ve bütün yöntemleri yazmak zorundadır; buna gerçekleştirim (implementation) denir. Bir sınıf birden çok arayüzü gerçekleştirebilir, virgülle ayrılmış olarak.

```php
<?php
// Odenebilir.php — yalniz bir imza tasiyan arayuz
interface Odenebilir
{
    public function tutar(): int;
}
```

```php
<?php
// Yazdirilabilir.php — ikinci bir arayuz
interface Yazdirilabilir
{
    public function metin(): string;
}
```

```php
<?php
// Fatura.php — iki arayuzu birden gerceklestiren sinif
class Fatura implements Odenebilir, Yazdirilabilir
{
    public function tutar(): int { return 120; }
    public function metin(): string { return 'fatura'; }
}
```

```php
<?php
// Maas.php — yalniz Odenebilir'i gerceklestiren sinif
class Maas implements Odenebilir
{
    public function tutar(): int { return 300; }
}
```

Arayüz bir tip olarak da kullanılır. Aşağıdaki fonksiyon `Odenebilir` bekler ve bu arayüzü gerçekleştiren herhangi bir sınıfın nesnesini kabul eder. `instanceof` işleci bir nesnenin verilen arayüzü gerçekleştirip gerçekleştirmediğini sorar.

```php
<?php
// arayuz_kullan.php — arayuz parametre tipi olarak ve instanceof ile
require 'Odenebilir.php';
require 'Yazdirilabilir.php';
require 'Fatura.php';
require 'Maas.php';

function toplamTutar(Odenebilir ...$kalemler): int
{
    $toplam = 0;
    foreach ($kalemler as $kalem) {
        $toplam += $kalem->tutar();
    }
    return $toplam;
}

echo toplamTutar(new Fatura(), new Maas()), "\n";
var_dump(new Fatura() instanceof Yazdirilabilir);
var_dump(new Maas() instanceof Yazdirilabilir);
```

```
420
bool(true)
bool(false)
```

**NM10.** `toplamTutar()` iki ayrı sınıfın nesnesini aldı, çünkü ikisi de `Odenebilir`'i gerçekleştiriyordu: `120 + 300`. `Fatura` iki arayüze, `Maas` yalnız birine uyuyor; `instanceof` bu farkı `true` ve `false` ile söyledi. Arayüz imzayı denetler, anlamı denetlemez: `tutar()` negatif bir sayı da döndürebilirdi ve dil sesini çıkarmazdı. M08/K03 bir davranışın garantisini kimin verdiğini sormuştu; burada arayüz bir söz değil, bir sınırdır. İmzanın dışındaki anlamı ölçmek Ortak Arayüz Standartları dersine kalıyor.

## Arayüz Sabiti ve Arayüzün Arayüzü Genişletmesi

Arayüz yalnız imza taşımaz, sabit de taşıyabilir. Arayüz sabiti (interface constant) gerçekleştiren her sınıfta aynı adla okunur. Bir arayüz başka bir arayüzü `extends` ile genişletebilir; bu durumda genişleten arayüzü gerçekleştiren sınıf iki arayüzün bütün imzalarını yazmak zorundadır. Sınıflarda tek kalıtım kuralı arayüzler için geçerli değildir: bir arayüz birden çok arayüzü genişletebilir.

```php
<?php
// Vergili.php — Odenebilir'i genisleten ve bir sabit tasiyan arayuz
require_once 'Odenebilir.php';

interface Vergili extends Odenebilir
{
    public const ORAN = 20;

    public function vergi(): int;
}
```

```php
<?php
// Satis.php — Vergili'yi gerceklestiren sinif, iki arayuzun imzalarini da yazar
require_once 'Vergili.php';

class Satis implements Vergili
{
    public function tutar(): int { return 200; }
    public function vergi(): int { return intdiv($this->tutar() * self::ORAN, 100); }
}
```

```php
<?php
// satis_kullan.php — genisleten arayuz, sabit ve ust arayuz tipi
require 'Satis.php';

$satis = new Satis();
echo $satis->tutar(), ' ', $satis->vergi(), ' ', Vergili::ORAN, "\n";
var_dump($satis instanceof Odenebilir);
```

```
200 40 20
bool(true)
```

`Satis` yalnız `Vergili`'yi gerçekleştirdiğini söylüyor, ama `instanceof Odenebilir` de `true` verdi: genişleten arayüz, üst arayüzün tipi sayılır. Sabit `Vergili::ORAN` ile arayüzün adı üzerinden de, `self::ORAN` ile gerçekleştiren sınıfın içinden de okunur.

## Tip Olarak Arayüz ve Örneklenememe

Arayüz bir sınıf gibi örneklenemez, çünkü gövdesi yoktur. Aynı sözleşmeyi taşımayan bir nesne de arayüz tipli bir parametreye giremez. İkisi de çalışma anında bir hata olarak görünür; ilki `Error`, ikincisi `TypeError` verir.

```php
<?php
// tip_hatasi.php — arayuz ornek olamaz, sozlesmesiz nesne parametreye giremez
require 'Satis.php';

function ode(Odenebilir $kalem): int
{
    return $kalem->tutar();
}

echo ode(new Satis()), "\n";

try {
    ode(new stdClass());
} catch (TypeError $e) {
    echo get_class($e), "\n";
}

try {
    $kalem = new Odenebilir();
} catch (Error $e) {
    echo get_class($e), "\n";
}
```

```
200
TypeError
Error
```

`ode()` bir sınıfa değil bir davranışa bağlıdır: `Satis`, `Fatura` ya da yarın yazılacak başka bir sınıf `Odenebilir`'i gerçekleştirdiği sürece gider. Bu bağımsızlık arayüzün asıl yararıdır, çünkü çağıran kod gerçekleştirimi tanımaz. Öte yandan sözleşmeyi taşımayan `stdClass` tür denetimine takılır ve `TypeError` doğurur.

## Gerçekleştirenin Yükümlülüğü

Arayüzü bildiren sınıf, arayüzün bütün yöntemlerini yazmak ve hepsini `public` yapmak zorundadır. Biri eksikse ya da görünürlüğü daraltılmışsa sınıf bildirilemez. Aşağıdaki betik bu iki durumu ayrı dosyalarda dener.

```bash
# yukumluluk.sh — eksik yontem ve daraltilmis gorunurluk sinifi bildirilemez yapar
cat > Eksik.php <<'PHP'
<?php
interface Odenebilir { public function tutar(): int; }
class Bos implements Odenebilir {}
PHP
cat > Dar.php <<'PHP'
<?php
interface Odenebilir { public function tutar(): int; }
class Gizli implements Odenebilir { private function tutar(): int { return 1; } }
PHP
php -d display_errors=0 Eksik.php; echo "eksik cikis=$?"
php -d display_errors=0 Dar.php; echo "dar cikis=$?"
```

```
eksik cikis=255
dar cikis=255
```

Kısıt sınıfın değil kullananın korunması içindir: arayüz tipli bir parametreye giren nesnenin `tutar()` yöntemi her zaman çağrılabilir olmalıdır. Bu garanti, aşağıdaki gibi bir yer değiştirmeyi güvenli yapar.

```php
<?php
// sahte.php — sozlesmeyi tasiyan sahte bir gerceklestirim, gercek olanin yerine gecer
require 'Odenebilir.php';
require 'Yazdirilabilir.php';
require 'Fatura.php';

class SahteKalem implements Odenebilir
{
    public function tutar(): int { return 1; }
}

$kalemler = [new Fatura(), new SahteKalem()];
echo array_sum(array_map(fn (Odenebilir $kalem): int => $kalem->tutar(), $kalemler)), "\n";
```

```
121
```

`array_map()` içindeki fonksiyon yalnız `Odenebilir` biliyor; gerçek bir `Fatura` ile sınama için yazılmış `SahteKalem` aynı kodun içinden geçti. Arayüzün sınamada sağladığı yarar budur: kodu gerçek ödeme ya da gerçek dosya gibi ağır bir bağımlılığa bağlamadan çalıştırmak mümkün olur. Kurs kapanışında ele alınan, bağımlılığın dışarıdan verilmesi bu yararın üzerine kuruludur ve arayüz olmadan aynı esnekliği vermez.

## Ölçüm Çekirdeği

Bu dersin ölçümü de `yayilim.php` dosyasını kullanır; Sınıflar ve Nesneler dersinde açıklanan çekirdek bu çalışma dizininde yeniden yazılıyor.

```php
<?php
// yayilim.php — bir degisikligin nereye ulastigini olcen yardimcilar

function yaz(string $dizin, array $dosyalar): void
{
    foreach ($dosyalar as $ad => $icerik) {
        if ($icerik === null) {
            continue; // null: dosya silindi
        }
        $yol = "$dizin/$ad";
        if (!is_dir(dirname($yol))) {
            mkdir(dirname($yol), 0777, true);
        }
        file_put_contents($yol, $icerik);
    }
}

function oku(string $dizin): array
{
    $dosyalar = [];
    $gezgin = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($dizin, FilesystemIterator::SKIP_DOTS)
    );
    foreach ($gezgin as $dosya) {
        $ad = substr($dosya->getPathname(), strlen($dizin) + 1);
        $dosyalar[$ad] = file_get_contents($dosya->getPathname());
    }
    return $dosyalar;
}

function kostur(string $dizin): array
{
    $komut = 'cd ' . escapeshellarg($dizin) . ' && php -d display_errors=0 main.php 2>/dev/null';
    exec($komut, $satirlar, $kod);
    return [$kod, implode("\n", $satirlar)];
}

function olc(string $ad, array $taban, array $degisiklik, array $baglanti = []): string
{
    if (array_key_exists('main.php', $degisiklik)) {
        throw new LogicException("$ad: kullanan duzenlenmez");
    }
    yaz("olcum/$ad/once", $taban);
    yaz("olcum/$ad/sonra", array_merge($taban, $degisiklik));
    [$kodOnce, $ciktiOnce] = kostur("olcum/$ad/once");
    [$kodSonra, $ciktiSonra] = kostur("olcum/$ad/sonra");
    if ($kodOnce !== 0) {
        throw new LogicException("$ad: taban calismadi");
    }
    $sinif = match (true) {
        $kodSonra !== 0 => 'kiran',
        $ciktiOnce !== $ciktiSonra => 'ortuk',
        array_intersect(array_keys($degisiklik), $baglanti) !== [] => 'baglantida',
        default => 'yerinde',
    };
    printf(
        "%-18s %d dosya  cikis=%-3d cikti %-6s -> %s\n",
        $ad,
        count($degisiklik),
        $kodSonra,
        $ciktiOnce === $ciktiSonra ? 'ayni' : 'farkli',
        $sinif
    );
    return $sinif;
}
```

## Arayüze Yöntem Eklenir

Ölçülecek değişiklik, yukarıdaki arayüze ikinci bir imza eklemektir: `paraBirimi()`. Gerçekleştiren sınıf `Fatura` yalnız `tutar()` yöntemini taşır. Kullanan `main.php` sınıfı bildirir ve `tutar()` değerini yazdırır; dosya düzenlenmez.

```php
<?php
// arayuz.php — arayuze yeni bir yontem eklenir
require_once 'yayilim.php';

olc('arayuze-yontem', [
    'odenebilir.php' => <<<'PHP'
        <?php
        interface Odenebilir
        {
            public function tutar(): int;
        }
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'odenebilir.php';
        class Fatura implements Odenebilir
        {
            public function tutar(): int { return 120; }
        }
        echo (new Fatura())->tutar(), "\n";
        PHP,
], [
    'odenebilir.php' => <<<'PHP'
        <?php
        interface Odenebilir
        {
            public function tutar(): int;
            public function paraBirimi(): string;
        }
        PHP,
]);

foreach (['once', 'sonra'] as $asama) {
    [$kod, $cikti] = kostur("olcum/arayuze-yontem/$asama");
    echo $asama, ' cikis=', $kod, ' cikti=', $cikti, "\n";
}
```

```
arayuze-yontem     1 dosya  cikis=255 cikti farkli -> kiran
once cikis=0 cikti=120
sonra cikis=255 cikti=
```

**NM11.** Tek dosya düzenlendi ve kullanan durdu: `Fatura` artık `paraBirimi()` yöntemini taşımadığı için bildirilemedi, çıkış 255. Önceki koşum `120` vermişti. Hata, kullanan kodun kendisinde değil gerçekleştiren sınıftadır; arayüzün imzası değişince onu gerçekleştiren her sınıf sözleşmeyi yeniden karşılamak zorunda kalır. Bu dersin ölçü sınıfı kırandır. `olc()` hata iletisini basmaz, yalnız çıkış kodunu görür.

## Soyut Sınıf mı, Arayüz mü

İkisi de gövdesiz imza bildirebilir, ama bir sınıfa farklı şeyler söylerler. Arayüz "bu davranışı sunuyorsun" der ve ilişkisiz sınıflar arasında bir ortak ad kurar; durum ve gövde taşıyamaz; sabit ve PHP 8.4'ten beri özellik sözleşmesi bildirebilir. Soyut sınıf "sen bu ailedensin" der; ortak özellik ve gövdeli yöntem taşıyabilir ama sınıfın tek kalıtım hakkını harcar.

Seçimi üç soru yönlendirir. Gerçekleştirenler birbirine akraba mı, yoksa yalnızca aynı davranışı mı sunuyor? Ortak gövde ya da ortak durum paylaşılacak mı? Sözleşme zamanla büyüyecek mi? Birinci soruya "yalnız aynı davranış", ikinciye "hayır" derseniz arayüz doğrudur. Ortak durum ya da gövde istiyorsanız soyut sınıf gerekir; bir sınıfın hem bir soyut sınıfı genişletmesi hem de birkaç arayüzü gerçekleştirmesi yaygın bir birleşimdir. Üçüncü soruya "evet" derseniz aşağıdaki ölçüm, bu seçimin bedelini gösteriyor: arayüz büyüdükçe gerçekleştirenlerin her biri durur, gövdeli soyut sınıf büyüdükçe durmaz. Bu nedenle sözleşmesi sık değişecek bir davranış için soyut sınıf, uzun süre sabit kalacak bir sınır için arayüz seçmek, yazan tarafın değişikliğin bedelini kimin ödeyeceğine verdiği karardır.

## Sınırlayıcı Ölçüm

Kırılmanın kaynağı arayüz kavramı mı, yoksa eklenen yöntemin gövdesiz olması mı? Aynı yöntemi gövdesiyle bir soyut sınıfa eklemek bunu ayırır. Bu ölçümde sözleşme soyut bir sınıftır, `Fatura` onu genişletir ve eklenen `paraBirimi()` yöntemi bir gövde taşır.

```php
<?php
// govdeli.php — ayni ek yontem, bu kez govdesiyle bir soyut sinifa
require_once 'yayilim.php';

olc('soyut-govde', [
    'odenebilir.php' => <<<'PHP'
        <?php
        abstract class Odenebilir
        {
            abstract public function tutar(): int;
        }
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'odenebilir.php';
        class Fatura extends Odenebilir
        {
            public function tutar(): int { return 120; }
        }
        echo (new Fatura())->tutar(), "\n";
        PHP,
], [
    'odenebilir.php' => <<<'PHP'
        <?php
        abstract class Odenebilir
        {
            abstract public function tutar(): int;
            public function paraBirimi(): string { return 'TL'; }
        }
        PHP,
]);

foreach (['once', 'sonra'] as $asama) {
    [$kod, $cikti] = kostur("olcum/soyut-govde/$asama");
    echo $asama, ' cikis=', $kod, ' cikti=', $cikti, "\n";
}
```

```
soyut-govde        1 dosya  cikis=0   cikti ayni   -> yerinde
once cikis=0 cikti=120
sonra cikis=0 cikti=120
```

**NM12.** Aynı yöntem, aynı ad, aynı kullanan; bu kez sınıf yerinde kaldı: çıkış 0, çıktı `120`. Eklenen yöntemin gövdesi olduğu için `Fatura`'nın bir şey yazması gerekmedi, yöntem devralındı. Demek ki kırılmayı arayüz sözcüğü değil gövdesiz sözleşme doğurdu. Bu çözümün bir bedeli var: bir sınıf yalnız bir sınıfı genişletebilir. Aşağıdaki betik iki üst sınıfı virgülle sayan bir bildirim yazar ve çıkış kodunu basar.

```bash
# tekli.sh — bir sinif iki sinifi genisletemez
cat > Cift.php <<'PHP'
<?php
abstract class Odenebilir {}
abstract class Yazdirilabilir {}
class Fatura extends Odenebilir, Yazdirilabilir {}
PHP
php -d display_errors=0 Cift.php; echo "cikis=$?"
```

```
cikis=255
```

Bir sınıf istediği kadar arayüzü gerçekleştirebilir ama yalnız bir sınıfı genişletebilir. Gövdeli soyut sınıf değişikliği yerinde tutar, ama sınıfın tek kalıtım hakkını harcar. Arayüz bu hakkı harcamaz, bunun karşılığında eklenen her yöntemi gerçekleştirenlere dayatır.

## Özet

- Arayüz yalnız imza taşır, bir sınıf istediği kadar arayüzü `implements` ile gerçekleştirebilir ve arayüz parametre tipi olarak kullanılır; `instanceof` hangi arayüzün gerçekleştirildiğini söyler.
- Arayüz imzayı denetler, anlamı denetlemez.
- Arayüze `paraBirimi()` imzası eklenince `Fatura` bildirilemedi, `120` yerine çıkış 255; bu dersin ölçü sınıfı kırandır.
- Aynı yöntem gövdesiyle bir soyut sınıfa eklenince sınıf yerinde kaldı, çıktı `120` olarak sürdü.
- Gövdeli soyut sınıfın bedeli tek kalıtımdır: bir sınıf iki sınıfı genişletemez, çıkış 255.

## Sonraki Adım

Soyut sınıf gövde taşıyabiliyordu ama sınıfa yalnız bir kez kalıtım hakkı bırakıyordu. Trait'ler dersi gövdeyi paylaşmanın başka bir yolunu soruyor: iki trait aynı adda bir yöntem getirirse kullanan sınıf ne yaşıyor?
