PHP'de sabit, betik çalıştığı sürece değeri değiştirilemeyen ve adı $ işareti almayan bir tanımlayıcıdır. Sabit iki yolla tanımlanır: const AD = değer; derleme zamanında, dosyanın en üst seviyesinde çalışır; define('AD', değer) ise bir fonksiyon olduğu için çalışma zamanında, koşulların veya fonksiyonların içinde de kullanılabilir. Tanımlanan sabit her kapsamdan görünür, yeniden tanımlanamaz ve silinemez.

Bu yazıda iki tanımlama yönteminin farkını, defined() ve constant() ile kontrolü, PHP 8 ile gelen hata davranışını, __DIR__ ve __LINE__ gibi sihirli sabitleri ve PHP_VERSION gibi önceden tanımlı sabitleri örneklerle anlatıyoruz. PHP 8.5'in sabitlere getirdiği yenilikleri de ayrıca belirtiyoruz. Serinin tamamı için PHP öğrenme rehberi sayfasına bakın.

Sabit nedir, değişkenden farkı ne?

Kılavuz, sabitle değişken arasındaki farkları dört maddede toplar: sabitlerin önünde $ yoktur; kapsam kurallarına bakılmaksızın her yerden tanımlanıp okunabilirler; bir kez tanımlandıktan sonra değiştirilemez veya silinemezler; değerleri yalnızca skaler tipler (bool, int, float, string) ya da diziler olabilir. PHP 8.1'den beri define() nesneyi de değer olarak kabul eder.

Sabit adları değişken adlarıyla aynı kurala uyar: harf veya alt çizgiyle başlar, ardından harf, rakam veya alt çizgi gelir. Adlar büyük-küçük harfe duyarlıdır ve gelenek olarak tamamen büyük harfle yazılır. PHP 8.0'dan önce define() fonksiyonunun üçüncü parametresiyle harf duyarsız sabit tanımlanabiliyordu; bu özellik 7.3'te kullanımdan kaldırılmaya başlandı ve 8.0'dan beri yalnızca false değeri kabul edilir. Sabitler ve global değişkenler ayrı ad alanlarında tutulur; yani true sabiti ile $TRUE değişkeni birbirinden bağımsızdır.

const ve define ile sabit tanımlama

const ve define ile sabit tanımlama: Koşula bağlı tanım için define kullanın, Ad alanlarında define tuzağı

İki yöntem de aynı türden sabit üretir; fark, ne zaman ve nerede değerlendirildikleridir. const bir dil yapısıdır ve derleme zamanında işlenir. Bu yüzden yalnızca dosyanın en üst seviyesinde (veya bir ad alanının ya da sınıfın gövdesinde) kullanılabilir; fonksiyon, döngü, if veya try/catch bloklarının içinde kullanılamaz. Değeri de sabit bir ifade olmalıdır: skaler değerler, diğer sabitlerle yapılan işlemler ve yalnızca skaler değer içeren diziler.

define() ise sıradan bir fonksiyondur ve çalışma zamanında çağrılır. Herhangi bir ifadeyi değer olarak alabilir, koşula bağlı olarak çalıştırılabilir ve adı bir değişkenden üretilebilir. Başarılı olduğunda true döndürür.

php
<?php
const SITE_ADI = 'Örnek Mağaza';
const KDV = 0.20;
const RENKLER = ['kırmızı', 'yeşil'];

define('PARA_BIRIMI', 'TRY');
define('GUN_SAYISI', 7 * 24 > 100 ? 'uzun' : 'kısa');   // define her ifadeyi kabul eder

echo SITE_ADI, "\n";      // çıktı: Örnek Mağaza
echo RENKLER[1], "\n";    // çıktı: yeşil
echo PARA_BIRIMI, "\n";   // çıktı: TRY
echo GUN_SAYISI, "\n";    // çıktı: uzun
var_dump(KDV);            // çıktı: float(0.2)

Aşağıdaki karşılaştırma tablosu iki yöntemin pratikteki farklarını özetler:

