PHP PDO Nedir? Neden Kullanmalıyız?
PHP PDO (PHP Data Objects), PHP'nin farklı veritabanlarına tek bir arayüzle erişim sağlayan hafif ve tutarlı bir katmanıdır. MySQL, PostgreSQL, Oracle gibi çeşitli veritabanı sistemleriyle çalışabilen bu yapı, kodunuzu daha esnek ve taşınabilir kılar.
PDO kullanmak, geliştirme süreçlerinizde standart bir yaklaşım benimsemenizi sağlar. Bu, özellikle büyük projelerde veya farklı veritabanı sistemleriyle çalışırken büyük bir avantajdır.
(In-Article)
- Güvenlik: SQL enjeksiyonu gibi yaygın güvenlik açıklarına karşı prepared statements (hazırlanmış ifadeler) ile koruma sağlar.
- Esneklik: Veritabanı türünü değiştirdiğinizde kodunuzda minimum değişiklikle adapte olmanızı sağlar.
- Performans: Hazırlanmış ifadeler, aynı sorgunun tekrar tekrar çalıştırılmasında veritabanı sunucusunun iş yükünü azaltır.
- Hata Yönetimi: Daha gelişmiş ve tutarlı hata raporlama mekanizmaları sunar.
PDO Bağlantısı Nasıl Oluşturulur?
PDO ile bir veritabanına bağlanmak, uygulamanızın ilk ve en kritik adımıdır. Doğru bir bağlantı, diğer tüm veritabanı işlemlerinin sorunsuz çalışmasını sağlar.
Veritabanı Bağlantısı Ayarları
Bağlantı için gerekli bilgileri (sunucu adı, veritabanı adı, kullanıcı adı, şifre) tanımlamanız gerekir. Bu bilgiler, DSN (Data Source Name) adı verilen bir string içinde birleştirilir.
$host = 'localhost';$db = 'veritabani_adi';$user = 'kullanici_adi';$pass = 'sifre';$charset = 'utf8mb4';$dsn = "mysql:host=$host;dbname=$db;charset=$charset";$options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false,];Try-Catch Bloğu ile Hata Yönetimi
Veritabanı bağlantısı sırasında oluşabilecek hataları yakalamak ve yönetmek önemlidir. Try-catch bloğu, bağlantı başarısız olduğunda uygulamanızın çökmesini engeller.
try { $pdo = new PDO($dsn, $user, $pass, $options);} catch (PDOException $e) { throw new PDOException($e->getMessage(), (int)$e->getCode());}Bu yapı, bağlantı sorunlarını kullanıcıya dostça bir mesajla bildirme veya loglama gibi eylemler için zemin hazırlar.
Veri Sorgulama: SELECT İşlemleri
Veritabanından bilgi çekmek, çoğu uygulamanın temel işlevidir. PDO, bu işlemleri güvenli ve etkili bir şekilde yapmanızı sağlar.
Hazırlanmış İfadeler (Prepared Statements)
Prepared statements, SQL enjeksiyonu saldırılarına karşı en etkili savunma mekanizmasıdır. Sorgu şablonu bir kez hazırlanır ve parametreler daha sonra güvenli bir şekilde bağlanır.
$stmt = $pdo->prepare("SELECT * FROM kullanicilar WHERE id = :id");$stmt->bindParam(':id', $id, PDO::PARAM_INT);$stmt->execute();Parametre bağlama, verinin sorgu string'ine doğrudan katılmasını engelleyerek, kötü niyetli girdilerin SQL komutları olarak yorumlanmasının önüne geçer.
Tek Satır Veri Çekme (fetch)
Sorgunuzdan yalnızca tek bir kayıt bekliyorsanız fetch() metodunu kullanırsınız. Bu metod, varsayılan olarak bir dizi döndürür.
$user = $stmt->fetch();if ($user) { echo "Kullanıcı Adı: " . $user['kullanici_adi'];}Tüm Satırları Çekme (fetchAll)
Bir sorgudan birden fazla kayıt döndürmek istediğinizde fetchAll() metodunu kullanırsınız. Bu, tüm sonuçları içeren bir dizi döndürür.
$users = $stmt->fetchAll();foreach ($users as $user) { echo $user['kullanici_adi'] . "
";}Veri Manipülasyonu: INSERT, UPDATE, DELETE
Veritabanında kayıt oluşturma, güncelleme ve silme işlemleri de prepared statements ile güvenli bir şekilde yapılmalıdır.
INSERT İşlemi
Yeni bir kayıt eklemek için INSERT ifadesini kullanırız.
$stmt = $pdo->prepare("INSERT INTO urunler (ad, fiyat) VALUES (:ad, :fiyat)");$stmt->bindParam(':ad', $urunAdi);$stmt->bindParam(':fiyat', $urunFiyati);$stmt->execute();echo "Yeni ürün eklendi. ID: " . $pdo->lastInsertId();UPDATE İşlemi
Mevcut bir kaydı güncellemek için UPDATE ifadesi kullanılır.
$stmt = $pdo->prepare("UPDATE urunler SET fiyat = :yeniFiyat WHERE id = :id");$stmt->bindParam(':yeniFiyat', $yeniFiyat);$stmt->bindParam(':id', $urunId);$stmt->execute();echo $stmt->rowCount() . " kayıt güncellendi.";DELETE İşlemi
Bir kaydı veritabanından silmek için DELETE ifadesi kullanılır.
$stmt = $pdo->prepare("DELETE FROM urunler WHERE id = :id");$stmt->bindParam(':id', $urunId);$stmt->execute();echo $stmt->rowCount() . " kayıt silindi.";İşlemler (Transactions) ile Veri Bütünlüğü
Birbiriyle ilişkili birden fazla veritabanı işleminin tutarlı bir şekilde tamamlanmasını sağlamak için transaction (işlem) mekanizması kullanılır. Tüm işlemler başarılı olursa değişiklikler kalıcı olur (commit), aksi takdirde tüm değişiklikler geri alınır (rollback).
beginTransaction(): İşlemleri başlatır.commit(): Tüm değişiklikleri kalıcı hale getirir.rollBack(): Başarısızlık durumunda tüm değişiklikleri geri alır.
try { $pdo->beginTransaction(); // İlk INSERT işlemi $stmt1 = $pdo->prepare("INSERT INTO siparisler (kullanici_id, urun_id) VALUES (:kullanici, :urun)"); $stmt1->bindParam(':kullanici', $kullaniciId); $stmt1->bindParam(':urun', $urunId); $stmt1->execute(); // İkinci UPDATE işlemi $stmt2 = $pdo->prepare("UPDATE stok SET miktar = miktar - 1 WHERE urun_id = :urun"); $stmt2->bindParam(':urun', $urunId); $stmt2->execute(); $pdo->commit(); echo "İşlemler başarıyla tamamlandı.";} catch (Exception $e) { $pdo->rollBack(); echo "Hata oluştu, işlemler geri alındı: " . $e->getMessage();}Bu, özellikle finansal işlemler gibi kritik durumlarda veri bütünlüğünü sağlamak için hayati öneme sahiptir.
Gelişmiş PDO Özellikleri ve İpuçları
PDO'nun sunduğu bazı gelişmiş özellikler ve doğru kullanım ipuçları, kodunuzu daha sağlam ve yönetilebilir hale getirir.
Hata Modları (Error Modes)
PDO, hataları farklı şekillerde yönetmenize olanak tanır:
PDO::ERRMODE_SILENT(Varsayılan): Hataları yoksayar, sadece hata kodu ayarlar.PDO::ERRMODE_WARNING: Hataları PHP uyarısı olarak gösterir.PDO::ERRMODE_EXCEPTION: Hataları PDOException olarak fırlatır. Bu, genellikle en çok tercih edilen moddur çünkü try-catch blokları ile kolayca yönetilebilir.
Bağlantı sırasında PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ayarını yaparak bu modu aktif hale getirebilirsiniz.
Fetch Modları (Fetch Modes)
fetch() ve fetchAll() metodlarının nasıl veri döndüreceğini belirleyen fetch modları vardır:
PDO::FETCH_ASSOC: Sütun adlarını anahtar olarak içeren ilişkisel bir dizi.PDO::FETCH_NUM: Sıfırdan başlayan indekslerle sayısal bir dizi.PDO::FETCH_BOTH: Hem ilişkisel hem de sayısal anahtarları içeren bir dizi.PDO::FETCH_OBJ: Sütun adlarını özellik olarak içeren bir nesne.PDO::FETCH_CLASS: Belirtilen sınıfın bir örneğine verileri yükler.
Varsayılan fetch modunu bağlantı seçeneklerinde PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC olarak ayarlayabilirsiniz.
Güvenlik İçin PDO: SQL Enjeksiyonuna Karşı Koruma
PDO'nun en büyük avantajlarından biri, SQL enjeksiyonu riskini minimuma indirmesidir. Kullanıcıdan alınan tüm verileri sorguya doğrudan dahil etmek yerine, bindParam() veya bindValue() ile parametre olarak bağlamak, güvenlik açıklarını önler.
Asla kullanıcıdan gelen veriyi doğrudan sorgu içine katmayın. Her zaman hazırlanmış ifadeler kullanın.
Sıkça Yapılan Hatalar ve Çözümleri
- Bağlantı Kapatmama: PHP, betik sona erdiğinde veritabanı bağlantısını otomatik olarak kapatır. Ancak, kaynakları erken serbest bırakmak isterseniz
$pdo = null;komutunu kullanabilirsiniz. - Hata Yönetimini İhmal Etme:
PDO::ERRMODE_EXCEPTIONkullanmak ve hataları uygun try-catch bloklarıyla yakalamak, uygulamanızın kararlılığı için kritik öneme sahiptir. - Prepared Statements Kullanmama: En büyük güvenlik açığı budur. Her zaman kullanıcı girdisi içeren sorgularda prepared statements kullanın.
Sıkça Sorulan Sorular (SSS)
PDOStatement::execute() metodu neden false döndürüyor?
execute() metodunun false döndürmesi, sorgu çalıştırılırken bir hata oluştuğunu gösterir. Hatanın detaylarını görmek için $stmt->errorInfo() metodunu kullanabilirsiniz. Genellikle yanlış parametre bağlama, SQL sözdizimi hatası veya veritabanı kısıtlamaları (örneğin benzersiz alan ihlali) bu duruma yol açar. PDO::ERRMODE_EXCEPTION modunu kullanmak, bu hataları doğrudan bir istisna olarak yakalamanızı sağlar.
PDO::lastInsertId() metodu her veritabanı için çalışır mı?
PDO::lastInsertId() metodu, son eklenen kaydın ID'sini döndürür. MySQL gibi bazı veritabanları için doğrudan çalışırken, PostgreSQL gibi bazılarında parametre olarak tablo adını veya sekans adını belirtmeniz gerekebilir (örneğin $pdo->lastInsertId('tablo_adi_id_seq')). Hangi veritabanıyla çalıştığınıza bağlı olarak dokümantasyonu kontrol etmek en doğrusudur.
PDOStatement::rowCount() ne zaman kullanılır ve ne anlama gelir?
PDOStatement::rowCount() metodu, en son çalıştırılan DELETE, INSERT veya UPDATE sorgusu tarafından etkilenen satır sayısını döndürür. SELECT sorguları için bu metodun dönüş değeri veritabanına ve sürücüye göre değişebilir ve genellikle güvenilir değildir. SELECT sorgularında sonuç satırı sayısını almak için genellikle fetchAll() sonrası dizinin eleman sayısını (count($results)) kullanmak daha doğru bir yaklaşımdır.