Php PDO Sınıfı ve Kullanımı

Bugün sizlerle php5 ile birlikte gelen pdo (php data object) sınıfının nasıl kullanılacağını ve hangi özellikleri olduğunu görecegiz. Bunun yanında pdo sınıfının avantajlarına da değineceğiz. Bildiğiniz üzere php5 ile birlikte oop mantığı iyice oturmuş durumda pdo da php5 ile gelmiş bir veritabanı sınıfı ve php artık bizim normal mysql fonksiyonlarını kullanmamızı önermemekte. Gelin bakalım pdo nasıl bir şeymiş.

PDO’nun Avantajları

  • Sql Injection yeme olasığınız yoktur. Kullanıcıdan alınan tüm veriler temizlenerek sorguya dahil edilir.
  • Nesne yönelimli programlama yatkındır.
  • Milisaniylerin bile önemli olduğu büyük sistemlerde hızlıdır.
  • Bir çok veritabanı sağlayıcısı  (mysql,sql,oracle vb.) ile uyumludur. Alt yapı değişikliğine uygundur.
  • Php eski mysql komutlarını önermediği için öğrenip kullanmaya başlamak gereklidir.

PDO’nun Dezavantajları

  • Php5 ile geldigi için php4 ile uyumluluğu yoktur.
  • Nesne yönelimli programlamaya yeni başlayanlar için yabancı gelebilir.

Aslına bakılırsa avantajları yanında dezavantajları yok denilebilir. Yeni teknolojileri öğrenmek her zaman sizi bir adım daha önde tutacaktır.

Şimdi gelin bakalım pdo sınıfı nasıl kullanılırmış , hangi fonksiyonları varmış ne işe yararmış.

Öncelikle sorgularımızda kullanacağımız bir veritabanı ve bir de tabloya ihtiyacımız olacak. Ben pdo isminde bir veritabanı ve example isminde bir tablo oluşturdum. Tablomun içinde title,description,author,category isminde sütunlarım mevcut veritabanı oluşturma kodu aşağıda veritabanımızı oluşturarak makalemize başlıyoruz.

Sql

--
-- Veritabanı: `pdo`
--
CREATE DATABASE IF NOT EXISTS `pdo` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `pdo`;
 
-- --------------------------------------------------------
 
--
-- Tablo için tablo yapısı `example`
--
 
CREATE TABLE IF NOT EXISTS `example` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  `description` longtext,
  `author` varchar(255) DEFAULT NULL,
  `category` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=93 ;

 

Pdo ile veritabanı bağlantısı

Pdo bir sınıf olduğu için her hangi bir sınıf nasıl türetiliyor ve başlatılıyor ise pdo’da aynı şekilde başlatılır. Pdo’nun __construct yapılandırıcı (başlangıç) fonksiyonu veritabanı bağlantı işlemleri barındırdığından sınıfımızı  bağlantı bilgilerini girerek başlatıyoruz. Bu bilgiler ;

  • mysql:host = bağlanacağımız veritabanı tipi (mysql) ve bağlanacağımız sunucunun adresi (localhost)
  • dbname = bağlanacağımız veritabanının adı (bizim veritabanı adımız “pdo”)
  • charset = karakter setimiz (utf8)
  • veritabanı kullanıcı adımız ve şifremiz (root/root)

Veritabanımıza bağlanırken try/catch yapısı kullanmalıyız. Böyle bir zorunluluğumuz yok. Ama PDOException ile bağlantı hatalarını düzenli bir şekilde yakalayabilmek için bu gerekli. Eğer try/catch kullanmaz isek bağlantıda bir hata olduğunda karışık bir hata ekranı karşımıza gelir ve çirkin bir görüntü oluşur. Bu yüzden try/catch kullanılmalı. Parağraflar halinda açıklamanın yanı sıra kod içerisinde de bolca açıklama satırı yazdım ki anlaşılması daha kolay olsun. Şimdi veritabanımıza bağlanalım.

 

