PHP'de == (eşit) iki değeri tip dönüşümünden sonra karşılaştırır, === (özdeş) ise hem değerin hem tipin aynı olmasını ister. Bu yüzden 1 == '1' sonucu true, 1 === '1' sonucu false olur. PHP 8.0 ile önemli bir değişiklik geldi: Bir sayı, sayısal olmayan bir metinle karşılaştırıldığında artık sayı metne çevrilir; böylece eski sürümlerde true dönen 0 == 'foo' artık false döner. Kılavuz, tip dönüşümünün her zaman açık olmadığını belirterek çoğu durumda === ve !== kullanmanızı önerir.
Bu yazıda gevşek ve sıkı karşılaştırmanın kurallarını, PHP'nin type juggling denen otomatik tip dönüşümünü, sayısal metinleri, bilimsel gösterim tuzağını, strpos() ve in_array() gibi fonksiyonlardaki tipik hataları, kayan noktalı sayı karşılaştırmasını ve tip dönüştürme (cast) işlemlerini çalıştırılmış örneklerle anlatıyoruz. Örnekler PHP 8.5.12 ile denendi. Veri tiplerinin kendisi için PHP veri tipleri, serinin tamamı için PHP öğrenme rehberi sayfasına bakabilirsiniz.
== ve === farkı
=== kuralı basittir: İki değer aynı tipteyse ve değerleri eşitse true, değilse false. Hiçbir dönüşüm yapılmaz. == ise önce iki tarafı ortak bir tipe getirir, sonra karşılaştırır. Kılavuza göre iki taraf da sayısal metinse veya biri sayı diğeri sayısal metinse karşılaştırma sayısal yapılır. Bu kural switch deyimi için de geçerlidir.
<?php
var_dump(1 == '1'); // bool(true)
var_dump(1 === '1'); // bool(false)
var_dump('1' == '01'); // bool(true) iki sayısal metin
var_dump('10' == '1e1'); // bool(true) 1e1 = 10
var_dump(100 == '1e2'); // bool(true)
var_dump('abc' == 0); // bool(false) PHP 8 ve sonrası
var_dump(null == false); // bool(true)
var_dump([] == false); // bool(true)
var_dump('0' == false); // bool(true)
var_dump('' == null); // bool(true)Son dört satır, == ile karşılaştırmanın ne kadar geniş bir eşitlik tanımı yaptığını gösteriyor. Kılavuzdaki karşılaştırma tablosuna göre bir taraf bool veya null ise iki taraf da bool'a çevrilir; null, boş dizi, '0' ve boş metin false sayıldığı için hepsi birbirine gevşekçe eşittir. Metinler arasında ise null boş metne çevrilir. '1' == '01' örneği de önemli: İki taraf da metin olduğu halde ikisi de sayısal olduğu için sayı olarak karşılaştırılıyorlar.
PHP 8.0'da değişen metin ve sayı karşılaştırması

