---
title: 'Ortak Arayüz Standartları'
source: 'https://academia.sh/tr/kurslar/php-nesne-modeli/ortak-arayuz-standartlari'
course: 'Nesneye Dayalı PHP ve Standartlar'
language: tr
updated: '2026-10-21T05:03:35+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Ortak bir arayüze bağlı kullananın gerçekleştirim değişince düzenlenmediğini ölçer'
    - 'Değişikliğin kurulum dosyasındaki bağlantı noktasında karşılandığını gösterir'
    - 'Arayüzün imzayı denetleyip anlamı denetlemediğini bir örtük ölçümle gösterir'
---

# Ortak Arayüz Standartları

PSR-3 gibi ortak arayüzler; kullananın arayüze bağlı olduğu ve gerçekleştirimin kurulum dosyasında değiştiği durum; arayüzün imzayı denetleyip anlamı denetlememesi; yer tutucuyu doldurmayan gerçekleştirimin çıktıyı sessizce değiştirmesi.

Otomatik Yükleme dersi sınıfın nereden geldiğini tek bir yerde topladı. Bu derste soru sınıfın içine dönüyor: kullanan bir **ortak arayüze** bağlıysa ve gerçekleştirim değişirse **bu değişiklik nereye ulaşıyor?** Aynı soru, aynı sürücü, aynı sınıf ölçüsü.

**Ortak arayüz standardı**, birçok kitaplığın ve uygulamanın aynı imzayı kabul etmesidir. PHP topluluğunun kayıt tutma için önerdiği **PSR-3** bunun bilinen örneğidir: bir kaydediciyi iletiyle ve bir bağlam dizisiyle çağırırsınız, ileti içindeki `{anahtar}` yer tutucuları bağlam değerleriyle değiştirilir. Bu derste PSR-3'ün tamamı değil, aynı fikrin küçük bir hâli kullanılıyor: tek yöntemli `Kaydedici` arayüzü ve `{no}` gibi yer tutucular.

## Standart Öneri Ne Demektir

PSR, PHP topluluğunun yayımladığı **standart önerilerin** kısaltmasıdır ve numarayla anılır: PSR-3 kayıt tutmayı, PSR-4 otomatik yüklemeyi tanımlar. Adındaki "öneri" sözü gerçektir: dil bir önerinin uygulanıp uygulanmadığını denetlemez. Bir kitaplığın PSR-3'ü benimsemesi o kitaplığın kararıdır. Değeri uyguladıkça doğar: iki kitaplık aynı arayüzü benimserse birbirinden haberi olmadan aynı uygulamada çalışabilir.

## Kim Neyi Bilir

Ortak arayüzün asıl işi, birbirini tanımayan iki kod parçasını buluşturmaktır. Aşağıdaki sürücüde bir **kitaplık** ödeme alır ve bunu kaydetmek ister; bir **uygulama** ise kaydın nereye gideceğine karar verir. Kitaplık yalnız `Kaydedici` arayüzünü bilir. Uygulama arayüzü bilir ve iki gerçekleştirim yazar. İkisi yalnız arayüzde buluşur: kitaplık dosyası hiçbir gerçekleştirimin adını içermez.