try {
    // server bilgilerini girerek database baglantimizi sagliyoruz.
    $db = new pdo("mysql:host=localhost;dbname=pdo;charset=utf8","root","root");
} catch (PDOException $e) {
    // PDOException baglanti hatalarini yakalayip $e değişkenine atıyoruz.
    // sonrasinda hatamiz var ise $e altindaki getMessage() fonksiyonu ile
    // hatamizi ekrana yazdiriyoruz.
    print $e->getMessage()

 

Eğer veritabanı bilgilerimizde bir hata var ise hata mesajımızı yazacaktır. Yok ise ekranımızın boş olması gerekmekte. Bağlantı kodlarımız başarı ile çalıştı.

Exec() kullanımı

Tek bir işlem yapılacak ve herhangi bir değer döndürülmeyecek ise kullanılır. Döndürdüğü tek değer yapılan sql sorgusu sonucu etkilenen satır sayısıdır. Etkilenen satır sayısı yok ise “0” değeri dönderir. Kategorisi “css” olan 3 tane verimizin olduğunu varsayarak delete sorgumuzu çalıştırıyoruz.

 

// exec() fonksiyonu ile delete sorgumuzu calistiriyoruz.
// delete sorgumuzu $deletedRows isimli degiskenimize esitliyoruz.
$deletedRows = $db->exec("DELETE FROM example where category = 'css' ");
 
// $deletedRows dan gelen değer tabloda işlem gören yani silinen satır sayısını 3'ü verecektir.
if($deletedRows)
    // Bu satirin ciktisi "Tablodan 3 adet satır silindi." olacaktir.
    print "Tablodan ". $deletedRows . " adet satır silindi.";

 

errorInfo() kullanımı

Yapılan sorgularda hata var ise hata mesajını geri döndermek için kullanılan fonksiyondur. Dönen hata mesajı dizi şeklinde olur. 0,1,2’inci dizi elemanlarının ilk ikisi hata kodunu barındırır. Sonuncu eleman yani 2. numaralı elemanda ise hata mesajı bulunur.

 

// bozuk bir sql sorgusu yazalim
// ve sql sorgumuzu $query degiskenine esitleyelim
$query = $db->exec("bozuk sql");
 
// yaptigimiz sql sorgusu hatali ise (tablo yok, soz dizimi hatasi vs..)
// hatamizi yazdirmamizi soyledik.
if(!$query){
 
    // Hatamizi $error degiskenine atiyoruz.
    $error = $db->errorInfo();
 
    // errorInfo() bir dizi dönderdiği için $error da bir dizidir.
    // print_r($error) ile dizideki tüm elemanları görebilirsiniz.
    // 0,1 elemanları hata kodu 2 elemanı hatayı metin olarak dönderir.
    print $error[2];
}

 

lastInsertId() kullanımı

Yapılan her hangi bir insert sql sorgusun hemen ardından yazılır. İşlem yapılan satırın idsini almak için kullanılan fonksiyondur. Bir insert sorgusu yaparak veritabanımıza veri ekleyelim ve sonra bu eklediğimiz satırın idsini alalım.

 

// example tablomuza bir adet insert sorgusu olusturarak veri girisi yapiyoruz.
$db->exec("INSERT INTO example (title,description,author,category) VALUES ('Makale Basligi','Makale icerigi','Emrah Ozgilik','html5')");
 
// print ile cikti almaya calistigimizda bize yukarida ekledigimiz satirin idsini verecektir.
// asagidaki komutun ciktisi ; " Biraz önce eklenen satırın idsi : 2 " tarzinda olacaktir.
print "Biraz önce eklenen satırın idsi : " .$db->lastInsertId();

 

prepare() ve execute() kullanımı

Sql sorgumuzu hazırlayıp kullanabileceğimiz fonksiyondur. Değer alabilir ve değer döndürebilir. Hazırlanan sql sorgusu execute() fonksiyonu ile calıştırılır. Aldığı değerler array() şeklinde gönderilir. İki şekilde değer alır. Birincisi “?” imi ile aldığı değerler ikincisi ise “:isim” şeklinde aldığı değerler. “:isim” şeklindeki atamalar daha anlaşılır olduğu için kullanılması mantıklıdır.

Yine yukarıdaki insert sorgu örneğimizi kullanarak tablomuza bir satır ekleyelim ve “?” imi ile nasıl değer alıyor bir görelim.

 

// insert sorgumuzu $query isminde bir degiskene esitleyelim.
$query = $db->prepare("INSERT INTO example (title,description,author,category) VALUES (?,?,?,?)");
 
// execute icinde array ile degerlerimizi insert sorgumuza yolladik ve kaydimizi ekledik.
$query->execute(array("Makale Basligi","Makale icerigi","Emrah Ozgilik","html5"));
 
// 2. bir kayit eklemek istedigimde sql sorgumu tekrar yazmama gerek yok hemen degerlerimi degistirip
// execute fonksiyonum ile baska bir icerik eklemesi yapabilirim ornegin ;
$query->execute(array("Makale Basligi 2","Makale icerigi 2","Salih Sonmez","css"));

 

Yukarıdaki kodlarımızı çalıştırdığımızda verimizin başarılı şekilde veritabanımıza eklendiğini göreceğiz. Burada dikkat edilmesi gereken nokta “?” imi ile aldığımız veriler insert sorgusunda, belirlediğimiz kolon isimleri ile gönderdiğimiz array değerlerinin sıralaması aynı olmak zorundadır.

Şimdi de yine veritabanımıza bir satır ekleyerek “:isim” şeklinde nasıl değer alıyor onu görelim.

 

// insert sorgumuzu $query isminde bir degiskene esitleyelim.
$query = $db->prepare("INSERT INTO example (title,description,author,category) VALUES (:baslik,:aciklama,:yazar,:kategori)");
 
// asagida da acikca goruldugu gibi insert sorgusunda ":isim" seklinde aldigimiz verileri
// array icinde anahtar=>deger mantigi seklinde kullanabiliyoruz.
$query->execute(array(
        'baslik'    => 'Makale Basligi 3',
        'yazar'     => 'Kemal Babaoglan',
        'kategori'  => 'php',
        'aciklama'  => 'Makale icerigi 3'
    ));

 

Yukarıda da açıkca görüldüğü gibi insert sorgusunda “:isim” şeklinde aldığımız verileri execute() fonksiyonumuz içindeki array içerisinde anahtar=>değer mantığı ile kullanabiliyoruz. “:isim” şeklinde gönderilen verilerin sıralamasının bir önemi yok. “aciklama” kısmını sıralam dışında yazdığım halde sorgumuzun sorunsuz şekilde sırası ile ekleme işlemi yapacağını göreceksiniz.

query() kullanımı

Sql sorgumuzu tek bir satırda çalıştırır ve bunu bir PDOStatement (sonuç kümesi) nesnesine dönüştürür. Defalarca ekleme yapılacak bir sistemde prepare() fonksiyonun kullanılması hız bakımdan mantıklıdır. query() fonksiyonun diğerlerinden farkı satır satır veri alabilmemizdir. Bir select sorgusu ve foreach döngüsü  ile listelem yapıp query() fonksiyonumuzun kullanımına bakalım.

 

// bir select sorgusu olusturalim ve bu sorgumuzu $query degiskenimize esitleyelim.
$query = $db->query("SELECT * FROM example");
 
// simdi bu sorgumuzu foreach ile listeleyelim,
// degerlerimiz dizi seklinde bize aktarilacaktir.
foreach ($query as $article) {
    // makalemizin basligini yazdirdik.
    print $article["title"]. "t";
    // makalemizin icerigini yazdirdik.
    print $article["description"]. "t";
    // makale yazarimizi yazdirdik.
    print $article["author"]. "t";
    // makalemizin kategorisini yazdirdik.
    print $article["category"]. "n";
}

 

Select sorgumuz ve döngümüz çalıştığında makalelerimizin sorunsuz şekilde listelendiğini görecegiz. Peki biz sadece bir satır veri çekmek istesek ? Tabi ki yapabiliriz where şartımız ve sorgumuzun sonuna ekleyeceğimiz “->fetch” ile bunu yapabiliriz. Hemen örneklendirelim ; query() ile sorgumuzu oluşturup sadece idsi 1 olan satırı listeleyelim.

 

// idsi 1 olan satirimizi $query degiskenimize esitledik. $query artik bir dizi.
$query = $db->query("SELECT * FROM example WHERE id=1")->fetch();
 
// simdi yazdiralim
// asagidaki gibi $query dizimizin icindeki idsi 1 olan makalemizin basligini basari ile getirebildik.
print $query["title"];

 

Kodlarımız çalıştığında idsi 1 olan verimizi başarı ile alıp yazdırabildiğimizi göreceksiniz. Burada tüm verileri görmek için print_r ile $query değişkenimizi yazdırabilirsiniz.

beginTransaction() ve rollBack() kullanımı

Bu özellik yaptığımız bazı sorguları geri alabilme özelliği kazandırmıştır. Rollback sözcüğüne online oyun oynayan (özellikle knight online tarzı) arkadaşlarım hakimdir. rollBack geriye dönüş, eskiye dönme anlamlarına gelmektedir. Bu özelliği kullanabilmemiz için öncelikle beginTransaction() ile rollBack yapabileceğimizin haberini vermemiz gerekir. beginTransaction() fonksiyonu ile rollBack() fonksiyonu arasında kalan sql işlemlerimiz geri alınabilir tabi kısıtlı olarak.

Kısıtlı kısmını açıklamak gerekirse CREATE TABLE ve DROP TABLE gibi yeni tablo oluşturma ve silme gibi işlemleri rollBack yapamayız. rollBack yapabileceğimiz işlemler genellikle insert, delete ve update sorgularımızdır. Hemen bir örnek ile açıklayalım.

 

//rollBack yapabilecegimizin bilgisini veriyoruz.
$db->beginTransaction();
 
// idsi 1 olan satirimizi sil dedik.
$db->query("DELETE FROM example WHERE id=1");
 
// idsi 2 olan satirimizin kategorisini teknoloji yap dedik.
$db->query("UPDATE FROM example SET category='teknoloji' where id=2");
 
// daha sonra rollBack() fonksiyonumuzu calistirarak bu islemlerden vazgectik.
$db->rollBack();

 

Kodlarımızı çalıştırdığımızda göreceğiz ki beginTransaction() fonksiyonu ile rollBack() fonksiyonu arasında yaptığımız 2 sorgu işleme alınmamış gibi eski halinde olacaktır.

setAttribute() kullanımı

Veritabanımız ile ilgili özellikleri tanımladığımız fonksiyondur. Bu fonksiyon ile veritabanından gelen verilerin özelliklerini değiştirebiliriz. Örneğin biz veritabanından select ile sorguladığımız verilerin dizi şeklinde değil de obje şeklinde gelmesini istiyoruz. Bu isteğimizi bu fonksiyon ile gerçekleştirmek mümkün.

Veritabanı bağlantısını yeniden kuralım ve özelliklerimizi belirterek bir listeleme yapalım. Biz çektiğimiz her verinin dizi değil obje olmasını istiyoruz. O halde kodlarımızı yazalım.

 

try {
    // server bilgilerini girerek database baglantimizi sagliyoruz.
    $db = new pdo("mysql:host=localhost;dbname=pdo;charset=utf8","root","root");
 
    // setAttribute() fonksiyonu ile verilerimizin obje olarak gelmesini istiyoruz.
    $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
 
} catch (PDOException $e) {
    // PDOException baglanti hatalarini yakalayip $e değişkenine atıyoruz.
    // sonrasinda hatamiz var ise $e altindaki getMessage() fonksiyonu ile
    // hatamizi ekrana yazdiriyoruz.
    print $e->getMessage();
}
 
// baglantimizi yaptik ve obje olarak gelmesini istedik.
// bir select sorgusu olusturalim ve bu sorgumuzu $query degiskenimize esitleyelim.
$query = $db->query("SELECT * FROM example");
 
// simdi bu sorgumuzu foreach ile listeleyelim,
// dongumuz calistiginda sorunsuz olarak makaleleri listeletecektir.
foreach ($query as $article) {
    // makalemizin basligini obje olarak yazdirdik.
    print $article->title. "t";
    // makalemizin icerigini obje olarak yazdirdik.
    print $article->description. "t";
    // makale yazarimizi obje olarak yazdirdik.
    print $article->author. "t";
    // makalemizin kategorisini obje olarak yazdirdik.
    print $article->category. "n";
}

 

Yukarıdaki kodlarımızı çalıştırdığımızda listememiz sorunsuz olarak çalışacaktır. Dikkat ettiyseniz verilerimizi bu sefer dizi değil obje şeklinde aldık. Değerlerimiz setAttribute() fonksiyonu sayesinde bize obje şeklinde gelecektir. Dizi şeklinde kullanmaya çalıştığımızda hata verecektir.

setAttribute() fonksiyonu ile hangi özellikler kullanılabilir ve veritabanı ile ilgili hangi özellikler değiştirilerek size uygun hale getirilebilir aşağıdaki linke tıklayarak detaylı şekilde inceleyebilirsiniz.

http://www.php.net/manual/tr/pdo.setattribute.php

Sizlere pdo ile ilgili bilgilerimi aktarmaya çalıştım. Eksik veya hatalı olduğuna inandığınız konuları yorum olarak paylaşmaktan çekinmeyin tabi sorularınızı da. Bir sonraki makalede görüşmek üzere.

Kaynaklar:

http://www.php.net/manual/en/book.pdo.php
http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
http://stackoverflow.com/questions/1402017/php-pdo-vs-normal-mysql-connect

  • Cemal Baş

    Yazı için Teşekkürler.Minik minik güzel oldu.

  • murat

    Teşekkürler. gece vakti işim gördü