PHP 8.0 öncesinde bir sayı ile bir metin karşılaştırıldığında metin her zaman sayıya çevrilirdi. Sayısal olmayan metinler 0 olduğu için 0 == 'herhangi bir kelime' doğru çıkardı. PHP 8.0'ın geriye dönük uyumsuz değişiklikler listesine göre artık sayı, sayısal olmayan bir metinle karşılaştırılırken metne çevrilir ve iki metin karşılaştırılır. Sayısal metinlerle karşılaştırma eskisi gibi çalışmaya devam eder.
| Karşılaştırma | PHP 8.0 öncesi | PHP 8.0 ve sonrası |
|---|---|---|
| 0 == '0' | true | true |
| 0 == '0.0' | true | true |
| 0 == 'foo' | true | false |
| 0 == '' | true | false |
| 42 == ' 42' | true | true |
| 42 == '42foo' | true | false |
<?php
var_dump(0 == 'foo'); // bool(false)
var_dump(0 == ''); // bool(false)
var_dump(42 == ' 42'); // bool(true)
var_dump(42 == '42foo'); // bool(false)
var_dump('42' == '42.0'); // bool(true)
var_dump('abc' == 'ABC'); // bool(false)Tablo kılavuzdan, kod çıktısı PHP 8.5.12'den. Eski bir projeyi yükseltiyorsanız bu değişiklik sessizce davranış değiştirebilir: PHP 7'de çalışan bir if ($deger == 0) kontrolü, değer boş metin olduğunda PHP 8'de farklı sonuç verir. Son satır da metin karşılaştırmasının büyük/küçük harfe duyarlı olduğunu hatırlatıyor; duyarsız karşılaştırma için strcasecmp() gibi fonksiyonlar kullanılır.
Sayısal metinler ve aritmetikte tip dönüşümü
Kılavuza göre bir metin, bir int veya float olarak yorumlanabiliyorsa sayısaldır. PHP 8.0'dan beri baştaki ve sondaki boşluklara izin verilir, yani ' 12' ve '12 ' sayısaldır. Bir de başı sayısal metin kavramı vardır: '10 elma' gibi sayıyla başlayıp başka karakterle devam eden metinler. Aritmetik işlemde sayısal metin sorunsuz çevrilir, başı sayısal metin çevrilir ama uyarı üretir, sayısal olmayan metin ise TypeError fırlatır.
<?php
var_dump(1 + '10.5'); // float(11.5)
var_dump('5' * '4'); // int(20)
var_dump(is_numeric('12'), is_numeric(' 12'), is_numeric('12 '), is_numeric('12abc'), is_numeric('1e3'));
// bool(true) bool(true) bool(true) bool(false) bool(true)
var_dump(1 + '10 elma');
/* çıktı:
Warning: A non-numeric value encountered in /yol/ornek.php on line 7
int(11)
*/
// var_dump(1 + 'elma'); ise şunu verir:
// Fatal error: Uncaught TypeError: Unsupported operand types: int + string in /yol/ornek.php:2Tip dönüşümü sayfası, PHP'nin otomatik dönüşüm yaptığı bağlamları sayar: aritmetik operatörlerin kullanıldığı sayısal bağlam; echo, metin birleştirme ve metin içine değişken yazmanın oluşturduğu metin bağlamı; if, üçlü operatör ve mantıksal operatörlerin oluşturduğu mantıksal bağlam; karşılaştırma operatörlerinin oluşturduğu karşılaştırma bağlamı ve tipli parametrelerin oluşturduğu fonksiyon bağlamı. Önemli bir not: Değer başka bir tip olarak yorumlandığında değişkenin kendi tipi değişmez; $s = '5'; $s * 2; sonrasında $s hâlâ bir metindir.
Bilimsel gösterim tuzağı: "0e" ile başlayan metinler