```php
<?php
// kimbilir.php — kitaplik arayuzu bilir, uygulama gerceklestirimi secer
mkdir('olcum/kimbilir', 0777, true);
file_put_contents('olcum/kimbilir/kitaplik.php', <<<'PHP'
    <?php
    interface Kaydedici
    {
        public function kaydet(string $ileti): void;
    }
    class OdemeServisi
    {
        public function __construct(private Kaydedici $kaydedici) {}
        public function al(int $tutar): void { $this->kaydedici->kaydet("odeme alindi: $tutar"); }
    }
    PHP);
file_put_contents('olcum/kimbilir/uygulama.php', <<<'PHP'
    <?php
    class EkranKaydedici implements Kaydedici
    {
        public function kaydet(string $ileti): void { echo $ileti, "\n"; }
    }
    class BuyukHarfKaydedici implements Kaydedici
    {
        public function kaydet(string $ileti): void { echo strtoupper($ileti), "\n"; }
    }
    PHP);

$kitaplik = file_get_contents('olcum/kimbilir/kitaplik.php');
$anar = str_contains($kitaplik, 'Ekran') || str_contains($kitaplik, 'Buyuk');
echo 'kitaplik gerceklestirimi anar mi: ', $anar ? 'evet' : 'hayir', "\n";

require 'olcum/kimbilir/kitaplik.php';
require 'olcum/kimbilir/uygulama.php';
(new OdemeServisi(new EkranKaydedici()))->al(50);
(new OdemeServisi(new BuyukHarfKaydedici()))->al(50);
```

```
kitaplik gerceklestirimi anar mi: hayir
odeme alindi: 50
ODEME ALINDI: 50
```

İlk satır kitaplığın gerçekleştirimlerden habersiz olduğunu gösteriyor. Sonraki iki satırda aynı `OdemeServisi` iki farklı kaydediciyle çalıştı ve çıktısı ona göre değişti. Kitaplık tek satır değişmedi. Bu, önceki bölümün ölçtüğü şeyin nedenidir: bağlantı noktası kitaplığın içinde değil, gerçekleştirimi seçen `kurulum.php` benzeri yerdedir. Arayüz sınırı çizer, sınırın iki yanındaki kod birbirinin değişimine kapalı kalır.

## Kaydedici Verilmediğinde

Kitaplık arayüze bağlıysa uygulamanın bir gerçekleştirim vermemesi de düşünülmelidir. Yaygın çözüm, hiçbir şey yapmayan bir gerçekleştirimi varsayılan olarak kullanmaktır; PSR-3 bunun için ayrıca bir boş kaydedici sınıfı da önerir. Bu sayede kitaplığın her çağrıda `null` denetlemesi yapması gerekmez ve uygulama kaydı istemiyorsa hiçbir şey bağlamaz.

```php
<?php
// bos.php — kaydedici verilmezse kitaplik sessiz gerceklestirimle calisir
interface Kaydedici
{
    public function kaydet(string $ileti): void;
}
class SessizKaydedici implements Kaydedici
{
    public function kaydet(string $ileti): void {}
}
class EkranKaydedici implements Kaydedici
{
    public function kaydet(string $ileti): void { echo $ileti, "\n"; }
}
class RaporServisi
{
    private Kaydedici $kaydedici;

    public function __construct(?Kaydedici $kaydedici = null)
    {
        $this->kaydedici = $kaydedici ?? new SessizKaydedici();
    }

    public function uret(): int
    {
        $this->kaydedici->kaydet('rapor uretildi');
        return 3;
    }
}

$sessiz = (new RaporServisi())->uret();
echo "kaydedicisiz: $sessiz\n";
$ekranli = (new RaporServisi(new EkranKaydedici()))->uret();
echo "ekranli: $ekranli\n";
```

```
kaydedicisiz: 3
rapor uretildi
ekranli: 3
```

İki çağrı da aynı değeri döndürdü; yalnız ikincisi bir kayıt satırı yazdı. Kayıt tutmak kitaplığın asıl işine karışmıyor. Bu yüzden kayıt arayüzü çoğu zaman kitaplığın yanında değil, ayrı ve çok küçük bir pakette dağıtılır: kitaplıklar yalnız arayüze, uygulamalar da arayüzü gerçekleştiren pakete bağlanır. Bağımlılıklar arayüze doğru akar, birbirine doğru akmaz.

## Arayüz Bir Sınırdır

Arayüzler dersinde (M08/K03) arayüzün söz değil sınır olduğu görüldü: PHP imzayı denetler, davranışı denetlemez. Bu derste o ayrım bir ölçüme bağlanıyor. Önce arayüzün iyi çalıştığı durum, sonra denetlemediği durum.

