Basit PDO Sınıfı ile Veritabanı İşlemlerini Kolaylaştırmak

Neden böyle bir şeye ihtiyaç var diye düşünebilirsiniz belki. Ama acemi ve yeni öğrenen arkadaşlar için böyle bir şey paylaşmak gerekiyor. PDO çok fazla kafa karıştıracak bir şey değil aslında ama öğrenme sürecinde sıkıntı çıkarabiliyor. Özellikle de mysql_connect() fonksiyonundan geçişlerde sancılı olabiliyor. Aşağıda yazdığım sınıf oldukça basit bir kullanıma sahip.

<?php
/**
 * Basit bir veritabanı sınıfı
 * Sorguları çalıştırır
 * PDO ile fetch, fetchAll, fetchColumn ... gibi metodlar
 * zincirleme çalıştırılabilir ve kullanılabilir.
 * 
 * @link http://demirphp.com
 * @author Yılmaz Demir <demiriy@gmail.com>
 */
class BasitPDO
{
   /**
    * PDO sınıfını tutar
    * @var void
    */
   public static $pdo;
   /**
    * PDO bağlantısını kurar
    * @param void $pdo
    */
   public function __construct(\PDO $pdo)
   {
      self::$pdo = $pdo;
   }
   /**
    * Sorgu çalıştırır
    * @param string $query
    * @return void
    */
   public static function query($query)
   {
      if (!self::$pdo instanceof \PDO) {
         throw new \Exception('PDO bağlantısı yapılmamış');
      }
      $stmt = self::$pdo->prepare($query);
      $args = array_slice(func_get_args(), 1);
      if (isset($args[0]) && is_array($args[0])) {
         $stmt->execute($args[0]);
      } else {
         $stmt->execute($args);
      }
      return $stmt;
   }
}

Yukarıdaki dosyayı kaydedelim. Öncelikle veritabanı ayarını yapalım.

Connection.php


$pdo = new \PDO('mysql:host=localhost;dbname=database;charset=utf8', 'kullaniciadi', 'sifre');
$basit_pdo = new BasitPDO($pdo);

Ne yapmak istiyorsunuz? Veritabanından bir tek gönderi mi birden fazla gönderi mi çekmek istiyorsunuz? Bütün haberleri çekelim:

Haberler.php

require 'Connection.php';
$haberler = BasitPDO::query('SELECT * FROM haberler WHERE onaylanmis=?', 'evet')->fetchAll();
 
foreach ($haberler as $key => $haber) {
   echo $haber['baslik'] . '
';
}

Haber.php?id=5

require 'Connection.php';
$id = $_GET['id'];
$haber = BasitPDO::query('SELECT * FROM haberler WHERE id=?', $id)->fetch();
echo $haber['baslik'];

HaberSayisi.php

require 'Connection.php';
$haberSayisi = BasitPDO::query('SELECT * FROM haberler')->rowCount();
// ya da
$haberSayisi = BasitPDO::query('SELECT COUNT(id) FROM haberler')->fetchColumn();
echo $haberSayisi;

Ekleme/Düzenleme/Silme

require 'Connection.php';
$ekle = BasitPDO::query('INSERT INTO haberler (baslik, icerik) VALUES (:baslik, :icerik)', [':baslik' => 'Başlık', ':icerik' => 'İçerik']);
$duzenle BasitPDO::query('UPDATE haberler SET baslik=:baslik WHERE id=:id', [':baslik' => 'Yeni Başlık', ':id' => $_GET['id']]);
$sil = BasitPDO::query('DELETE FROM haberler WHERE id=?', $_GET['id']);

Türkçe Programlama Dersleri

İnternette özellikle türkçe programlama kaynağı bulmak özellikle ingilizceye göre oldukça zor. Bunun sebebi bir kenarda dursun elimizde neler var onlara bir bakalım. Aşağıdaki -şimdilik- ufak olan liste nitelikli olduğunu düşündüğüm programlama derslerini barındırıyor. Umarım iş görür.

HTML Dersleri

Türkçe kaynak olarak rastladığım diğerlerine nazaran daha nitelikli HTML dersleri bu sayfada bulunuyor. Aslında yeni özelliklerden ve güncel kullanımdan bahsedilmemiş ama yine de başlangıç açısından temiz bilgiler barındırıyor.

Bağlantı

CSS Dersleri

Oldukça eski ve nitelikli olan Fatih Hayrioğlu’nun zamanla genişlettiği CSS arşivi. Epey bir emek harcanmış olan bu kaynak oldukça yararlı ve iyi bir rehber.

