PHP'de static olarak bildirilen özellik ve metotlar tek tek nesnelere değil, sınıfın kendisine aittir. Onlara nesne oluşturmadan Sinif::metot() veya Sinif::$ozellik biçiminde, çift iki nokta üst üste (::) operatörüyle erişilir. Sınıfın içinden erişirken üç anahtar kelime kullanılır: self:: kodun yazıldığı sınıfı, parent:: üst sınıfı, static:: ise çalışma anında gerçekten çağrılan sınıfı gösterir. Bu son davranışa late static binding (geç statik bağlama) denir ve kalıtımda self:: ile static:: farklı sonuçlar verebilir.

Bu yazıda static özellik ve metotları, :: operatörünü, self ve static farkını, new static() ile fabrika metotlarını, yönlendiren ve yönlendirmeyen çağrıları ve sınıf sabitlerini çalışan örneklerle ele alıyoruz. Nesne temelleri için sınıf ve nesne yazısına, serinin tamamı için PHP öğrenme rehberine göz atabilirsiniz. Fonksiyon içindeki static değişkenler ise değişkenler ve kapsam yazısının konusu.

static özellikler ve metotlar

static özellikler ve metotlar: Static metotta $this kullanılamaz, Static özelliğe nesne operatörüyle erişilmez

Bir özelliği static yaptığınızda o özelliğin sınıf başına tek bir kopyası olur; sınıftan kaç nesne üretirseniz üretin hepsi aynı değeri görür. Sayaçlar, sınıf düzeyinde önbellekler ve yapılandırma değerleri tipik kullanım alanlarıdır. Static bir metot de nesne olmadan çağrılabilir; bu yüzden içinde $this yoktur. Sınıfın içinden static üyelere self:: ile erişirsiniz. Sınıf adını bir değişkende tutup $sinif::metot() biçiminde de çağırabilirsiniz, ancak değişkenin değeri self, parent veya static gibi bir anahtar kelime olamaz.

php
<?php
class Kimlik
{
    private static int $sonNo = 0;
    public const ONEK = 'MUS-';

    public static function yeni(): string
    {
        self::$sonNo++;
        return self::ONEK . str_pad((string) self::$sonNo, 4, '0', STR_PAD_LEFT);
    }

    public static function toplam(): int
    {
        return self::$sonNo;
    }
}

echo Kimlik::yeni(), PHP_EOL;   // çıktı: MUS-0001
echo Kimlik::yeni(), PHP_EOL;   // çıktı: MUS-0002
echo Kimlik::toplam(), PHP_EOL; // çıktı: 2

$sinif = 'Kimlik';
echo $sinif::yeni(), PHP_EOL;   // çıktı: MUS-0003

Static özellikte değişkenin $ işareti :: operatöründen sonra gelir: self::$sonNo. Sabitlerde ise $ yoktur: self::ONEK. Bu küçük fark, yeni başlayanların sık karıştırdığı bir noktadır.

Örnekteki sayaç, betik çalıştığı sürece bellekte kalır ve her çağrıda kaldığı yerden devam eder; betik sona erdiğinde değer de kaybolur. Kalıcı bir numara gerekiyorsa değeri bir dosyada veya veritabanında tutmanız gerekir. Ayrıca static kelimesinin PHP'de birden fazla görevi olduğunu bilmekte fayda var. Kılavuz bu sayfanın yalnızca static özellik ve metotları anlattığını, aynı kelimenin fonksiyon içinde static değişken tanımlamak, static anonim fonksiyon oluşturmak ve late static binding için de kullanıldığını hatırlatır. Static anonim fonksiyonlar için closure ve arrow function yazısına bakabilirsiniz.

Static metotta $this kullanılamaz

Static bir metot belli bir nesneye bağlı çalışmadığı için içinde $this tanımlı değildir. Kullanmaya çalışırsanız metot çağrıldığında bir Error alırsınız. Tersi de bir hatadır: static olmayan bir metodu Sinif::metot() biçiminde çağırmak PHP 8.0'dan beri Error fırlatır; daha önce yalnızca kullanımdan kaldırma uyarısı veriyordu.

php
<?php
class Arac
{
    public string $ad = 'çekiç';

    public static function goster(): string
    {
        return $this->ad;
    }
}