Kılavuz, rakamlarla çevrili bir E harfi içeren her metnin bilimsel gösterimde bir sayı sayıldığını ve bunun beklenmedik sonuçlar doğurabileceğini uyarır. '0E1' değeri 0 çarpı 10 üzeri 1, yani sıfırdır. Bu nedenle iki farklı metin, ikisi de 0e ile başlayıp yalnızca rakamla devam ediyorsa == ile eşit çıkar:
<?php
var_dump('0E1' == '000'); // bool(true)
var_dump('2E1' == '020'); // bool(true) 20 == 20
var_dump('0D1' == '000'); // bool(false) bilimsel gösterim değil
var_dump('0e462' == '0e830'); // bool(true) ikisi de 0
var_dump('0e462' === '0e830'); // bool(false)Fonksiyon dönüşlerinde false ve 0 karışıklığı
strpos() aranan metni bulursa konumunu (int), bulamazsa false döndürür. Kılavuz bu fonksiyon için açık bir uyarı içerir: Dönüş false olabileceği gibi false gibi değerlendirilen 0 da olabilir, bu yüzden sonucu === ile test edin. Aranan metin en baştaysa konum 0'dır ve == false kontrolü onu "bulunamadı" sanır:
<?php
$metin = 'php öğreniyorum';
$konum = strpos($metin, 'php');
var_dump($konum); // int(0)
if ($konum == false) {
echo 'Yanlış: bulunamadı sanıldı', PHP_EOL;
}
if ($konum !== false) {
echo "Doğru: $konum konumunda bulundu", PHP_EOL;
}
/* çıktı:
Yanlış: bulunamadı sanıldı
Doğru: 0 konumunda bulundu
*/Yalnızca "içeriyor mu?" sorusunun cevabı gerekiyorsa PHP 8.0'dan beri var olan str_contains() doğrudan bool döndürür ve bu tuzağı tamamen ortadan kaldırır. Metin fonksiyonlarının tamamı PHP string fonksiyonları yazısında.
Aynı sorun dizi aramasında da görülür. in_array() varsayılan olarak gevşek karşılaştırma yapar. Kılavuz, katı (strict) modda olmadığında true değerinin her doğru sayılan metinle, false değerinin ise '' ve '0' ile eşleştiğini belirtir ve tiplerden emin değilseniz üçüncü parametreyi true vermenizi önerir:
<?php
$izinli = ['1', '2', '3'];
var_dump(in_array(1, $izinli)); // bool(true)
var_dump(in_array(1, $izinli, true)); // bool(false)
$durumlar = ['aktif', 'pasif'];
var_dump(in_array(0, $durumlar)); // bool(false) PHP 8 ve sonrası
var_dump(in_array(true, $durumlar)); // bool(true)
var_dump(in_array(true, $durumlar, true)); // bool(false)
var_dump(array_search('1', [0, 1, '1'], true)); // int(2)array_search() de aynı strict parametresini alır ve tıpkı strpos() gibi bulunamadığında false, bulunduğunda anahtarı döndürür; anahtar 0 olabileceği için sonucu yine !== false ile kontrol etmelisiniz. Dizi fonksiyonlarının ayrıntısı PHP dizi fonksiyonları yazısında.
switch gevşek, match sıkı karşılaştırır
Kılavuz, gevşek karşılaştırma kurallarının switch deyimi için de geçerli olduğunu belirtir. PHP 8.0 ile gelen match ifadesi ise dallarını === ile karşılaştırır. Aynı girdi iki yapıda farklı dala gidebilir:
<?php
$girdi = '1';
switch ($girdi) {
case 1:
echo 'switch: int 1 ile eşleşti', PHP_EOL;
break;
case '1':
echo "switch: '1' ile eşleşti", PHP_EOL;
break;
}
echo match ($girdi) {
1 => 'match: int 1',
'1' => "match: '1'",
}, PHP_EOL;
/* çıktı:
switch: int 1 ile eşleşti
match: '1'
*/switch metin '1' ile sayı 1'i eşit saydığı için ilk case dalına girdi. match ise tipi de karşılaştırdığı için doğru dalı seçti. İki yapının diğer farkları için if, else, switch ve match yazısına bakabilirsiniz.
Büyüklük karşılaştırması ve spaceship operatörü
<, >, <= ve >= operatörleri de aynı tip dönüşümü kurallarına uyar. <=> (spaceship) operatörü sol taraf küçükse negatif, eşitse sıfır, büyükse pozitif bir tam sayı döndürür ve sıralama fonksiyonlarında çok kullanılır. Diziler önce eleman sayısına göre, sayı eşitse eleman eleman karşılaştırılır.
<?php
echo 1 <=> 2, ' ', 2 <=> 2, ' ', 3 <=> 2, PHP_EOL; // -1 0 1
echo 'a' <=> 'b', ' ', 'zz' <=> 'aa', PHP_EOL; // -1 1
echo [1, 2, 3] <=> [1, 2, 4], ' ', [1, 2] <=> [1, 2, 0], PHP_EOL; // -1 -1
var_dump('10' < '9'); // bool(false) ikisi de sayısal: 10 < 9
var_dump('10' < '9a'); // bool(true) metin karşılaştırması
var_dump('abc' < 'b'); // bool(true)İkinci ve üçüncü var_dump satırı arasındaki fark öğreticidir: '10' ve '9' sayısal olduğu için sayı olarak karşılaştırılır ve 10, 9'dan büyüktür. '9a' sayısal olmadığı için karşılaştırma metin olarak yapılır ve '1' karakteri '9''dan önce geldiği için sonuç tersine döner. Kılavuz ayrıca, bool veya null içeren karşılaştırmalarda her iki tarafın bool'a çevrildiğini hatırlatır; bu yüzden null < -1 sonucu true çıkar, çünkü false < true'dur. Sıralama için PHP dizi sıralama yazısına bakın.
Kayan noktalı sayıları karşılaştırmak
Kılavuz, kayan noktalı sayıların iç gösterimi nedeniyle iki float değeri eşitlik için doğrudan test etmemenizi söyler. Önerilen yöntem, farkın mutlak değerini küçük bir tolerans değeriyle karşılaştırmaktır. NAN ise özel bir durumdur: true dışındaki hiçbir değere, kendisi de dahil, eşit değildir. NAN kontrolü için is_nan() kullanılır.
<?php
$a = 0.1 + 0.2;
var_dump($a == 0.3); // bool(false)
var_dump(abs($a - 0.3) < PHP_FLOAT_EPSILON); // bool(true)
var_dump(round($a, 2) == 0.3); // bool(true)
var_dump(NAN == NAN); // bool(false)
var_dump(is_nan(sqrt(-1))); // bool(true)Tolerans değeri hesabınızın ölçeğine göre seçilmelidir; kılavuzdaki örnek beş basamak hassasiyet için 0.00001 kullanır. Para gibi kesin sonuç gerektiren hesaplarda değeri kuruş cinsinden tam sayıya çevirerek çalışmayı da düşünebilirsiniz.
Tip dönüştürme (cast) ve doğru değer tablosu

