---
title: 'Tip Bildirimleri'
source: 'https://academia.sh/tr/kurslar/php-nesne-modeli/tip-bildirimleri'
course: 'Nesneye Dayalı PHP ve Standartlar'
language: tr
updated: '2026-10-21T05:03:35+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Parametre, dönüş ve özellik tipi bildirir; ?int ve birleşim tipi yazar'
    - 'Tipsiz bir parametreye int eklemenin null veren kullananı durdurduğunu ölçer'
    - 'Aynı eklemenin ?int ile ve sayısal metin gönderen kullanana ulaşmadığını gösterir'
---

# Tip Bildirimleri

Parametre, dönüş ve özellik tipleri, ?int ve birleşim tipi ve bir parametreye tip eklemenin kullananı hangi girdilerde durdurduğu.

Sihirli yöntemler adları gevşek biçimde çözüyordu; tip bildirimleri (type declaration) sınıfın sınırına bir kapı koyar. Soru, tipsiz bir parametreye `int` yazmanın kullananı hangi girdilerde durdurduğudur.

## Tip Bildirimleri

Bir parametrenin, dönüş değerinin ya da özelliğin adından önce yazılan tip, PHP'nin o noktada kabul edeceği değerleri sınırlar. `?int` ya `int` ya da `null` demektir. `int|string` birleşim tipidir (union type): iki tipten birini kabul eder.

```php
<?php
// Kdv.php — parametre, donus, ?int ve birlesim tipi
class Kdv
{
    public static function ekle(int $tutar): float
    {
        return $tutar * 1.2;
    }

    public static function yaz(?int $adet): string
    {
        return $adet === null ? 'yok' : 'var';
    }

    public static function tur(int|string $kod): string
    {
        return gettype($kod);
    }
}
```

```php
<?php
// kdv_kullan.php — tipe uyan girdiler gecer, uymayan TypeError verir
require 'Kdv.php';

var_dump(Kdv::ekle(100));
echo Kdv::yaz(null), ' ', Kdv::yaz(7), "\n";
echo Kdv::tur(5), ' ', Kdv::tur('a'), "\n";

try {
    Kdv::ekle('abc');
} catch (TypeError $e) {
    echo get_class($e), "\n";
}
```

```
float(120)
yok var
integer string
TypeError
```

**NM25.** `ekle()` yalnız `int` aldı ve `'abc'` gelince `TypeError` fırlattı; `yaz()` `null`'ı kabul etti çünkü tipi `?int`'ti. Bu davranışın ayrıntısı, yani `TypeError`, `E_DEPRECATED` ve `strict_types`, M12/K01 Değişkenler dersinde ölçülmüştü ve burada yinelenmez. Bu ders bir tip bildiriminin eklenmesinin kullanana ulaşıp ulaşmadığını soruyor.

## Dönüş Tipleri: void ve never

`void`, yöntemin bir değer döndürmediğini söyler; çağrının sonucu her zaman `null`'dır ve bir değere bağlanması anlamsızdır. `never` daha güçlü bir sözdür: yöntem hiç dönmez; ya bir istisna fırlatır, ya süreci sonlandırır ya da sonsuza dek sürer. `never` bildirilmiş bir yöntem sessizce sona ererse PHP bunu `TypeError` ile bildirir.

```php
<?php
// Akis.php — void ve never donus tipleri
class Akis
{
    public static function yaz(string $mesaj): void
    {
        echo $mesaj, "\n";
    }

    public static function dur(string $sebep): never
    {
        throw new RuntimeException($sebep);
    }

    public static function bozukDur(): never
    {
        echo "ic\n";
    }
}

var_dump(Akis::yaz('a'));

try {
    Akis::dur('x');
} catch (RuntimeException $e) {
    echo get_class($e), ' ', $e->getMessage(), "\n";
}

try {
    Akis::bozukDur();
} catch (TypeError $e) {
    echo get_class($e), "\n";
}
```

```
a
NULL
RuntimeException x
ic
TypeError
```