echo Arac::goster();
text
Fatal error: Uncaught Error: Using $this when not in object context in /yol/ornek.php:8
Stack trace:
#0 /yol/ornek.php(12): Arac::goster()
#1 {main}
  thrown in /yol/ornek.php on line 8
php
<?php
class Arac
{
    public function ad(): string
    {
        return 'çekiç';
    }
}

echo Arac::ad();
text
Fatal error: Uncaught Error: Non-static method Arac::ad() cannot be called statically in /yol/ornek.php:10
Stack trace:
#0 {main}
  thrown in /yol/ornek.php on line 10

Static özelliğe nesne operatörüyle erişilmez

Static metotlar bir nesne üzerinden de çağrılabilir ($nesne::metot() ya da $nesne->metot()), ama static özellikler -> ile okunamaz. Kılavuz bunu açıkça belirtir: static özelliklere yalnızca :: ile erişilir. $nesne->ozellik yazarsanız PHP bir bildirim ve "tanımsız özellik" uyarısı üretir, değer de boş gelir.

php
<?php
class Ayar
{
    public static string $dil = 'tr';
}

$a = new Ayar();
echo $a::$dil, PHP_EOL; // çıktı: tr
echo $a->dil, PHP_EOL;
text
tr

Notice: Accessing static property Ayar::$dil as non static in /yol/ornek.php on line 9

Warning: Undefined property: Ayar::$dil in /yol/ornek.php on line 9

self:: ve static:: farkı: late static binding

self:: ve __CLASS__, metodun tanımlandığı sınıfa göre çözülür. Bu, kalıtımda bir sınırlama yaratır: üst sınıfta yazılmış bir metot self::tablo() çağırırsa, alt sınıf tablo() metodunu ezmiş olsa bile üst sınıfın sürümü çalışır. Late static binding bu sorunu çözer. static::, metodun yazıldığı sınıfı değil, çalışma anında çağrının yapıldığı sınıfı kullanır. PHP geliştiricileri bunun için yeni bir anahtar kelime eklemek yerine zaten ayrılmış olan static kelimesini kullanmayı seçmiştir.

php
<?php
class Model
{
    public static function tablo(): string
    {
        return 'kayitlar';
    }

    public static function sorgu(): string
    {
        return 'self: ' . self::tablo() . ' | static: ' . static::tablo();
    }

    public static function olustur(): static
    {
        return new static();
    }

    public static function olusturSelf(): self
    {
        return new self();
    }
}

class Urun extends Model
{
    public static function tablo(): string
    {
        return 'urunler';
    }
}

echo Urun::sorgu(), PHP_EOL;                 // çıktı: self: kayitlar | static: urunler
echo get_class(Urun::olustur()), PHP_EOL;     // çıktı: Urun
echo get_class(Urun::olusturSelf()), PHP_EOL; // çıktı: Model

Aynı fark nesne üretiminde de görülüyor. new self() her zaman Model üretir; new static() ise hangi sınıf üzerinden çağrıldıysa onu üretir. Dönüş tipi olarak static yazmak da bu niyeti tip sistemine taşır. Kılavuza göre PHP 8.5 ile final bir alt sınıfta, üst metodun static dönüş tipini self veya sınıfın kendi adıyla değiştirmek serbest bırakıldı, çünkü türetilemeyen bir sınıfta bu üçü aynı anlama gelir.

Late static binding yalnızca static metotlarla sınırlı değildir. Static olmayan bir bağlamda "çağrılan sınıf", nesnenin sınıfıdır. Kılavuz burada önemli bir inceliğe dikkat çeker: $this->metot() private metotları önce aynı kapsamda arar, static::metot() ise çağrılan sınıfa bakar; bu yüzden private metotlarla birlikte kullanıldığında ikisi farklı sonuç verebilir. Ayrıca static:: yalnızca static özelliklere başvurabilir.

Yönlendiren ve yönlendirmeyen çağrılar

Yönlendiren ve yönlendirmeyen çağrılar

Late static binding, "son yönlendirmeyen çağrıda" adı geçen sınıfı saklar. Bir sınıf adıyla doğrudan yapılan çağrı (A::foo()) yönlendirmeyen (non-forwarding) bir çağrıdır ve çağrılan sınıf bilgisini o sınıfa sıfırlar. self::, parent:: ve static:: ile yapılan çağrılar ise yönlendiren (forwarding) çağrılardır ve önceki çağrılan sınıf bilgisini korur. Çağrılan sınıfın adını get_called_class() fonksiyonuyla görebilirsiniz.