Bağlantı

Modern JavaScript

Yine rastladığım en nitelikli JavaScript dersleri. Modern vurgusunu yapmamın sebebi güncel tekniklerle, kullanımlarla JavaScript’i öğretiyor olması.

Bağlantı

Python Programlama Dili Dersleri

Bu sayfa için ne söylesek azdır. Python için böyle bir türkçe kaynak büyük bir emek ve sorumluluk gerektiriyor. Python öğrenmek, bilgi tazelemek ve referans olarak kullanmak için -hala- epeyce kullandığım bir programlama ders dizisi.

Bağlantı

Node.JS Dersleri

Node’u es geçmek olmaz. Daha önceden faydalandığım gayet iyi bir dille anlatılmış olan bu kaynak eminim node’a meraklı dostlar için faydalı olacaktır.

Bağlantı

PHP’de Compact Fonksiyonu

Laravel ile geliştirilmiş bir uygulamada rastladım bu fonksiyona. Şablon dosyası yorumlarken kullanılmış. Normal şartlarde şablon dosyası yorumlarken şunu kullanıyordum:

$post = Post::get($id);
$user = User::get();

render('home.template', [
	'post' => $post,
	'user' => $user,
	'message' => 'Gönderi görüntülendi!'
]);

ama şu kullanım da yukarıdaki kadar kullanışlı ve düzenli olabilir:

$post = Post::get($id);
$user = User::get();
$message = 'Gönderi görüntülendi!';

render('home.template', compact('post', 'user', 'message'));

Eğer değişkenlerle değerlerinden oluşan bir dizi oluşturmak istiyorsak bu fonksiyonu kullanabiliriz. Farklı alanlarda da farklı şekillerde kullanılabilir. Detaylar için:

http://php.net/manual/tr/function.compact.php

PHP ve Sabit Tanımlamalar

PHP’de değişkenlerden başka kullanabileceğimiz bir de sabitler vardır. Sabitler, tanımlandıktan sonra değiştirilemezler. Birkaç örnek verelim.

define('SABIT', 'foo');
var_dump(SABIT);

Sabitler, programlama dillerinde genellikle büyük harflerle tanımlanırlar. Bu genel bir gelenektir, daha farklı biçimlerde de kullanılabilir elbette. Sabitleri bir kere tanımladıktan sonra başka bir yerde değiştiremiyorsunuz ve yeniden tanımlayamıyorsunuz. Yani şöyle:

define('TEST', 'foo');
define('TEST', 'bar');
// Hata: Notice: Constant test already defined in /var/www/constant.php on line 2

Sabitlerin Kontrolü

Bir sabit tanımlı olup olmadığını kontrol etmemize yarayan fonksiyonlar da var. defined fonksiyonu sayesinde, sabitin tanımlı olup olmadığını öğrenebiliyoruz. Kullanalım:

define('TEST', 'foo');

defined('TEST') or define('TEST', 'foo'); // Tanımlamaz, çünkü zaten tanımlı
defined('DENEME') or define('DENEME', 'bar'); // Tanımlar, çünkü tanımlı değil

var_dump(defined('DIGER')); // bool(false)

Sabitlere Tanımlayabileceğimiz Türler

Sabitlere, değişkenleri tanımlayabiliriz fakat daha sonrasında değişkene yeni bir değer verdiğimizde sabitin değeri değişmez. Yani;

$foo = 'bar';
define('TEST', $foo);
$foo = 'baz';
var_dump(TEST); // string(3) "bar"

Sabitlere değer döndüren fonksiyon tanımladığımı test ettim (sürüm 5.4) fakat anonim fonksiyonlar sabitlere tanımlanmıyor.

function foo($bar) {
    return (string) $bar;
}

define('TEST', foo('test'));
var_dump(TEST); // string(4) "test"

// Hatalı kullanım:
define('TEST', function(){
    return 'foo';
});

Sabitlerde şimdilik dizi (array) tanımlaması yapamıyoruz ama PHP 7’de bunu kullanabileceğiz. PHP 7 ile çalıştırdığımızı varsayalım:

define('FOO', ['bar' => 'Bar...', 'baz' => 'Baz...']);
var_dump(FOO['bar']); // string(6) "Bar..."

Sınıflardaki Sabitler

Sınıf içerisinde kullandığımız sabitlerde, normalde kullandıklarımızla benzerlikler taşır. Bu sabitlerde daha sonrasında üzerine yazılamaz ve değiştirilemez. Sadece okumak içindir. Örneğimizi inceleyelim:

