24 Sep

“call-time pass-by-reference” is deprecated çözümü

Bu da PHP4 den PHP5 e geçerken karşılaşılması muhtemel bir problemdir . PHP5 de nesneyi parametre olarak göndermek yeterli, PHP5 de nesne her zaman referans olarak gönderildiği için PHP4 deki gibi & işaretini kullanmanıza gerek yok.

function ipucu(&$a){
echo $a->test();
}

yukarıdaki kullanım PHP5 de “call-time pass-by-reference” is deprecated görmenize sebep olur. Doğru kullanımı aşağıdaki gibidir :

function ipucu($a){
echo $a->test();
}

24 Sep

“headers already sent” problemi çözümü

Çok karşılaşılan, artık birçoğumuzun kanıksadığı bir olgu. Çözümü :

Yol 1:
php.ini de
output_buffering=off
anahtarını bulup
output_buffering=on
olarka değiştirip kaydedin ve sunucunuzu yeniden başlatın.

Yol 2:
kodlarınızın başına (daha ekrana herhangi bir çıktı, boşuk dahil; vermeden) ob_start();

yazmanız sorununuzu çözecektir

24 Sep

MySQL de transaction kullanımı

Bir önceki yazıda bulunan örnek ile devam edeceğim için, ilk önce bu örnekteki kodları edinip çalıştırmanız gerekli.

Transction, kelime anlamı ile işlem demektir. Fakat bu kelime anlamının haricinde, veritabanına doğru gerçekleştirilen işlemlerin, veritabanına kalıcı olarak işlenip işlenmemesini yöneten muazzam bir sistemdir. Ve kullandığınızda göreceksiniz ki çok hayat kurtaran bir sistemdir . MySQL 4.0 ve yukarısı InnoDB ve BDB saklama motorları transaction desteklemektedir.

Örneğimizde bir kullanıcı tablomuz var ve bir de gönderi tablomuz. Şöyle bir senaryo çizelim:
Bir kullanıcımızı silmek istiyoruz ve haliyle bu kullanıcının girdiği bütün gönderileri de silmek istiyoruz. Bunu basit bir sorgu ile kolayca gerçekleştirebiliriz:

baglan();
kullaniciSil($kullaniciId);
baglantiyiKapat();

Durum kabaca bundan ibaret. Ama ya işler ters gittiğinde. Kullanıcıyı sildik, ama bir terslik oldu, tam kullanıcı gönderileri silinirken hata oluştu ve gönderileri silemedik. O zaman ne yapacağız ? Gönderi tablosunda kullanıcısı olmayan gönderileri bulup silmek için bir işlem daha yaptırabiliriz. Ama bu ne performans açısından kabul edilebilir, ne de uygulamanın sağlamlığı ve kararlılığı açısından. İşte burada devreye transaction giriyor , tabi bu yapıyı kullanmanın en iyi yolunun PDO dan geçtiğini söylemek gerekir. Dönelim örneğimize:

try
{
   $veritabani = new PDO ( 'mysql:dbname=testdb;host=127.0.0.1', $kullanici, $sifre );
   $veritabani->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
   $veritabani->beginTransaction ();
   try
   {
      if ($veritabani->exec ( $sorgu1 ) == 0)
         throw new Exception ( 'birinci
sorgu çalışmadı'
);
      echo 'sorgu 1 çalıştı
<br />
'
;
      if ($veritabani->exec ( $sorgu2 ) == 0)
         throw new Exception ( 'ikinci
sorgu çalışmadı'
);
      echo 'sorgu 2 çalıştı';
      $veritabani->commit ();
   } catch ( Exception $istisna )
   {
      echo $istisna->getMessage ();
      $veritabani->rollBack ();
   }
} catch ( Exception $baglantiIstistisnasi )
{
   echo 'bağlantı sağlanamadı sebep :
<br />
<b>'
. $baglantiIstistisnasi->getMessage () . '</b>
'
;
}