php
<?php
class A
{
    public static function kim(): void
    {
        echo get_called_class(), PHP_EOL;
    }

    public static function cagir(): void
    {
        static::kim();
    }
}

class B extends A
{
    public static function test(): void
    {
        A::cagir();      // yönlendirmeyen: bilgi A'ya sıfırlanır
        parent::cagir(); // yönlendiren: C bilgisi korunur
        self::cagir();   // yönlendiren: C bilgisi korunur
    }
}

class C extends B {}

C::test();
/*
A
C
C
*/

C::test() çağrısı çağrılan sınıfı C yapar. A::cagir() sınıf adını açıkça yazdığı için bu bilgiyi A ile değiştirir. parent::cagir() ve self::cagir() ise bilgiyi olduğu gibi aktarır, bu yüzden static::kim() her ikisinde de C sınıfında çözülür. Bir alt sınıfın davranışını korumak istediğiniz yerde üst sınıfın adını açıkça yazmak yerine parent:: kullanmanın nedeni budur.

Statik oluşturucu metotlar ve private kurucu

PHP bir sınıfta yalnızca tek bir kurucuya izin verir. Kılavuzun önerdiği çözüm, farklı girdi biçimleri için static oluşturucu metotlar yazmaktır. Kurucuyu private yaparsanız sınıf dışından new kullanılamaz ve nesneler yalnızca bu metotlar üzerinden üretilir. Static metotlar aynı sınıfın içinde olduğu için private kurucuya erişebilir.

php
<?php
class Tarih
{
    private function __construct(
        private int $gun,
        private int $ay,
        private int $yil,
    ) {}

    public static function metinden(string $s): static
    {
        [$g, $a, $y] = array_map('intval', explode('.', $s));
        return new static($g, $a, $y);
    }

    public static function diziden(array $d): static
    {
        return new static($d['gun'], $d['ay'], $d['yil']);
    }

    public function iso(): string
    {
        return sprintf('%04d-%02d-%02d', $this->yil, $this->ay, $this->gun);
    }
}

echo Tarih::metinden('07.11.2026')->iso(), PHP_EOL;                         // çıktı: 2026-11-07
echo Tarih::diziden(['gun' => 1, 'ay' => 3, 'yil' => 2025])->iso(), PHP_EOL; // çıktı: 2025-03-01

new Tarih(1, 1, 2026);
text
2026-11-07
2025-03-01

Fatal error: Uncaught Error: Call to private Tarih::__construct() from global scope in /yol/ornek.php:30
Stack trace:
#0 {main}
  thrown in /yol/ornek.php on line 30

Metot adları (metinden, diziden) neyin girdi olarak beklendiğini açıkça anlattığı için bu kalıba "isimli kurucu" (named constructor) da denir. Gerçek tarih işlemleri için PHP'nin yerleşik sınıflarını anlatan DateTime yazısına bakabilirsiniz.

Static özellikler ve kalıtım

Static özellikler de public ve protected oldukları sürece alt sınıfa geçer. Kılavuzun örneğinde üst sınıfta tanımlı bir static özellik, alt sınıfın adıyla (Bar::$my_static) ve alt sınıfın içinden parent::$my_static ile okunabiliyor. Asıl soru, alt sınıf üzerinden yapılan bir yazmanın nereye gittiğidir. Aşağıdaki denemede üst sınıftaki metotlar static::$kayit kullanıyor. Özelliği yeniden bildiren iki alt sınıf kendi ayrı dizilerine yazıyor; yeniden bildirmeyen üçüncü alt sınıf ise üst sınıfın dizisine yazıyor.

php
<?php
abstract class Onbellek
{
    protected static array $kayit = [];

    public static function koy(string $anahtar, mixed $deger): void
    {
        static::$kayit[$anahtar] = $deger;
    }

    public static function adet(): int
    {
        return count(static::$kayit);
    }
}

class SayfaOnbellek extends Onbellek
{
    protected static array $kayit = []; // kendi deposu
}

class MenuOnbellek extends Onbellek
{
    protected static array $kayit = []; // kendi deposu
}

class GenelOnbellek extends Onbellek {} // yeniden bildirmiyor