**ST3.** Ders `Kaydedici` arayüzünü PSR-3'ün tamamına değil, tek `kaydet` yöntemine indirgenmiş hâliyle kullanır. Seviye adları, istisna bağlamı ve `Stringable` iletiler ölçülmez.

## PSR-3: Seviyeler ve Bağlam Dizisi

PSR-3 arayüzü her seviye için bir yöntem tanımlar ve genel bir `log` yöntemi ekler. Seviyeler en ağırdan en hafife doğru sekizdir: `emergency`, `alert`, `critical`, `error`, `warning`, `notice`, `info`, `debug`. İleti bir dizgidir ve içinde `{anahtar}` biçiminde yer tutucular taşıyabilir; ikinci argüman olan bağlam dizisi bu yer tutucuların değerlerini verir. Bağlamda `exception` anahtarı bir istisna nesnesi için ayrılmıştır. Standart hangi seviyenin yazılıp hangisinin atılacağını söylemez; bu bir gerçekleştirim kararıdır.

Aşağıdaki sürücü küçük bir gerçekleştirimi modeller: ağırlık sırası dizi sırasıdır ve bir eşik seviyesi eşiğin altındaki, yani daha hafif kayıtları atar. Aynı dört kayıt iki ayrı eşikle yazılır.

```php
<?php
// seviyeler.php — sekiz seviye, esik ve baglam dizisi
$seviyeler = ['emergency', 'alert', 'critical', 'error', 'warning', 'notice', 'info', 'debug'];

function yaz(array $seviyeler, string $esik, string $seviye, string $ileti, array $baglam): void
{
    if (array_search($seviye, $seviyeler) > array_search($esik, $seviyeler)) {
        return;
    }
    $yerler = [];
    foreach ($baglam as $anahtar => $deger) {
        $yerler['{' . $anahtar . '}'] = $deger;
    }
    echo str_pad($seviye, 10), strtr($ileti, $yerler), "\n";
}

$kayitlar = [
    ['critical', 'veritabani {sunucu} yanit vermiyor', ['sunucu' => 'db1']],
    ['warning', 'siparis {no} gecikti', ['no' => 42]],
    ['info', 'kullanici {kisi} giris yapti', ['kisi' => 'ayse']],
    ['debug', 'sorgu suresi {sure} ms', ['sure' => 12]],
];
foreach (['warning', 'debug'] as $esik) {
    echo "-- esik: $esik\n";
    foreach ($kayitlar as [$seviye, $ileti, $baglam]) {
        yaz($seviyeler, $esik, $seviye, $ileti, $baglam);
    }
}
```

```
-- esik: warning
critical  veritabani db1 yanit vermiyor
warning   siparis 42 gecikti
-- esik: debug
critical  veritabani db1 yanit vermiyor
warning   siparis 42 gecikti
info      kullanici ayse giris yapti
debug     sorgu suresi 12 ms
```

`warning` eşiğinde yalnız `critical` ve `warning` kayıtları yazıldı; `info` ve `debug` atıldı. `debug` eşiğinde dördü de yazıldı. İletiler her iki durumda yer tutucuları doldurarak çıktı: `{sunucu}` yerine `db1`, `{no}` yerine `42`. İletiyi bir kez, sabit bir kalıpla yazıp değişken kısmı bağlamda taşımanın yararı, aynı kalıbın farklı gerçekleştirimlerce işlenebilmesidir: biri düz metin, biri yapılandırılmış kayıt üretebilir.

## Ölçüm Düzeneği

`yayilim.php` önceki derslerle aynıdır: aynı programı değişiklikten önce ve sonra kurup koşturur. Sınıfı sırayla sorar: çıkış 0 değilse **kıran**, çıktı farklıysa **örtük**, düzenlenen dosya bağlantı listesindeyse **bağlantıda**, hiçbiri değilse **yerinde**. Önceki sürüm 0 ile çıkmalıdır ve kullanan `main.php` düzenlenmez.