class Test
{
    const FOO = 'Sabit';

    public function bar()
    {
        return self::FOO;
    }
}

$test = new Test;
var_dump($test->bar()); // string(5) "Sabit"
var_dump(Test::FOO); // string(5) "Sabit"

Bu yapı yalnızca PHP 5.3 ve sonrasında kullanılabilir.

Sabitlerin Kullanım Yerleri

Sabitler daha çok ayar/konfigürasyon (config) dosyalarında kullanılırlar. Örneğin bir veritabanı bağlantı ayarları veya dizin belirleme ayarları gibi. Örnekleyelim:


defined('DB_DSN') or define('DB_DSN', 'mysql:host=localhost;dbname=veritabani');
defined('DB_USR') or define('DB_USR, 'root');
defined('DB_PWD') or define('DB_PWD', null);

$pdo = new PDO(DB_DSN, DB_USR, DB_PWD);

Bu şekilde veritabanı bağlantısını daha kontrollü biçimde yapabiliyoruz. İstersek sınıflar içinden de erişebiliyoruz. Başka bir senaryoda ise, dizin yapılarını kontrolümüz altında tutmak isteyelim.

defined('KOK_DIZIN') or define('KOK_DIZIN', __DIR__);
defined('UYG_DIZINI') or define('UYG_DIZINI', KOK_DIZIN.'/app');
defined('SINIFLAR') or define('SINIFLAR', KOK_DIZIN.'/classes');
defined('GORUNUMLER') or define('GORUNUMLER', KOK_DIZIN.'/views');

Herhangi bir yerde betik içine sınıf dahil etmek istediğimizde, yeniden dizin yolunu yazmak yerine sabit sayesinde tek sefer çağırabiliriz: require SINIFLAR.'/database.class.php'; gibi. Bu şekilde bir kullanım yapmak, daha sonrasında sınıflarının dizin yolunu değiştirdiğimizde de bizi zorlamayacaktır.

Sabitlerin Kullanımı ve Performans

Hiç istatistik ve ölçüm bulamadım fakat değişkenlerle global sabitleri karşılaştırdığımız vakit, sabitler değişkenlere nazaran daha yavaşmış. Yalnız bunu sınıflar için söyleyemem.

Kolay gelsin.

jQuery ile Dinamik Olarak Oluşturulan Elemente Erişmek

jQuery ile DOM’da bulunan elementlere $('.element') şeklinde kullanarak erişebiliyoruz. Fakat dinamik olarak oluşturulan elementlere erişmek için farklı bir durum söz konusu oluyor. Bunun için şu kullanım yeterli geliyor:

$('body').on('click', '.element', function(){
    console.log($(this).html())
})

Kolay gelsin.

PHP için Kullanışlı Veritabanı Sınıfı

Yazdığım uygulamalarda en çok ihtiyaç duyduğum ve kullandığım şey veritabanı işlemleri yapmak olduğu için bir sınıf yazmaya giriştim. Daha öncesinde ufak tefek girişimlerim olmuştu ve tecrübe edinmiştim. Ama işi en basite indirgemeye ve kullanılabilirliğini arttırabilmeye çalıştım. Şimdi paylaşacağım veritabanı sınıfı benim işimi oldukça kolaylaştırıyor.

DemirPHP Veritabanı Sınıfı

Bu veritabanı sınıfı sayesinde yazdığımız SQL ifadelerini, zincirleme metodlarla oluşturuyoruz. İstersek sorguyu elde ediyor, istersek PDO veri döndürüyoruz. Paketin GitHub kaynağına buradan ulaşabilirsiniz.

Basit bir kullanım örneği:


$db = new Database(new PDO('mysql:host=localhost;dbname=cms', 'root', 'root'));
$db->select()
 ->from('tablo')
 ->join('digerTablo', 'alan1', '=', 'alan2')
 ->where('taslak', '=', 0)
 ->andWhere('id', '=', ':id')
 ->bindParam([':id' => 15])
 ->fetch();

Daha fazla detay, bilgi ve dökümantasyona buradan ulaşabilirsiniz. Soru işaretleri hakkında bana ulaşabilirseniz yardımcı olabilirim. İyi çalışmalar.

PHP’de explode Fonksiyonu

PHP’de en çok karşıma çıkan fonksiyonlardan birisi olan explode() fonksiyonu hakkında bir kaç kelam etmek gerekiyor. Bu fonksiyonun kullanım amacı, belirli bir karakteri kullanarak bu karakteri içeren dizgeyi parçalara ayırıp dizge haline getirmek.

(PHP 4, PHP 5, PHP 7)
explode — Bir dizgeyi bir ayraca göre bölüp bir dizi haline getirir

Kullanımı

explode(dizge $ayraç, dizge $dizge)

Örneklemelerle kullanımını anlayalım. Örneğin bir formdan etiketler alanı gelmiş olsun. Bu etiketleri virgül yardımıyla parçalara ayırıp dize haline getirelim.

// Örnek POST alan içeriği: php dersleri, fonksiyonlar, nasıl yapılır, içerik
$etiketler = $_POST['etiketler'];

// , karakteriyle dizgeyi bölüyoruz
$etiketlerDizesi = explode(',', $etiketler);
// Her dizge öğesine trim() fonksiyonu uyguluyoruz
// bu fonksiyon, sağdaki ve soldaki boşlukları temizler
$etiketlerDizesi = array_map('trim', $etiketlerDizesi);

// Dizge içeriğini ekrana yazdıralım:
print_r($etiketlerDizesi);

/* 
Sonuç olarak dönen değer şu olacaktır:
Array
(
    [0] => php dersleri
    [1] =>  fonksiyonlar
    [2] =>  nasıl yapılır
    [3] =>  içerik
)
*/

explode Fonksiyonunun Kullanım Alanları

Nerelerde kullanıyoruz bu fonksiyonu hemen söyleyelim. Örneğin, URL barındaki adresi anlamak için kullanıyoruz ya da belli karakterlerle listelenmiş bir yazıyı parçalara bölmek için kullanıyoruz. Ben, örnek olarak basit bir yöntemi anlatacağım. Bu anlatacağım yöntemde URL satırındaki adresi alıp, daha anlaşılabilir hale getireceğiz.

Bahsedeceğim örnekte, modül ve bölüm sistemi olacak. Modüller, anasayfa, haber, galeri gibi kök yöneticiler, bölümler ise alt yöneticileri olacak. Yani örneğin haber modülü için haberGoster, haberEkle gibi ek bölümler olacak.


// Eğer rota varsa rotadır, yoksa kök halindedir
$rota = isset($_GET['rota']) ? $_GET['rota'] : '/';
// Burada explode ile / karakterini kullanara dizgeyi böldük
$rotalar = explode('/', $rota);
// Eğer dize içindeki ilk rota boşsa diziden çıkaralım
// array_shift fonksiyonu dizideki ilk öğeyi çıkarır
if (empty($rotalar[0])) array_shift($rotalar);

// Burada modül eğer varsa ve boş değilse modüldir, değilse geçerli olarak anasayfa'dır
$modul = isset($rotalar[0]) && !empty($rotalar[0]) ? $rotalar[0] : 'anasayfa';
// Burada aynı şekilde modül gibi varsa vardır yoksa giriş'dir
$bolum = isset($rotalar[1]) && !empty($rotalar[1]) ? $rotalar[1] : 'giris';

// Yukarıdaki işlemin diğer bir kullanımı şöyledir:
$modul = null;
if (isset($rotalar[0]) && !empty($rotalar[0])) {
	$modul = $rotalar[0];
} else {
	$modul = 'anasayfa';
}

Yukarıdaki örneği olabildiğince basite indirgediğim için işimizi tam anlamıyla ve sürekli olarak görmeyebilir ama anlamak açısından iyi gelebilir. MVC çatıları sayfanın ne olduğunu explode fonksiyonu ile anlar ve işlemi buna göre yönlendirirler.

PHP’de array_sum Fonksiyonunu Alt Dizelerde Kullanmak

PHP’de array_sum fonksiyonu kullanmam gerekti. Ama normal kök dizide değilde, alt dizideki değerleri toplamam gerekiyordu.

array_sum fonksiyonu ne işe yarar?
Bu fonksiyon bir dize içerisindeki değerlerin toplamını döndürür.

Örnek senaryo, her müşteriye ait tutar/bakiye değerlerini listeleyip hepsinin toplamını en son göstermek.

['Müşteri' => ['Tutar' => 150.00, 'Bakiye' => 360.00]]

<?php
$amount = [];
$balance = [];

foreach ($result as $result) {
    $amount[] = $result['amount'];
    $balance[] = $result['balance'];
    # Listeleme yapacak kod bloğu
}

$totalAmount = array_sum($amount);
$totalBalance = array_sum($balance);

Şeklinde kullanılabilir, kolay gelsin.

PDO’nun En Kolay Hali

Genelde, mysql fonksiyonundan PDO’ya geçişte biraz zorlanılır. Bu yazıda, PHP ile veri çekerken ve eklerken en çok kullandığımız yöntemlerin PDO karşılığını yazacağım.

PDO ile MySQL Veritabanına Bağlanmak

$pdo = new PDO('mysql:host=localhost;dbname=veritabani;charset=utf8', 'kullaniciAdi', 'sifre');

Bu satır, mysql_connect() satırıyla aynı işi hatta daha fazlasını yapar. Hem belirttiğimiz veritabanına bağlanır hem de karakter setini belirler. Böylece türkçe karakter sıkıntısı yaşamayız.

PDO ile Veri Listelemek

$sorgu = $pdo->query('SELECT * FROM tablo');
$ogeler = $sorgu->fetchAll();

foreach ($ogeler as $oge) {
	echo $oge['baslik'] . '<br>';
}

Burada, query() ile sorguyu yazdık ve fetchAll() metodu ile verileri birden fazla yani hepsini çekecek biçimde aldık. Daha sonra foreach() ile sayfaya yazdırdık.

PDO ile Veri Çekmek

PHP’de PDO ile veri çekerken veya listelerken iki yöntemimiz var. Bunlardan birincisi query() metodu diğeriyse önce prepare() yani hazırlama metodu sonrasında execute() yani çalıştır metodu. İlk metodun örneğini veri listelemek bölümünde yaptık, şimdi tekil veri çekerken, ikinci yöntemi yani prepare() metodunu kullanacağız.

$id = $_GET['id'];
$sorgu = $pdo->prepare('SELECT * FROM table WHERE id=?');
$calistir = $sorgu->execute(array($id));
$oge = $calistir->fetch();
echo $oge['baslik'];

Neden ilkinden farkı bir yöntem kullandık?

Çünkü, veritabanı ile bilgi alışverişi yaparken güvenliğe önem vermemiz gerekiyor. Son örnekte, kullanıcıdan gelen bilgiye göre ($id = $_GET['id'] satırına dikkat) bilgi çekiyoruz. Önceleri, yani PDO’dan evvel değişkeni sorgu içine ekleyip de veriler çekiliyordu. Ama SQL Injection dediğimiz açıkları da beraberinde getiriyordu. Biz, bu örnekte önce sorguyu hazırladık, şart yerine ? işareti koyduk ve soru işareti gelen yere $sorgu->execute(array($id)); kısmında göründüğü üzere gelecek verinin $id değişkeni olduğunu söyledik.

Bunun gibi ve bundan farklı birçok örnek mevcut ve kullanıma açık. Mesele mantığı kavramak. Ama en basit hali bu hali. Kolay gelsin. Bir dahaki yazıda, PDO ile veri ekleme, silme ve güncelleme konularına değineceğim.

Esen kalın.

Deprecated: mysql_connect() Hatası Üzerine

PHP’ye yeni başlayanlar, öğrenmek için çaba harcayanlar muhtemelen bu hatayla karşılaşacaklardır. Kafa karıştırmadan hatanın çözümünü söyleyelim…

Hata tam olarak şöyle:

 Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in /dosya/yolu/bilmemne.php on line 1

Bu hatayı alıyorsanız, çok eski ve artık desteklenmeyen bir yöntem kullanıyorsunuz demektir. Hatanın türkçesi:

Kullanımı önerilmiyor: mysql_connect(): msyql uzantısının kullanımı önerilmiyor ve yakın gelecekte bu fonksiyon kaldırılacak. mysqli veya PDO kullanın

Peki neden artık bu fonksiyon desteklenmiyor? Çünkü, bu fonksiyon kullanışlı ve yönetilebilir bir fonksiyon değil. Bunun yerine mysqli ve PDO kullanmak gerekiyor.

mysqli nedir?

Bu da tıpkı mysql fonksiyonları gibi bir fonksiyondur ve PHP’nin mysql fonksiyonlarına alternatifidir, eğer illa ki fonksiyonlarla veri çekeceğim diyorsanız bunu kullanın ama bana kalırsa PDO kullanmanızı öneririm.

PDO nedir?

PDO, PHP’nin bir uzantısıdır. PHP Data Objeleri diye anlayabiliriz. Neden öneriyorum, çünkü bu yöntem daha bir nesne yönelimli ve öğrenince daha da kolayınıza gelecektir. Yakın zamanda PDO hakkında bir şeyler yazmak istiyorum, bakalım.

Sonuç olarak, artık bu fonksiyonu kullanmamanızı öneriyorum.