SayfaOnbellek::koy('ana', '<h1>Ana sayfa</h1>');
SayfaOnbellek::koy('iletisim', '<h1>İletişim</h1>');
MenuOnbellek::koy('ust', ['Ana', 'İletişim']);
GenelOnbellek::koy('surum', '1.2');

echo SayfaOnbellek::adet(), ' ', MenuOnbellek::adet(), ' ', GenelOnbellek::adet(), PHP_EOL; // çıktı: 2 1 1
echo Onbellek::adet(), PHP_EOL; // çıktı: 1

Son satır, GenelOnbellek üzerinden yazılan değerin aslında Onbellek sınıfının dizisine gittiğini gösteriyor: özelliği yeniden bildirmeyen alt sınıf, üst sınıfın static özelliğini paylaşıyor. Metotlarda static:: yerine self:: kullansaydınız, yeniden bildirilmiş özellikler hiç kullanılmaz ve bütün değerler Onbellek::$kayit içine yazılırdı. Bu kalıp, alt sınıf başına ayrı bir kayıt defteri tutmanın kısa bir yoludur. Trait'lerde static özelliklerin nasıl kopyalandığı ise trait kullanımı yazısında anlatılıyor.

:: operatörü ve sınıf sabitleri

:: operatörünün resmî adı kapsam çözümleme operatörüdür (Scope Resolution Operator). Kılavuz, İbranice "çift iki nokta" anlamına gelen Paamayim Nekudotayim adını da anar; bu ad Zend Engine 0.5 geliştirilirken verilmiş ve bazı hata mesajlarında hâlâ görülebilir. Operatör sabitlere, static özelliklere ve static metotlara erişmek için kullanılır. Üst sınıfın ezilmiş bir metodunu çağırmak için de parent::metot() yazımı kullanılır.

Sınıf sabitleri const ile tanımlanır, sınıf başına bir kez ayrılır ve varsayılan görünürlükleri public'tir. Alt sınıf bir sabiti yeniden tanımlayabilir; PHP 8.1'den beri final sabitler ezilemez. PHP 8.3 iki yenilik getirdi: sabitlere int, string, array gibi tip verilebiliyor ve sabit adı bir değişkenden Sinif::{$ad} yazımıyla dinamik okunabiliyor.

Sabitin değeri derleme anında bilinebilen bir ifade olmalıdır, ama bu ifade başka sabitleri kullanabilir. Kılavuzun örneğinde const TWO = ONE * 2; ve const THREE = ONE + self::TWO; gibi tanımlar geçerlidir. Tipli bir dizi sabitinde ise PHP 8.3 kuralına göre dizinin içeriği yalnızca skaler değerlerden oluşabilir. Sabitler nesne başına değil sınıf başına bir kez ayrıldığı için bir nesneden de ($nesne::SABIT) okunabilirler ve her nesnede aynı değeri verirler.

php
<?php
class Durum
{
    public const string TASLAK = 'taslak';
    public const string YAYINDA = 'yayinda';
    final public const array HEPSI = [self::TASLAK, self::YAYINDA];
    private const int GIZLI = 42;

    public static function gecerliMi(string $d): bool
    {
        return in_array($d, self::HEPSI, true);
    }
}

var_dump(Durum::gecerliMi('yayinda')); // çıktı: bool(true)
$ad = 'TASLAK';
echo Durum::{$ad}, PHP_EOL;            // çıktı: taslak
echo Durum::GIZLI;
text
bool(true)
taslak

Fatal error: Uncaught Error: Cannot access private constant Durum::GIZLI in /yol/ornek.php:18
Stack trace:
#0 {main}
  thrown in /yol/ornek.php on line 18

Sabitlerde de self:: ile static:: farkı geçerlidir. Üst sınıftaki bir metot self::BIRIM okursa kendi sabitini, static::BIRIM okursa çağrılan alt sınıfın yeniden tanımladığı sabiti alır:

php
<?php
class Para
{
    public const BIRIM = 'TRY';

    public static function birimler(): string
    {
        return self::BIRIM . ' / ' . static::BIRIM;
    }
}

class Euro extends Para
{
    public const BIRIM = 'EUR';
}

echo Para::birimler(), PHP_EOL; // çıktı: TRY / TRY
echo Euro::birimler(), PHP_EOL; // çıktı: TRY / EUR