```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;
}
```

## Gerçekleştirimi Değiştirmek: Bağlantıda

Gözlem `ortak-arayuz`: `Siparis` sınıfı yalnız `Kaydedici` arayüzünü tanır ve ona bir sipariş iletisi yazdırır. Hangi gerçekleştirimin kullanılacağını `kurulum.php` seçer; `main.php` onu `require` ile alıp `Siparis`'e verir. Tabanda `EkranKaydedici` iletiyi doğrudan ekrana basıyor. Değişiklik tek dosya: `kurulum.php` artık iletiyi bir tamponda biriktiren `TamponKaydedici` döndürüyor ve program sonunda hepsini basıyor. Dördüncü argüman bağlantı listesidir ve `kurulum.php`'yi bağlantı noktası olarak adlandırır.

`Siparis` yer tutucuyu kendisi doldurmaz. `{no}` yer tutucusunu dolduran `yerlestir()` fonksiyonu arayüzle aynı dosyada durur ve iki gerçekleştirim de onu çağırır; `Siparis` yalnız `kaydet` yönteminu bilir.

```php
<?php
// kurulum.php degisimi — gerceklestirim kurulum dosyasinda degisir
require_once 'yayilim.php';

// 10. Ortak bir kayit arayuzunun gerceklestirimi degistirilir
$siniflar[] = olc('ortak-arayuz', [
    'kaydedici.php' => <<<'PHP'
        <?php
        interface Kaydedici
        {
            public function kaydet(string $ileti, array $baglam = []): void;
        }
        function yerlestir(string $ileti, array $baglam): string
        {
            $yerler = [];
            foreach ($baglam as $anahtar => $deger) {
                $yerler['{' . $anahtar . '}'] = $deger;
            }
            return strtr($ileti, $yerler);
        }
        class EkranKaydedici implements Kaydedici
        {
            public function kaydet(string $ileti, array $baglam = []): void
            {
                echo yerlestir($ileti, $baglam), "\n";
            }
        }
        PHP,
    'kurulum.php' => <<<'PHP'
        <?php
        return new EkranKaydedici();
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'kaydedici.php';
        class Siparis
        {
            public function __construct(private Kaydedici $kaydedici) {}
            public function ver(int $no): void { $this->kaydedici->kaydet('siparis {no} alindi', ['no' => $no]); }
        }
        (new Siparis(require 'kurulum.php'))->ver(7);
        PHP,
], [
    'kurulum.php' => <<<'PHP'
        <?php
        class TamponKaydedici implements Kaydedici
        {
            private array $satirlar = [];
            public function kaydet(string $ileti, array $baglam = []): void
            {
                $this->satirlar[] = yerlestir($ileti, $baglam);
            }
            public function __destruct() { echo implode("\n", $this->satirlar), "\n"; }
        }
        return new TamponKaydedici();
        PHP,
], ['kurulum.php']);

echo kostur('olcum/ortak-arayuz/once')[1], "\n";
echo kostur('olcum/ortak-arayuz/sonra')[1], "\n";
$adlar = array_keys(oku('olcum/ortak-arayuz/sonra'));
sort($adlar);
echo implode(', ', $adlar), "\n";
```

```
ortak-arayuz       1 dosya  cikis=0   cikti ayni   -> baglantida
siparis 7 alindi
siparis 7 alindi
kaydedici.php, kurulum.php, main.php
```

İlk satır ölçümün sonucu: bir dosya değişti, çıkış 0 kaldı, çıktı aynı kaldı ve değişen dosya bağlantı listesinde olduğu için sınıf **bağlantıda**. Sonraki iki satır programın iki sürümünün çıktısıdır: ekrana yazan gerçekleştirim de, tamponlayan gerçekleştirim de aynı `siparis 7 alindi` satırını verdi. Son satır `olcum/ortak-arayuz/sonra` dizinindeki dosyaların sıralı listesidir: `main.php` listede var ve ölçüm sırasında hiç düzenlenmedi.