Özellikconstdefine()
Değerlendirme zamanıDerleme zamanıÇalışma zamanı
if, döngü veya fonksiyon içindeKullanılamazKullanılabilir
DeğerSabit ifade (skaler ve dizi)Herhangi bir ifade, 8.1 ile nesne de
Ad alanıBulunduğu namespace içinde tanımlanırAd düz metindir, namespace eklenmez
Sınıf sabitiSınıf gövdesinde kullanılırKullanılamaz
Attribute (PHP 8.5)EklenebilirEklenemez

Koşula bağlı tanım için define kullanın

Bir sabiti yalnızca belirli bir durumda tanımlamanız gerekiyorsa tek seçenek define()'dır. const deyimini bir if bloğuna yazdığınızda PHP dosyayı ayrıştırırken hata verir:

php
<?php
if (true) {
    const DEBUG = true;
}
text
Parse error: syntax error, unexpected token "const" in /yol/ornek.php on line 3

Aynı koşulu define() ile yazmak sorunsuz çalışır. Aşağıdaki örnek ayrıca defined() ile bir sabitin var olup olmadığını kontrol etmeyi ve constant() ile adı bir değişkende tutulan sabitin değerini okumayı gösteriyor. Dikkat: defined() sabitin adını metin olarak bekler, yani defined('DEBUG') yazılmalıdır.

php
<?php
$ortam = 'test';

if ($ortam === 'test') {
    define('DEBUG', true);    // çalışma zamanında, koşula bağlı tanım
}

var_dump(DEBUG);              // çıktı: bool(true)
var_dump(defined('DEBUG'));   // çıktı: bool(true)
var_dump(defined('YOK'));     // çıktı: bool(false)

$ad = 'DEBUG';
var_dump(constant($ad));      // çıktı: bool(true)

Ad alanlarında define tuzağı

define() sabitin adını düz bir metin olarak alır ve bulunduğu ad alanına göre çözümlemez. namespace Uygulama; satırının altında define('LIMIT', 1) çağırırsanız sabit sessizce global ad alanında oluşur. Sabiti ad alanına yerleştirmek için adın içine ad alanını yazmanız gerekir: define(__NAMESPACE__ . '\LIMIT', 1). Baştaki ters eğik çizgi ile yazılan bir ad ise true döner ama bir daha hiçbir şekilde okunamayan bir sabit oluşturur. const bu sorunu yaşamaz, çünkü bulunduğu ad alanında tanımlanır. defined() ve constant() da adları global ad alanında arar ve use takma adlarını uygulamaz. Ad alanları namespace ve use yazısında anlatılıyor.

Tanımsız sabit ve yeniden tanımlama hataları

PHP 8.0 öncesinde tanımsız bir sabit kullanıldığında PHP onu adıyla aynı metin gibi yorumluyor ve yalnızca uyarı veriyordu. PHP 8.0'dan beri tanımsız sabit bir Error fırlatır ve betik durur. Sabitler harf duyarlı olduğu için en sık rastlanan neden yazım farkıdır:

php
<?php
define('LIMIT', 10);
echo Limit;
text
Fatal error: Uncaught Error: Undefined constant "Limit" in /yol/ornek.php:3
Stack trace:
#0 {main}
  thrown in /yol/ornek.php on line 3

Aynı kural constant() için de geçerlidir: PHP 8.0'dan beri tanımsız bir ad verildiğinde null döndürmek yerine Error fırlatır. Bu tür yakalanmamış hataların nasıl okunacağı Fatal error: Uncaught Error yazısında, try/catch ile yakalanması ise try, catch ve exception yazısında anlatılıyor.

Tırnaksız dizi anahtarı da tanımsız sabittir

Eski betiklerde sık görülen $urun[fiyat] yazımı da aynı kurala takılır. Tırnak olmadığı için PHP fiyat kelimesini bir sabit adı olarak okur. PHP 7 ve öncesinde böyle bir sabit yoksa kelime metne çevrilip uyarıyla devam ediliyordu; kılavuza göre bu geri dönüş PHP 8.0 ile kaldırıldı ve artık Error fırlatılıyor. Metin anahtarları her zaman tırnak içinde yazın; anahtar gerçekten bir sabit veya değişkense tırnak kullanmayın, aksi hâlde PHP onları yorumlamaz.

php
<?php
$urun = ['ad' => 'Defter', 'fiyat' => 45];
echo $urun['ad'], "\n";    // çıktı: Defter
echo $urun[fiyat], "\n";   // tırnaksız anahtar: tanımsız sabit
text
Defter