`yaz()` bir şey yazdı ve çağrının değeri `null` çıktı. `dur()` hiç dönmedi, istisna yakalandı. `bozukDur()` gövdesini çalıştırdı ama sonunda dönmeye kalkınca `TypeError` aldı; `never` sözünü tutmayan kod tipin kendisi tarafından yakalanır.

## Özellik Tipi ve Başlatılmamış Özellik

Özellik tipi, özelliğe yazılan her değeri denetler. Varsayılan değeri olmayan tipli bir özellik başlatılmamış durumdadır; bu, `null` olmakla aynı şey değildir. Başlatılmamış özelliği okumak `Error` doğurur. `null` kabul eden tipli özellikte ise varsayılan değer yazılırsa okuma `null` verir.

```php
<?php
// Profil.php — ozellik tipi ve baslatilmamis ozellik
class Profil
{
    public int $yas;
    public ?string $ad = null;
}

$profil = new Profil();
var_dump($profil->ad);

try {
    echo $profil->yas;
} catch (Error $e) {
    echo get_class($e), "\n";
}

try {
    $profil->yas = 'abc';
} catch (TypeError $e) {
    echo get_class($e), "\n";
}

$profil->yas = '42';
var_dump($profil->yas);
```

```
NULL
Error
TypeError
int(42)
```

`ad` varsayılan olarak `null` taşıdığı için okunabildi; `yas` ise hiç yazılmadığı için `Error` verdi. `'abc'` sayıya çevrilemediğinden `TypeError` doğdu, `'42'` ise kipsiz dosyada `int`'e zorlandı. Özellik tipi bu yüzden iki ayrı sözdür: yazılan değerin tipi ve yazılmadan okunamayacağı.

## mixed ve Birleşim Tipinde Zorlama

`mixed` her değeri kabul eder; `null` dahil. Tip yazmamakla farkı, tipin bilerek açık bırakıldığını söylemesidir. Birleşim tipinde ise, değer üyelerden hiçbirine tam uymuyorsa PHP kipsiz dosyada bir zorlama dener ve hangi üyeye çevireceğini kurala göre seçer: tam sayı olarak okunabilen bir metin `int`, ondalıklı bir metin `float` olur.

```php
<?php
// Esle.php — mixed ve int|float birlesim tipinde zorlama
class Esle
{
    public static function herhangi(mixed $deger): string
    {
        return gettype($deger);
    }

    public static function sayi(int|float $sayi): string
    {
        return gettype($sayi);
    }
}

echo Esle::herhangi(null), ' ', Esle::herhangi([1]), "\n";
echo Esle::sayi('1.5'), ' ', Esle::sayi('7'), ' ', Esle::sayi(true), "\n";
```

```
NULL array
double integer integer
```

`mixed` hiçbir değeri reddetmedi. `int|float` ise `'1.5'` metnini `float`'a (`gettype` bunu `double` diye yazar), `'7'` metnini ve `true` değerini `int`'e çevirdi. Birleşim tipi bir girdinin tipini korumaz, kabul ettiği üyelerden birine çevirebilir; bu yüzden tipi sınırlayan kişi, kabul edilen çevirilerin neler olduğunu da sınırlamış olur.

## static Dönüş Tipi

Bir yöntemin dönüş tipi `static` ise, yöntemin hangi sınıf üzerinden çağrıldıysa o sınıfın nesnesini döndüreceğini söyler. `self` bunun aksine, yöntemin yazıldığı sınıfı gösterir. Zincirleme çağrılan yöntemler `static` kullanırsa alt sınıfın nesnesi zincir boyunca alt sınıf olarak kalır.

```php
<?php
// Sorgu.php — static donus tipi zincirde alt sinifi korur
class Sorgu
{
    private array $parca = [];

    public function nerede(string $kosul): static
    {
        $kopya = clone $this;
        $kopya->parca[] = $kosul;
        return $kopya;
    }

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

class OzelSorgu extends Sorgu
{
}

$sorgu = (new OzelSorgu())->nerede('a')->nerede('b');
echo get_class($sorgu), ' ', $sorgu->say(), "\n";
```

```
OzelSorgu 2
```