Sabit değerleri sınıfa bağlı sabit kümeleri için hâlâ yaygın olsa da, sınırlı sayıda seçeneği temsil eden değerler (durum, rol, öncelik gibi) için PHP 8.1 ile gelen enum yapısı tip güvenliği açısından daha güçlü bir seçenektir. Sınıf dışı genel sabitler için define ve const yazısına bakabilirsiniz.

self, parent ve static özet tablosu

YazımNeyi gösterirNe zaman çözülürTipik kullanım
self::Kodun yazıldığı sınıfDerleme anı (tanım yerine göre)Kendi sabitleri ve static özellikleri
parent::Üst sınıfTanım yerine göreEzilen metodu veya üst kurucuyu çağırmak
static::Çalışma anında çağrılan sınıfÇalışma anıAlt sınıfta ezilebilecek davranış, new static()
Sinif::Adı yazılan sınıfYazıldığı gibiDışarıdan erişim; çağrılan sınıfı sıfırlar
$this->Mevcut nesneÇalışma anıStatic olmayan özellik ve metotlar

Sık yapılan hatalar

Sık yapılan hatalar: Static metotta $this kullanmak, Static olmayan metodu :: ile çağırmak, Static özelliği -> ile okumak, Kalıtımda self:: ile yetinmek
  • Static metotta $this kullanmak: "Using $this when not in object context" hatası alırsınız. Gerekli değeri parametre olarak alın veya metodu static olmaktan çıkarın.
  • Static olmayan metodu :: ile çağırmak: PHP 8.0'dan beri Error fırlatır; önce bir nesne oluşturun.
  • Static özelliği -> ile okumak: Bildirim ve "Undefined property" uyarısı üretir; Sinif::$ozellik yazın.
  • Kalıtımda self:: ile yetinmek: Alt sınıfın ezdiği metot veya sabit kullanılmaz; ezilebilir olmasını istediğiniz yerde static:: kullanın.
  • Static durumu aşırı kullanmak: Static özellikler betik boyunca paylaşılan küresel bir durum gibi davranır ve testleri birbirine bağımlı hâle getirebilir. Nesne düzeyinde tutulabilecek veriyi nesnede tutun.

Sık Sorulan Sorular

static metot ne zaman kullanılmalı?

Metodun bir nesnenin durumuna ihtiyacı yoksa (ör. bir oluşturucu metot, saf bir hesaplama veya sınıf düzeyinde bir sayaç) static uygundur. Nesneye ait verilerle çalışan metotlar ise static olmamalıdır.

self ile static arasındaki fark nedir?

self metodun tanımlandığı sınıfı, static çalışma anında çağrılan sınıfı gösterir. Kalıtım yoksa ikisi aynı sonucu verir; alt sınıflar devreye girdiğinde fark ortaya çıkar.

Alt sınıf static bir metodu ezebilir mi?

Evet. Kılavuzun late static binding örneklerinde alt sınıf, üst sınıftaki static who() metodunu aynı adla yeniden tanımlıyor. Ezilen sürümün üst sınıftaki kodlardan da çağrılmasını istiyorsanız üst sınıfta self:: yerine static:: kullanmanız gerekir; aksi hâlde üst sınıf her zaman kendi sürümünü çalıştırır.

Static metot bir nesne üzerinden çağrılabilir mi?

Evet. Kılavuza göre static üyelere örneklenmiş bir nesne üzerinden de erişilebilir; $nesne::metot() yazımı çalışır. Static özellikler ise -> ile okunamaz, $nesne::$ozellik yazılmalıdır.

Paamayim Nekudotayim ne demek?

Kılavuza göre bu ad İbranice "çift iki nokta" anlamına gelir ve :: operatörünün kendisidir. :: çevresinde bir sözdizimi hatası alırsanız çözüm adımları için fatal error ve ParseError yazısına bakabilirsiniz.

Static özellik alt sınıfla paylaşılır mı?

Alt sınıf static özelliği yeniden bildirmezse, yukarıdaki önbellek örneğinde görüldüğü gibi, üst sınıfla aynı depoyu kullanır. Alt sınıfa ayrı bir değer vermek istiyorsanız özelliği alt sınıfta yeniden bildirin ve üst sınıfın metotlarında static:: kullanın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: PHP öğrenme rehberi · Sınıf ve nesne · Kalıtım, abstract ve interface · Trait kullanımı · Enum kullanımı · define ve const