Fatal error: Uncaught Error: Undefined constant "fiyat" in /yol/ornek.php:4
Stack trace:
#0 {main}
  thrown in /yol/ornek.php on line 4

Var olan bir sabiti yeniden tanımlamaya çalışmak sabitin değerini değiştirmez; PHP bir uyarı verir ve eski değer korunur. Kılavuzun 8.5 geçiş notlarına göre sabitin yeniden tanımlanması PHP 8.5'te kullanımdan kaldırıldı (deprecated); uyarı mesajı da bunun PHP 9'da hata olacağını söylüyor:

php
<?php
define('LIMIT', 10);
define('LIMIT', 20);
echo LIMIT, "\n";
text
Warning: Constant LIMIT already defined, this will be an error in PHP 9 in /yol/ornek.php on line 3
10

Bir yapılandırma dosyası birden fazla kez include edildiğinde bu uyarıyla sık karşılaşılır. Çözüm ya dosyayı require_once ile yüklemek ya da define() çağrısını if (!defined('LIMIT')) kontrolüyle korumaktır.

Sihirli sabitler (magic constants)

Sihirli sabitler (magic constants): __LINE__, __FILE__, __DIR__, __FUNCTION__

Sihirli sabitler, kaynak kodda yazıldıkları yere göre değer alan anahtar kelimelerdir: bulundukları dosya, satır, fonksiyon, sınıf, trait, ad alanı veya özellik kancası. Adlarına rağmen gerçek sabit değildirler; defined() ve constant() onları tanımaz ve define() ile aynı adda oluşturulan bir sabit onları etkilemez. Büyük-küçük harfe duyarsızdırlar ve ilgili bağlamın dışında kullanıldıklarında (örneğin sınıf dışında __CLASS__) boş metne dönüşürler.

Sihirli sabitDeğeri
__LINE__Yazıldığı satırın numarası
__FILE__Dosyanın tam yolu ve adı (sembolik bağlantılar çözülmüş)
__DIR__Dosyanın klasörü, dirname(__FILE__) ile aynı; kök dizin dışında sonda eğik çizgi yok
__FUNCTION__Fonksiyon adı (ad alanıyla); metot içinde yalnızca metot adı
__CLASS__Sınıf adı (ad alanıyla); trait içinde trait'i kullanan sınıfın adı
__TRAIT__Trait adı (ad alanıyla)
__METHOD__Sınıf ve metot adı, ör. Uygulama\Sepet::ekle
__PROPERTY__Property hook içinde özelliğin adı (PHP 8.4 ve sonrası)
__NAMESPACE__Geçerli ad alanının adı
php
<?php
namespace Uygulama;

function yardimci()
{
    return __FUNCTION__;
}

class Sepet
{
    public function ekle()
    {
        return __METHOD__ . ' / ' . __CLASS__;
    }
}

echo __LINE__, "\n";                 // çıktı: 17
echo basename(__FILE__), "\n";       // çıktı: c6.php
echo yardimci(), "\n";               // çıktı: Uygulama\yardimci
echo (new Sepet)->ekle(), "\n";      // çıktı: Uygulama\Sepet::ekle / Uygulama\Sepet
echo __NAMESPACE__, "\n";            // çıktı: Uygulama
var_dump(defined('__LINE__'));       // çıktı: bool(false)

Pratikte en çok kullanılan __DIR__'dır: require __DIR__ . '/ayarlar.php'; yazımı, betiği hangi klasörden çalıştırırsanız çalıştırın dosyayı kendi konumuna göre bulur. Göreli yollar ise geçerli çalışma dizinine bağlı olduğu için komut satırı ile web sunucusu arasında farklı sonuç verebilir. __PROPERTY__ sabitinin kullanımı property hooks yazısında, metot çağrılan sınıfın adını veren static::class ise static ve late static binding yazısında anlatılıyor. PHP 8.4'ten beri anonim fonksiyonlarda __FUNCTION__, eskiden olduğu gibi yalnızca {closure} değil, closure'ın tanımlandığı yeri içeren bir ad döndürür.

Önceden tanımlı sabitler