`nerede()` `Sorgu` sınıfında yazılmış olsa da `OzelSorgu` üzerinden çağrıldığı için dönen nesne `OzelSorgu` oldu. Dönüş tipi `self` yazılmış olsaydı tip `Sorgu` olarak okunur ve zincirin ucundaki nesnenin alt sınıf olduğu tip düzeyinde kaybolurdu. Bu fark, bir sınıfı sonradan genişletecek kodlar için önemlidir: alt sınıfın kendi yöntemlerini zincirin sonunda çağırabilmek, dönüş tipinin alt sınıfı koruyup korumadığına bağlıdır.

## Kalıtımda Tip Uyumu

Alt sınıf bir yöntemi yeniden tanımladığında tipleri üst sınıfla uyumlu olmak zorundadır. Kural şudur: dönüş tipi daraltılabilir (üst sınıf `iterable` döndürüyorsa alt sınıf `array` döndürebilir, çünkü her `array` bir `iterable`'dır), parametre tipi ise genişletilebilir ama daraltılamaz. Üst sınıf kodunun beklediği garantiler alt sınıfta zayıflamamalıdır.

```php
<?php
// Kaynak.php — donus tipini daraltmak serbesttir
class Kaynak
{
    public function ver(): iterable
    {
        return [1];
    }
}

class Daraltan extends Kaynak
{
    public function ver(): array
    {
        return [1, 2];
    }
}

echo count((new Daraltan())->ver()), "\n";
```

```
2
```

Tersini deneyen kod sınıf bildirimi aşamasında durur.

```bash
# uyumsuz.sh — donus tipini genisletmek ve parametre tipini daraltmak bildirilemez yapar
cat > Genis.php <<'PHP'
<?php
class Taban { public function ver(): array { return []; } }
class Alt extends Taban { public function ver(): iterable { return []; } }
PHP
cat > Dar.php <<'PHP'
<?php
class Taban { public function al(int|string $girdi): void {} }
class Alt extends Taban { public function al(int $girdi): void {} }
PHP
php -d display_errors=0 Genis.php; echo "genis cikis=$?"
php -d display_errors=0 Dar.php; echo "dar cikis=$?"
```

```
genis cikis=255
dar cikis=255
```

İkisi de aynı ilkeye çarptı. `Taban` tipli bir değişkene konan her nesne, `ver()` çağrıldığında `array` döndüreceğine söz verir; `iterable` döndüren bir alt sınıf bu sözü bozar. Benzer biçimde `al()` hem `int` hem `string` kabul ediyorsa, yalnız `int` kabul eden alt sınıf, üst sınıf tipiyle yazılmış çağrıyı reddedebilir.

## Ölçüm Çekirdeği

Bu dersin ölçümü de `yayilim.php` dosyasını kullanır; çekirdek ilk derste satır satır açıklanmıştı.

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

## Parametreye Tip Eklenir

Ölçülen değişiklik, tipsiz `ekle($tutar)` yöntemini `ekle(int $tutar): float` yapmaktır. Kullanan `main.php` değişkeni `null` ile bırakıp `Kdv::ekle($tutar)` çağırır ve sonucu `var_dump` ile yazdırır.

```php
<?php
// parametre_tipi.php — tipsiz parametreye int eklenir, kullanan null veriyor
require_once 'yayilim.php';

olc('parametre-tipi', [
    'kdv.php' => <<<'PHP'
        <?php
        class Kdv
        {
            public static function ekle($tutar) { return $tutar * 1.2; }
        }
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'kdv.php';
        $tutar = null;
        var_dump(Kdv::ekle($tutar));
        PHP,
], [
    'kdv.php' => <<<'PHP'
        <?php
        class Kdv
        {
            public static function ekle(int $tutar): float { return $tutar * 1.2; }
        }
        PHP,
]);

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

```
parametre-tipi     1 dosya  cikis=255 cikti farkli -> kiran
once cikis=0 cikti=float(0)
sonra cikis=255 cikti=
```

**NM26.** Önce `null * 1.2` sessizce `float(0)` verdi, tip eklenince `null` bir `int`'e dönüşemediği için `TypeError` doğdu ve çıkış 255 oldu. Hata, kullanan dosya değişmeden, yürütme sırasında duyuldu. Dersin birinci ölçü sınıfı kırandır.

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

Kırılma tip bildirimi eklemekten mi geliyor, yoksa eklenen tipin `null`'ı reddetmesinden mi? Aynı değişikliği `?int` ile yapmak ikincisini ayırır.

```php
<?php
// bos_izinli.php — ayni degisiklik, bu kez ?int ile
require_once 'yayilim.php';

olc('bos-izinli', [
    'kdv.php' => <<<'PHP'
        <?php
        class Kdv
        {
            public static function ekle($tutar) { return $tutar * 1.2; }
        }
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'kdv.php';
        $tutar = null;
        var_dump(Kdv::ekle($tutar));
        PHP,
], [
    'kdv.php' => <<<'PHP'
        <?php
        class Kdv
        {
            public static function ekle(?int $tutar): float { return $tutar * 1.2; }
        }
        PHP,
]);

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

```
bos-izinli         1 dosya  cikis=0   cikti ayni   -> yerinde
once cikis=0 cikti=float(0)
sonra cikis=0 cikti=float(0)
```

**NM27.** `?int` ile `null` hâlâ geçti ve `float(0)` aynı kaldı: tip bildirimi yerinde bir değişiklik olabildi. Kıran, tipin `null`'ı reddetmesiydi. Bir başka girdi türü sayısal metindir: `strict_types` kullanılmayan bir dosyada `'5'` gibi sayısal metin bir `int` parametreye zorlanır.

```php
<?php
// sayisal_metin.php — kullanan '5' veriyor, dosyasi strict_types kullanmiyor
require_once 'yayilim.php';

olc('sayisal-metin', [
    'kdv.php' => <<<'PHP'
        <?php
        class Kdv
        {
            public static function ekle($tutar) { return $tutar * 1.2; }
        }
        PHP,
    'main.php' => <<<'PHP'
        <?php
        require 'kdv.php';
        var_dump(Kdv::ekle('5'));
        PHP,
], [
    'kdv.php' => <<<'PHP'
        <?php
        class Kdv
        {
            public static function ekle(int $tutar): float { return $tutar * 1.2; }
        }
        PHP,
]);

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

```
sayisal-metin      1 dosya  cikis=0   cikti ayni   -> yerinde
once cikis=0 cikti=float(6)
sonra cikis=0 cikti=float(6)
```

**NM28.** `'5'` zorlamayla `5` oldu ve sonuç önce de sonra da `float(6)` kaldı: kullanan yerinde. Yani tip eklemek kullananı yalnız tipin reddettiği girdilerde durdurur; kabul ettiği ya da zorlayabildiği girdilerde ulaşmaz. Bu kursta ölçülen kıranlar bildirimde de çağrıda da duyuldu ve hangi aşamada duyuldukları M11/K01'in konusudur; kurs aşamayı değil değişikliğin kullanana ulaşıp ulaşmadığını ölçer.

## Özet

- Parametre, dönüş ve özellik tipi bir değerin kabul edildiği noktayı sınırlar; `?int` `int` ya da `null`, `int|string` iki tipten biridir.
- Tipsiz `ekle($tutar)` yöntemine `int` eklenince `null` veren kullanan `float(0)` yerine çıkış 255 aldı; bu dersin ölçü sınıfı kırandır.
- Aynı değişiklik `?int` ile yapılınca `null` hâlâ geçti ve çıktı `float(0)` kaldı: yerinde.
- Kullanan `'5'` veriyorsa ve dosyası kipsizse tip eklemek zorlama nedeniyle yerinde kaldı, çıktı `float(6)`.
- Tip eklemenin kullanana ulaşması tipin reddettiği girdilere bağlıdır.

## Sonraki Adım

Sınıflar, arayüzler, trait'ler, sabitler, sihirli yöntemler ve tipler tek dosyadan çok dosyaya yayıldıkça adların çakışması kaçınılmaz olur. Sıradaki ders Ad Alanları, `use` ile içe aktarmanın ve ad alanı değişikliğinin kullananı nasıl etkilediğini soruyor.