Normal şartlar altında, aksini belirmedikçe PDO bütün sorgularınızı otomatikman veritabanına iletir. beginTransaction () metodu ile PDO ya işlemlerin sonuçlandırılması için bizim onayımızı almasını söylüyoruz. Daha sonra try bloğu sağlıklı çalışır ise commit() metodu ile PDO ya işlemlerimizin istediğimiz gibi gittiğini ve işlemleri sonuçlandırmasını söylüyoruz. Eğer catch bloğuna düşer ise, ters giden birşeyler olduğunu bildiğimiz için rollBack() metodu ile yaptığımız bütün işlemlerin geri alınmasını söylüyoruz.
Bunu en iyi şöyle test edebilirsiniz. Örnekteki veritabanı ve tabloları oluşturun. User tablosuna veri girin ve user_posts tablosuna hiçbirşey girmeyin. $sorgu1 deki yere kullanıcının id sini doğru girin ve $sorgu2 ye dokunmadan örneği çalıştırın, bakın bakalım ne olmuş.
Şimdi normal şartlar altında,kullanıcı olduğu için kullanıcının silinmesi gerekirdi, kullanıcı gönderilerinin silinmesi için verdiğimiz kullanıcı id si yanlış olduğu için silinecek herhangi birşey olmayacaktı. Kullanıcı uçmuş gitmiş ama kullanıcı gönderileri öyle kalacak idi. Ama kalmayacak, sorgu çalıştıktan sonra gidip tabloya baktığınızda şaşırmayın, bir hata yapmadınız. Kullanıcı orda duruyor ,silinmedi.
Çünkü try bloğumuz sonuna kadar çalışmadı, kullanıcı gönderisini silemediği için istisna fırlattı ve bu yüzden catch blokuna düştü, burda da işlem ters gittiği için yapılan işlemler geri alındı. İşte hayat kurtaran bu güzell işlevi kullanmak bu kadar kolay.

Güzel günler dileği ile, hoşça kalın.

23 Sep

PHP de try catch Kullanımı

<?php
// bunu belirttik, çünkü tarayıcıda türkçe karakter problemi yaşamak istemiyoruz
header ( 'Content-type:text/html; charset=UTF8' );
/**
 * örneklerimizde kullanacağımız iki tablo
 * bunları siz kendi sunucunuzda çalıştırıp
 * örnekleri uygulamak için kullanabilirsiniz
 */


$_veritabani = 'create database testdb';

$kullaniciTablosu = 'CREATE TABLE `testdb`.`user` (
`id` INTEGER  NOT NULL AUTO_INCREMENT,
`name` VARCHAR(25)  NOT NULL,
`password` VARCHAR(32)  NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE = InnoDB;'
;

$gonderiTablosu = 'CREATE TABLE `testdb`.`user_posts` (
`id` INTEGER  NOT NULL AUTO_INCREMENT,
`user_id` INTEGER  NOT NULL,
`title` VARCHAR(255)  NOT NULL,
`content` TEXT  NOT NULL,
PRIMARY KEY (`id`)
)
ENGINE = InnoDB;'
;

$kullanici = 'kull';
$sifre = 'sifr';
$sorgu1 = 'delete from user where id=2';
$sorgu2 = 'delete from user_posts where user_id=2';
/**
 *
 *try catch , daha önce de kısaca değindiğim gibi bir hata yönetim mekanizmasıdır.
 *Uygulamnımızın kararlılığını arttırmak için hatayı yakalamak ve onu işlemek de önemlidir.
 *Tabi hatayı yakalamak ve işlemek sadece try catch ile olabilen birşey değil,
 * ama neden kullanmalı ona değinmeye çalışacağım.
 *
 * Normal kullanım
 */


$baglanti = mysql_connect ( 'localhost', $kullanici, $sifre );
if ($baglanti)
{
   if (! mysql_select_db ( 'testdb', $baglanti ))
      die ( 'Veritabanı seçemedi' );
} else
{
   die ( 'veritabanına bağlanamadı' );
}
/*
* Yeri gelmişken yazalım. mysql_unbuffered_query fonksiyonu, çalıştıracağınız sorgudan geriye
* veri döndürmeyecekseniz , işinize yarayabilecek bir fonksiyondur. Bu fonksiyon geriye
* bir sonuç kümesi döndürmez , onun yerine sorgunun sağlıklı çalışıp çalışmadığını
* belirten bir boolean değer döndürür.Böylece değer döndürmeyen sorgularınız daha hızlı çalışır.
*/