PHP çekirdeği ve yüklü eklentiler çok sayıda sabit tanımlar. Çekirdek sabitlerinden en kullanışlıları sürüm, platform ve sayı sınırlarıyla ilgilidir. PHP_VERSION sürümü metin olarak, PHP_VERSION_ID ise karşılaştırmaya uygun bir tamsayı olarak verir; 8.5.12 sürümünde bu değer 80512'dir. PHP_EOL platformun satır sonu karakterini, PHP_OS_FAMILY ise işletim sistemi ailesini ('Windows', 'Linux', 'Darwin', 'BSD', 'Solaris' veya 'Unknown') tutar. PHP_INT_MAX, PHP_INT_MIN ve PHP_INT_SIZE tamsayı sınırlarını, PHP_FLOAT_EPSILON ve PHP_FLOAT_MAX ise ondalıklı sayı sınırlarını verir. PHP 8.5 ile derleme tarihini veren PHP_BUILD_DATE ve derleyen tarafı belirten PHP_BUILD_PROVIDER eklendi; ikincisi her derlemede bulunmayabilir.

php
<?php
echo PHP_VERSION, "\n";          // çıktı: 8.5.12
echo PHP_MAJOR_VERSION, "\n";    // çıktı: 8
echo PHP_VERSION_ID, "\n";       // çıktı: 80512
echo PHP_INT_MAX, "\n";          // çıktı: 9223372036854775807
echo PHP_INT_SIZE, "\n";         // çıktı: 8

if (PHP_VERSION_ID >= 80400) {
    echo "PHP 8.4 veya üstü\n";  // çıktı: PHP 8.4 veya üstü
}

Sürüme göre farklı kod çalıştırmanız gerekiyorsa PHP_VERSION_ID ile tamsayı karşılaştırması yapmak, sürüm metnini parçalamaktan daha basit ve güvenilirdir. Hata seviyelerini belirten E_ERROR, E_WARNING gibi sabitler de bu listededir ve error_reporting ve hata seviyeleri yazısında ayrıca ele alınıyor. Tamsayı ve ondalıklı sayı sınırlarının pratik etkisini veri tipleri yazısında görebilirsiniz.

PHP 8.5 ile sabitlere gelen yenilikler

PHP 8.5 sabit ifadelerine iki yenilik getirdi. Birincisi tür dönüşümü (cast) desteğidir: const ORAN = (int) '18'; gibi bir tanım önceden "Constant expression contains invalid operations" hatası verirken artık geçerlidir. Kılavuz ayrıca closure'ların ve birinci sınıf callable'ların sabit ifadelerinde kullanılabildiğini belirtir. İkincisi, const ile tanımlanan (sınıf dışı) sabitlere öznitelik eklenebilmesidir; #[\Deprecated] özniteliği de artık sabitlerde kullanılabilir. define() ile tanımlanan sabitlere öznitelik eklenemez. Aşağıdaki örnek PHP 8.5 veya sonrasını gerektirir:

php
<?php
const ORAN = (int) '18';     // PHP 8.5: sabit ifadesinde tür dönüşümü
var_dump(ORAN);              // çıktı: int(18)

#[\Deprecated(message: 'YENI_LIMIT kullanın', since: '2.0')]
const ESKI_LIMIT = 5;        // PHP 8.5: const ile tanımlanan sabite attribute

echo ESKI_LIMIT, "\n";
text
int(18)

Deprecated: Constant ESKI_LIMIT is deprecated since 2.0, YENI_LIMIT kullanın in /yol/ornek.php on line 8
5

Kullanımdan kalkacak bir sabiti bu şekilde işaretlemek, kodunuzu kullanan ekiplere geçiş için süre tanır: sabit çalışmaya devam eder ama her kullanımda bir E_USER_DEPRECATED düzeyinde bildirim görünür. Özniteliklerin genel kullanımı PHP attributes yazısında, 8.5'in diğer yenilikleri PHP 8.5 yenilikleri yazısında anlatılıyor.

Uygulamalı örnek: güvenli bir ayar dosyası