Sonuç şu: kullanan arayüze bağlı olduğu için gerçekleştirim değişince `Siparis` ve `main.php` yerinde kaldı. Değişiklik `kurulum.php` noktasında karşılandı. Ekrana basan gerçekleştirimden tamponlayana geçmek tek dosyalık bir iş oldu ve çıktı aynı kaldı.

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

Arayüz imzayı denetler, anlamı denetlemez. Aynı tabana bir gerçekleştirim daha uygulanıyor: `kaydet` yöntemi arayüzü imza olarak eksiksiz karşılar, ama bağlamı kullanmaz ve iletiyi yer tutucusu doldurulmadan basar. Sürücü ayrı bir ölçümdür ve `olcum/yer-tutucusuz` altında çalışır; taban önceki ölçümün tabanıdır.

```php
<?php
// yer-tutucusuz.php — imzayi karsilayan ama anlami tasimayan gerceklestirim
require_once 'yayilim.php';

$taban = oku('olcum/ortak-arayuz/once');
olc('yer-tutucusuz', $taban, [
    'kurulum.php' => <<<'PHP'
        <?php
        class DuzKaydedici implements Kaydedici
        {
            public function kaydet(string $ileti, array $baglam = []): void
            {
                echo $ileti, "\n";
            }
        }
        return new DuzKaydedici();
        PHP,
], ['kurulum.php']);

echo kostur('olcum/yer-tutucusuz/once')[1], ' -> ', kostur('olcum/yer-tutucusuz/sonra')[1], "\n";
```

```
yer-tutucusuz      1 dosya  cikis=0   cikti farkli -> ortuk
siparis 7 alindi -> siparis {no} alindi
```

Sınıf **örtük** oldu: bir dosya değişti, çıkış 0 kaldı, ama çıktı `siparis 7 alindi` iken `siparis {no} alindi` oldu. `DuzKaydedici` arayüzü imza olarak eksiksiz karşılıyor; PHP bir şey söylemedi, program çökmedi. Değişen dosya bağlantı listesinde olsa da çıktı değiştiği için sınıf **örtük** sayıldı, çünkü sıralamada çıktı farkı bağlantıdan önce gelir. Arayüz sınırı korudu, anlamı korumadı. Yer tutucuyu doldurma sözü yalnız belgede ve ortak standardın metninde duruyor; onu denetleyen bir ölçüm ya da test gerekir.

## Özet

- Bu dersin ölçü sınıfı **bağlantıda**. `ortak-arayuz` gözleminde gerçekleştirim `kurulum.php` dosyasında değişti, `Siparis` ve `main.php` düzenlenmedi, çıktı `siparis 7 alindi` kaldı.
- Ortak arayüz (PSR-3 gibi) kullananı gerçekleştirimden ayırır; değişiklik kurulum dosyasındaki bağlantı noktasında karşılanır.
- Sınırlayıcı ölçüm `yer-tutucusuz` **örtük**: imzayı karşılayan ama `{no}` yer tutucusunu doldurmayan gerçekleştirim çıkış 0 verdi, çıktı `siparis {no} alindi` oldu.
- Kitaplık yalnız arayüzü bilir, uygulama gerçekleştirimi seçer; PSR-3 sekiz seviye ve `{anahtar}` yer tutuculu bir bağlam dizisi tanımlar, hangi seviyenin yazılacağına gerçekleştirim karar verir.
- Arayüz imzayı denetler, anlamı denetlemez; anlam için ayrı ölçüm gerekir.

## Sonraki Adım

Kurulum dosyası gerçekleştirimi seçti. Bir bağımlılık ise başka birinin yayımladığı kodsa ve o kod güncellenirse kaç dosya düzenlenir? Bağımlılık Yöneticisi dersi bunu ölçüyor.