if (mysql_unbuffered_query ( $sorgu1, $baglanti ))
{
   if (mysql_unbuffered_query ( $sorgu2, $baglanti ))
   {
      echo 'Sorgular başarı ile çalıştırıldı';
   } else
   {
      echo 'sorgu 2 çalışmadı';
   }
} else
{
   echo 'sorgu 1 çalışmadı';
}

mysql_close ( $baglanti );

/**
 * Buraya kadar heşey normal gibi görünüyor. Normal olarak kabul de edebiliriz, kod karmaşasını saymaz isek.
 * Peki gelin bir de böyle deniyelim :
 */


try
{
   $veritabani = new PDO ( 'mysql:dbname=testdb;host=127.0.0.1', $kullanici, $sifre );
   $veritabani->setAttribute ( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
   $veritabani->beginTransaction ();
   try
   {
      if ($veritabani->exec ( $sorgu1 ) == 0)
         
         throw new Exception ( 'birinci sorgu çalışmadı' );
      echo 'sorgu 1 çalıştı <br />;';
      if ($veritabani->exec ( $sorgu2 ) == 0)
         
         throw new Exception ( 'ikinci sorgu çalışmadı' );
      echo 'sorgu 2 çalıştı';
      $veritabani->commit ();
   } catch ( Exception $istisna )
   {
      echo $istisna->getMessage ();
      $veritabani->rollBack ();
   }
} catch ( Exception $baglantiIstistisnasi )
{
   echo 'bağlantı sağlanamadı sebep : <br /><b>' . $baglantiIstistisnasi->getMessage () . '</b>';
}

/**
* Şimdi kod daha sade değil mi ? Gerçi bakıma ihtiyacı olsa da, bir önceki örneğimizden daha anlaşılır ve daha işlevsel.
* Şimdi gelelim işleyişe. Kod try bloğuna girer ve bir istisna (Exceptipon) fırlatıladılmadıkça o blok çalışmasına devam eder.
* Eğer başarılı olmuşsa kendisini takip eden catch bloğunu ( catch() {} ) es geçerek bir alt satıra geçer.
* Ama eğer try bloğu içerisinde bir Exception fırlatılır ise o zaman kod, Exception fırlatılan satırdan sonra (örneğin ilk sorgumuz
* çalışmadığında biz bir istisna fırlatıyoruz, böylece try bloku içerisindeki o satırdan sonraki kodlar çalıştırılmaz)
* catch bloğuna geçer.
*
* Bunu şöyle deneyebilirsiniz, bu örneği alıp kaydedin ve veritabanını oluşturun. Sonra da hiçbir kayıt girmeden örneği çalıştırın.
* Bu durumda size "birinci sorgu çalışmadı" diye bir mesaj verecek. Böylce yukarıda değindiğimiz gibi, try blokundaki kod exception
* fırlatılan satıra kadar çalışır , exception fırlatılırsa exception dan sonraki satır çalışmaz ve catch bloğuna geçer (böylece biz
* birinci sorgu çalıştı mesajını görmeyiz) ve bu blok çalışır.
*
* try catch işleminin sağlıklı yürüyebilmesi için, Exception fırlatan bir mekanizmanın olması gerekir. PHP 5. versiyonundan sonra
* nesne yönemli programlamaya  ağırlık verildiğinden, eski nesnelerin çoğu ile kullanmak mümkün değildir.
* Kimi yeni nesneler ve sizin kendi oluşturacağınız nesneler ile try catch mekanizmasını kullanabilirsiniz.
*
* Bu bölümde son olarak finally e değinmek istiyorum. Diğer dillerde (Java , C# gibi) try catch blokunun son halkası olan finally
* mevcuttur, bu blok ister try bloku çalışsın isterse catch bloku çalışsın buna bakılmaksızın en son ve her halukarda çalıştırılan
* bir bloktur. Ama bu işlev ne yazıkki php de mevcut değil henüz. Bu yüzden kısaca değinip geçiyorum.
*
* Bundan sonraki bölümde bu örneğimizden devam ederek, transaction e değinmeye çalışacağım. Sonrasında Exception nesnesini biraz açmaya
* çalışacağım. Eksik,hatalı veya karmaşık anlatılmış yerler konusunda yorum yazarak uyarır iseniz mutluluk duyarım.
*
* Güzel günler dileği ile.
*/