Bir değeri açıkça başka bir tipe çevirmek için tip adını parantez içinde değerin önüne yazarsınız: (int), (float), (string), (bool), (array), (object). Kılavuza göre (integer), (boolean), (double) ve (binary) takma adları PHP 8.5'ten itibaren deprecated'dir; standart adları kullanın.
<?php
var_dump((int) '12abc'); // int(12)
var_dump((int) 'abc'); // int(0)
var_dump((int) 9.99); // int(9)
var_dump((bool) '0'); // bool(false)
var_dump((bool) '0.0'); // bool(true)
var_dump((bool) []); // bool(false)
var_dump((bool) [0]); // bool(true)
var_dump((string) false); // string(0) ""
var_dump((string) true); // string(1) "1"
var_dump(intval('0x1A'), intval('012'), intval('42', 8)); // int(0) int(12) int(34)Açık dönüşüm, aritmetikteki otomatik dönüşümden farklı olarak uyarı vermez: (int) '12abc' sessizce 12 üretir. Bu nedenle kullanıcı girdisini doğrulamak için cast yerine filter_var gibi doğrulama fonksiyonlarını tercih edin. (bool) '0.0' sonucunun true olmasına da dikkat edin: Yalnızca '0' ve boş metin false sayılır. Kılavuzun karşılaştırma tablolarından seçilmiş satırlar şöyledir:
| $x | gettype() | empty($x) | isset($x) | if ($x) |
|---|---|---|---|---|
| "" | string | true | true | false |
| "0" | string | true | true | false |
| "php" | string | false | true | true |
| 0 | integer | true | true | false |
| null | NULL | true | false | false |
| [] | array | true | true | false |
| false | boolean | true | true | false |
Tablodaki gettype() sütunu, fonksiyonun gerçekte döndürdüğü adları gösterir: PHP 8.5.12'de gettype(0) "integer", gettype(false) "boolean" döndürür. isset() ile empty() farkı için Undefined variable ve array key uyarıları yazısına bakabilirsiniz.
Küçük uygulama: form verisini güvenle kontrol etmek
HTML formları sayı veya mantıksal değer göndermez, her şeyi metin olarak gönderir; kılavuz da bunu karşılaştırma tablolarının başında hatırlatır. Kullanıcı adet alanına 0 yazdığında gelen değer '0' metnidir ve gevşek bir kontrol onu "boş" sanır:
<?php
$_POST = ['adet' => '0', 'kupon' => ''];
$adet = $_POST['adet'] ?? null;
if (!$adet) {
echo 'Gevşek kontrol: adet boş sayıldı', PHP_EOL;
}
if ($adet === null || $adet === '') {
echo 'Adet girilmemiş', PHP_EOL;
} elseif (filter_var($adet, FILTER_VALIDATE_INT) === false) {
echo 'Adet tam sayı değil', PHP_EOL;
} else {
echo 'Adet geçerli: ', (int) $adet, PHP_EOL;
}
/* çıktı:
Gevşek kontrol: adet boş sayıldı
Adet geçerli: 0
*/İkinci kontrol üç ayrı durumu ayırt ediyor: alan hiç gelmemiş, boş gönderilmiş veya tam sayı olmayan bir şey yazılmış. filter_var() sonucunun da === false ile kontrol edildiğine dikkat edin; geçerli bir 0 değeri döndüğünde gevşek kontrol yine yanılırdı.
Sık yapılan hatalar
- strpos sonucunu == false ile kontrol etmek: Konum 0 olduğunda yanlış sonuç verir;
=== falseveyastr_contains()kullanın. - in_array'i strict olmadan kullanmak: Karışık tipli dizilerde beklenmedik eşleşmeler olur; üçüncü parametreyi
trueverin. - Özetleri == ile karşılaştırmak:
0eile başlayan sayısal metinler eşit çıkabilir;hash_equals()kullanın. - Float eşitliği test etmek:
0.1 + 0.2 == 0.3yanlıştır; tolerans ile karşılaştırın. - PHP 7 davranışına güvenmek:
0 == ''artıkfalse; yükseltmeden sonra gevşek karşılaştırmaları gözden geçirin. - Girdiyi cast ile doğrulamak:
(int)geçersiz girdiyi sessizce sayıya çevirir; önce doğrulayın.
Sık Sorulan Sorular
Her zaman === mı kullanmalıyım?
Kılavuz, tip dönüşümünün her zaman açık olmadığını belirterek çoğu durumda === ve !== kullanmanın tavsiye edildiğini yazar. == kullanmanın bilinçli bir tercih olduğu durumlar da vardır; örneğin iki sayısal metni sayı olarak karşılaştırmak. Önemli olan, hangi kuralın uygulanacağını bilerek seçim yapmaktır.
İki nesne ne zaman eşittir?
== iki nesneyi aynı sınıftan olup özellikleri eşitse eşit sayar; === ise iki değişkenin aynı nesne örneğini gösterip göstermediğine bakar. Bu konu ve nesne kopyalama clone ve nesne karşılaştırma yazısında ayrıntılı anlatılıyor.
Diziler == ile nasıl karşılaştırılır?
== iki dizide aynı anahtar ve değer çiftleri varsa true döner; sıra ve tip önemli değildir. === ise ayrıca aynı sırayı ve aynı tipleri ister. Örneğin ['x' => 1, 'y' => 2] == ['y' => 2, 'x' => 1] doğru, === ile yanlıştır; [1, 2] == ['1', '2'] de doğru ama özdeş değildir.
Boş metin, null ve 0 arasındaki farkı nasıl kontrol ederim?
Üçü de gevşek karşılaştırmada ve if koşulunda false gibi davranır. Ayırt etmek için === null, === '' ve === 0 gibi sıkı kontroller kullanın. Değişkenin tanımlı olup olmadığını isset(), bir dizi anahtarının varlığını değeri null olsa bile array_key_exists() ile kontrol edebilirsiniz.
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 veri tipleri · PHP operatörler ve öncelik · if, else, switch ve match · Tip bildirimleri ve strict_types