Şimdi öğrendiklerimizi küçük bir ayar dosyasında birleştirelim. Ortam bilgisi çalışma zamanında belirlendiği için define() ile, defined() kontrolüyle korunarak tanımlanıyor; böylece dosya iki kez yüklense bile yeniden tanımlama uyarısı oluşmaz. getenv() ortam değişkeni bulunamazsa false döndürdüğü için kısa üçlü operatör varsayılan değere geçiyor. Değeri baştan belli olan dil ayarları ise const ile tanımlanıyor; ikinci sabitin bir önceki sabiti kullanması, sabit ifadelerinde diğer sabitlere başvurulabildiğini gösteriyor.

php
<?php
// ayarlar.php: birden fazla kez yüklense bile güvenli
if (!defined('UYGULAMA_ORTAMI')) {
    define('UYGULAMA_ORTAMI', getenv('UYGULAMA_ORTAMI') ?: 'gelistirme');
}

const VARSAYILAN_DIL = 'tr';
const DESTEKLENEN_DILLER = [VARSAYILAN_DIL, 'en', 'de'];

function dilSec(string $istenen): string
{
    return in_array($istenen, DESTEKLENEN_DILLER, true) ? $istenen : VARSAYILAN_DIL;
}

echo UYGULAMA_ORTAMI, "\n";     // çıktı: gelistirme
echo dilSec('de'), "\n";        // çıktı: de
echo dilSec('fr'), "\n";        // çıktı: tr

Fonksiyon içinden DESTEKLENEN_DILLER ve VARSAYILAN_DIL sabitlerine hiçbir global bildirimi olmadan erişildiğine dikkat edin; sabitlerin kapsamı her zaman globaldir. Aynı yapıyı değişkenlerle kursaydınız her fonksiyona parametre geçirmeniz veya global kullanmanız gerekirdi. in_array() çağrısındaki üçüncü argüman true, aramanın katı karşılaştırmayla yapılmasını sağlar; bu fonksiyon dizi fonksiyonları yazısında anlatılıyor.

Sık yapılan hatalar

Sık yapılan hatalar: Sabitin adını defined() içinde tırnaksız yazmak, Harf farkı, const deyimini koşul içinde kullanmak, Aynı sabiti iki kez tanımlamak
  • Sabitin adını defined() içinde tırnaksız yazmak: defined(DEBUG) sabitin değerini gönderir; doğrusu defined('DEBUG').
  • Harf farkı: LIMIT ile Limit farklıdır ve PHP 8'de tanımsız sabit betiği durdurur.
  • const deyimini koşul içinde kullanmak: Ayrıştırma hatası verir; koşullu tanım için define() kullanın.
  • Aynı sabiti iki kez tanımlamak: Uyarı üretir, PHP 8.5'te kullanımdan kaldırıldı; require_once veya defined() kontrolü kullanın.
  • Ad alanında define ile sabit oluşturup ad alanında aramak: Ad, ad alanı önekiyle verilmedikçe sabit global ad alanına düşer.

Sık Sorulan Sorular

const mu define mı kullanmalıyım?

Değer önceden belliyse ve tanım dosyanın en üst seviyesindeyse const tercih edin; ad alanına uyar, öznitelik alabilir ve sınıf içinde de aynı sözdizimiyle yazılır. Sabiti koşula bağlı tanımlamanız veya adını çalışma zamanında üretmeniz gerekiyorsa define() kullanın.

Sabite dizi atanabilir mi?

Evet. Hem const hem define() dizileri kabul eder; const ile tanımlanan dizinin elemanları da skaler sabit ifadeler olmalıdır. Elemanlara normal dizi gibi RENKLER[1] biçiminde erişilir.

Bir sabitin tanımlı olup olmadığını nasıl kontrol ederim?

defined('AD') fonksiyonunu kullanın; sınıf sabitleri ve enum durumları için de çalışır (defined('Sinif::SABIT')). Değişkenler için isset(), fonksiyonlar için function_exists() kullanılır.

__DIR__ ile dirname(__FILE__) arasında fark var mı?

Kılavuza göre __DIR__, dirname(__FILE__) ile eşdeğerdir. Daha kısa olduğu ve fonksiyon çağrısı gerektirmediği için yeni kodda genellikle __DIR__ tercih edilir.

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 · PHP değişkenler ve kapsam · PHP veri tipleri · PHP static ve sınıf sabitleri · PHP enum kullanımı