PHP'den önce C++ veya benzeri bir dille uğraştıysanız, o zaman OOP (Object Oriented Programming) yani Nesneye Yönelik Programlama (NYP) ile tanışmışsınızdır. NYP ile daha önce uğraşmadıysanız gözünüzü biraz korkutabilir, ama aslında pek korkacak bir şey yok. NYP aslında sadece bir programlama yaklaşımıdır.
Mesela C yapısal bir programlama dili, daha sonra çıkan C++ ise nesne yönelimli bir dildir. NYP üstün özellikleri olan bir yaklaşımdır ama hiç kimse C++ ile yapılan bir programın C ile yazılamayacağını söyleyemez. NYP sadece size programlarınızı yazmanız için olaylara daha değişik bakmanızı sağlayan bir yaklaşım sunmaktadır. Nasıl bir yaklaşım mı,nesnelerle çalşmak tabii...
Şimdi diyeceksiniz,yaw kardeşim yıllardır yazıyoz kod, her işimizi de yaptık, nerden çıktı bu nesneler? Ne gibi bi faydası var bunların bize?
NYP'nin getirmiş olduğu pek çok kolaylık ve güzellikler var :
- 1- Nesne kavramı,nesnelerin metod ve özellikler içermeleriyle, artık programcının kendisine yüklemiş olduğu değişkenler,durumlar,fonksiyonlar arasında bulunan ilişkileri programcıdan alıp nesnenin depolama özelliği sayesinde nesneye yükleyebiliyor. Programcı kendisine yüklemiş olduğu bu sorumluluğu,nesne kavramı ile halledebiliyor.
- 2- Nesne kavramı gerçek yaşam problemlerini programlamaya aktarmada kolaylık getiriyor.
- 3- NYP, kalıtım özelliği sayesinde, yazılan kod başka amaçlar için ek özellikler eklenerek tekrar kullanılabiliyor.
- 4- NYP,ile yazılan kod daha okunabilir ve anlaşılabilir oluyor.
- 5- NYP ve kalıtım programcıların kollektif çalşmalarına olanak sunuyor.
- 6- Zor problemleri sunduğu yaklaşım ile daha kolay ve hızlı çözülebilir hale getiriyor.
Şimdi de bu yazdıklarıma bakarak diyeceksiniz,yaw neymiş bu NYP, iyice merak ettik... :-)
Aslında NYP daha çok büyük çaplı projelerde kullanılmak üzere tasarlanmştır.Varolan bir projenizi NYP yaklaşımı ile olduğundan daha karmaşık bir şekle de sokabilirsiniz. Ama yukarıda belirttiğim gibi tekrar kullanılabilir,daha okunaklı,sonradan geliştirilmeye açık kod yazmak istiyorsanız ne olursa olsun NYP tam size göre...
Nesne de nesne ? Nedir bu nesne?
Class'lar aslında değişkenler ve fonksiyonlardan oluşan paketler gibidirler.Değişkenlere 'özellik', fonksiyonlara 'metod' denir. Class'lar sadece kendilerinden oluşturulucak nesnelerin yapılarını gösteren tanımlamalardır.
Mesela
class ogrenci{
//özellikler
var $ad;
var $soyad;
//metodlar
function isim_ata($str)
{$this->ad=$str;}
function soyadi_ata($str)
{$this->soyad=$str;}
}
$murat = new ogrenci; |
Şu an için yukarıdaki kodun ne anlama geldiğini anlamanıza gerek yok- birazdan geçeceğiz -sadece şunu görmeniz gerek. Öncelikle ogrenci adlı bir class tanımladık. 'ogrenci' class tanımlaması ile ogrenci class'ı ile oluşturulacak nesnelerin
özellik ve metodlarını belirlemiş ve tasarlamş olduk. Şu ana kadar herhangi hafızada yer kaplayan bir şey yapmş olmadık. Ama aşağıdaki satır ile varolan bu class yapısından bir nesne oluşturuyoruz.
$murat = new ogrenci;
Artık hafızada bu class yapısının bir kopyası oluşturulup, $murat isimli değişkene atanmş oldu.Aynı şekilde
$mustafa = new ogrenci;
dediğimizde yine hafızada bir kopya daha oluşturulup $mustafa isimli değişkene atanıyor.
PHP ve Nesneler :
Yukarıda da bir giriş yaptığımız üzere artık soyut konuşmayı kesip hemen PHP'nin NYP syntax'ına geçelim. PHP C++ ve JAVA kadar güçlü bir şekilde NYP'yı desteklemese bile bu konuda oldukça iyi olduğunu söyleyebiliriz. Çünkü sonuçta PHP standalone programlar (.EXE programlar) geliştirmek için değil de web üzerinde çalşmak için tasarlanmş bir dildir.Bu yüzden diğer dillere göre daha zayıf bir NYP anlayşı vardır. Java veya c++ ile uğraşanlar için söyleyelim, Multi inheritance,tam anlamıyla depolama,destructor fonksiyonlar desteklenmemektedir. Neyse,geçelim...
Sınıf tanımlaması class kelimesi ile yapılır, tanımlama içinde sınıf metodları ve özellikleri tanımlanır.
class ogrenci {
//özellikler
var $ad;
var $soyad; //özellikler
function ogrenci(){
echo "Ögrenci olusturuldu...";
} }
?>
Sinif tanimlandiktan sonra sinifi program
içinde kullanmak istedigimizde new operatörünü kullaniriz.
$mustafa = new ogrenci;
?> |
Bu andan itibaren hafızada bir ogrenci sınıf kopyası oluşturulur ve $mustafa isimli değişkene atanır. Artık $mustafa isimli bir değişkeni kullanarak sınıfın metod ve
özelliklerine erişebiliriz.Bu iş için '->' operatörü kullanılır.
$mustafa = new ogrenci;
$mustafa->ogrenci();
echo $mustafa->ad;
echo $mustafa->soyad;
?> |
Bu arada dikkat ettiyseniz ogrenci sınıfının ogrenci isimli bir metodu var. Sınıf adıyla aynı isme sahip olan fonksiyonların NYP'da özel bir durumları vardır. Bu fonksiyonlara constructor denir. Yani $mustafa = new ogrenci; ile yeni bir nesne oluşturulduğunda yapılan bir sonraki iş sınıf yapısı içinde constructor fonksiyon varsa onu işlemektir. Mesela $mustafa=new ogrenci; çalştırıldığında
1- Hafızada sınıf yapısının bir kopyası oluşturulacak
2- Constructor fonksiyon - yani ogrenci - çağrılacak ve ekrana 'Öğrenci oluşturuldu' yazılacaktır.
Şimdi NYP'ya biraz alştığımıza göre sınıf yapımızı daha düzgün bi şekle getirelim :
class ogrenci {
var $ad;
var $soyad; function ogrenci ($isim,$soyisim){
$this->ad=$isim;
$this->soyad = $soyisim;
} }
$mustafa = new ogrenci ("Mustafa","Karabulut");
echo "Yeni ögrenci:". $mustafa->ad." ".$mustafa->soyad;
?> |
Öncelikle şunu söyleyeyim constructor fonksiyonlar parametre kabul edebilirler,eğer constructor için parametre söz konusu ise yeni nesne oluşturulurken bu parametrelerde verilmelidir. Burada yeni bir şeyler gözünüze çarpmş olmalı: $this ...
Normalde class özelliklerine ve fonksiyonlarına değişken adı ve '->' operatorü ile erişebiliyoruz. Peki ya henüz daha bir değişken oluşturulmadığı durumlarda,sınıf henüz tasarlanırken yani sınıf tanımlaması içinde sınıfın özelliklerine nasıl erişeceğiz. şte burada '$this' devreye girmekte ve içinde bulunulan sınıfın özellik ve metodlarına erişimde kullanılmaktadır.
Bilmemiz gereken bir iki nokta var:
1-Constructor fonksiyonlar nesne oluşturulduğunda otomatik çağrıldıkları için nesnenin ilk özellik ve işlemlerini yaptırmak için oldukça uygundurlar. Eğer bir constructor kullanmıyorsak bu tür ilk atamaları kendimiz bir şekilde yapmak zorunda kalırız.Bu açıdan çoğu durumda constructor kullanmak oldukça avantajlıdır.
2- C++ ve Java'da olduğu gibi destructor fonksiyonlar yoktur.
Kalıtım :
NYP'nin belki de en güzel özelliklerinden birisi de miras kavramıdır. Genellikle benzer özellikler taşıyan sınıflarda aynı özelliklerin tekrar tekrar yazılmasını önler. Varolan bir sınıf yapısına sadece bir kaç özellik daha ekleyerek hem yeni sınıf yapısını elde etmiş ,varolan kodu tekrar kullanılır yapmş ve aynı şeyleri tekrar yazmaktan kurtulmuş olursunuz.
Kalıtım olayı PHP'de extends anahtar sözcüğü ile yapılır.Örneğin :
class ogrenci {
var $ad;
var $soyad;
function ogrenci()
{}
} class liseli extends ogrenci{
var $lise_adi;
function liseli($isim,$soyisim)
{
$this->ad=$isim;
$this->soyad=$soyad;
}
function set_lise_adi($str)
{
$this->lise_adi=$str;
}
}
?> // Böylece liseli adli ogrenci sinifinin bütün özellik ve
// metodlarini barindiran, ayni zamanda kendine has '$lise_adi'
// ve 'liseli','set_lise_adi' metod ve özelliklerine sahip bir
// sinif yazms olduk.
$murat = liseli ("murat","hüdevandigar");
$murat->set_lise_adi("bilmem ne lisesi");
echo "Ögrencimiz : ".$murat->ad." ".$murat->soyad;
echo " Okulu :" .$murat->lise_adi;
?> |
Çok şık di mi ? Sadece kodu bir kere yazıp, çok değişik yerlerde kullanabiliyoruz. Tabii bir kaç nokta var dikkat edilecek :
1- 'liseli' sınıf kopyası hafızada oluşturulduğunda constructor fonksiyon olarak 'liseli' fonksiyonu çağrılır ve 'ogrenci' fonksiyonu çağrılmaz. Çünkü PHP4'de kural şöyledir :
a. Eğer sınıf adına sahip bir fonksiyon varsa onu çağır
b. Eğer yoksa taban sınıfın constructor fonksiyonunu çağır.
NOT:PHP3'de b kuralı geçerli değildir. Sadece a.kuralı geçerlidir.
2-üst sınıf içinde alt sınıf ile aynı isimde bir fonksiyon varsa, üst sınıfın fonksiyonu geçerlidir.
class a {
function c()
{echo "AAA";}
}
class b extends a{
function c()
{echo "BBB";} }
$letter = new b;
$letter->c();
?> |
Ekrana ne yazacak ? Ekrana "BBB" yazılacaktır. Çünkü üst sınıfın fonksiyonu alt sınıfın fonksiyonunun
üstüne yazılmştır.
3- Peki alt sınıfın aynı isimli bir fonksiyonunu
üstüne yazılıyorsa, alt sınıftaki aynı isimli fonksiyona erişmek için ne yapacağız ? Mesela yukarıdaki örnek için ekrana 'AAA' yazdırmamız gerekiyor ise ne yapacağız ? Burada 'parent::' anahtar kelimesini kullanacağız.
class a {
function c()
{echo "AAA";}
}
class b extends a{
function c()
{
parent::c();
echo "BBB";
} }
$letter = new b;
$letter->c();
?> |
parent::c() ile bir alttaki sınıfın c() fonksiyonunu çağırıyoruz. Böylece bu örnekte ekrana :
AAABBB yazılacaktır.
Buraya kadar NYP,Class,PHP'nin NYP syntax'ını gördüğümüze göre şimdi de güzel bir örnek ile bilgilerimizi pekiştirelim...
Dosyalama islemlerini yapan basit bir sinif yapisi:
Böylece hem dosya işlemlerini yapan fonksiyonları inceleyip hem de sınıf kullanarak NYP kavramına biraz daha ısınalım.
Şu işlemleri yapan bir sınıf yazalım :
1- Dosyaya kayıt ekleyen
2- Dosyadan kayıt silen
3- Dosyada kayıt arayan
######################################################
# #
# Coded By : Mustafa Karabulut (mkarabulut@ceviz.net) #
# Purpose : Just to share knowledge #
# Respect please: Do not sell or republish,reuse without #
# permission of the owner #
# #
# #
# Stand firm in the straight path as you are commanded #
####################################################### class filemanager{
var $filepath;
var $records;
var $recordSep;
var $fieldSep;
var $error;
function filemanager($file,$rsep="\r\n",$fsep="|"){
//dosyayi aç
if ($dosya = @fopen ($file,"r")){
//tüm dosyanin içeriğini oku ve
$content=fread($dosya,filesize($file));
//bütün içeriği kayitlara parçala
$this->records=explode($rsep,$content);
//kayit ve alan ayraçlarini belirle
$this->recordSep=$rsep;
$this->fieldSep =$fsep;
//dosya path
$this->filepath=$file;
} else {
$this->error[]="$file açilamadi";
}
@fclose($dosya);
} // function file manager sonu
function add_record ($newrecordarray){
//diziyi kayit formatina getir
$newrecordstr=implode($this->fieldSep,$newrecordarray);
//kaydi ekle
$this->records[]=$newrecordstr;
}
function delete_record($recordnumber){
$first_slice = array_slice($this->records,0,$recordnumber);
$second_slice = array_slice($this->records,$recordnumber+1);
$this->records = array_merge($first_slice,$second_slice);
}
function find_record($recordname){
//sadece isme göre arar
for($i=0;$irecords);$i++){
$fields=explode($this->fieldSep,$this->records[$i]);
if ($fields[0]==$recordname){
return $i;
}
}
} function update_file(){
//kayitlari dosya formatinda birlestir
$recordstr=implode($this->recordSep,$this->records);
$dosya=fopen($this->filepath,"w");
fwrite($dosya,$recordstr);
fclose($dosya);
}
} // class sonu |
Şimdi biraz açıklama yapmamız gerek sanırım :-).
Önce dosyamızın ve programımızın çalışma mantığı üzerine bir şeyler söyleyelim. Dosyamızda
kayıtlarımızı ve
kayıtların alanlarını ayırmak için
özel karakterler kullanıyoruz.Mesela
Mustafa|Karabulut|Programcı'\r\n'Şahin|Gür|
Webmaster Her kaydı \r\n karakterleri ile ayırıyoruz. Bu Windows sistemlerde alt satıra geçme karakteridir.Text dosyamızı notepad ile açtığımızda her kaydın bir satır teşkil ettiğini görürsünüz. Dosya yapımıza göre her kayıt 3 alandan oluşuyor. İsim,soyisim ve meslek... Kaydın alanlarını ayırmak için ise '|' karakterini kullanıyoruz.
function filemanager($file,$rsep="\r\n",$fsep="|"){
...
} |
Constructor fonksiyon tek parametre,isteğe göre 2 veya 3 parametre ile çalışabiliyor.İlk parametre kesin verilmesi gereken dosya adı-dosyanın
yolu desek daha doğru olur-,2. ve 3. parametreler ise eğer verilirse dosya için geçerli
kayıt ve alan ayraçlarını belirliyor.Örneğimizde bu değerler için default parametreler verdiğimizden,bunları yazmazsak bahsettiğimiz değerler kullanılacak.
Constructor'da dosya açılıp,bütün içeriği okunduktan sonra içeriği
kayıt ayraç karakteri ile parçalayıp tüm kayıtları bir
diziye atıyoruz.Bunu explode fonksiyonu ile yapıyoruz.
$this->records=explode($rsep,$content);
Explode fonksiyonu kısaca,ikinci parametresi ile verilen stringi birinci parametredeki stringe göre parçalar ve her elemanı bir
diziye atar.
Örneğin:
Örneğin:
$str="Mustafa#Karabulut#Sahin";
$dizi=explode("#",$str);
/*
artik
$dizi[0]="Mustafa";
$dizi[1]="Karabulut";
$dizi[2]="Sahin";
*/
?> |
Explode fonksiyonunun
tam ters
işlemini ise implode yapmaktadır.Kısaca verilen bir
diziyi istenilen bir karakter ile birleştirip bir string verir.Mesela yukarıdaki $
dizi değişkenini kullanırsak :
$yeni_str=implode("&",$dizi);
/*
$yeni_str="Mustafa&Karabulut&Sahin";
*/
?> |
Diğer sınıf metodlarımız ise adlarından anlaşılacağı üzere kayıt ekleme,kayıt bulma ve kayıt silme işlemlerini yapıyor. Ama gene de program içinde kullandığımız bir kaç fonksiyonu burada anlatsak iyi olur heralde:
array_slice: Bu fonksiyon verilen bir dizi içinden belirli bir parçayı alıp yeni bir dizi geri dönderir. Kullanımı:
array_slice($eski_dizi,$baslangicindis,$kac_tane);
$dizi = array ("Mustafa","Karabulut","Sahin","Gür");
$yeni_dizi=array_slice ($dizi,0,2);
$yeni_dizi2=array_slice($dizi,2,2);
$yeni_dizi3=array_slice($dizi,2);
?> |
Şimdi bakalım: $yeni_dizi değişkenine $dizi değişkeninin 0.elemanından itibaren 2 eleman atıyoruz.Böylece $yeni_dizi dizisinde "Mustafa","Karabulut" elemanları var artık.
$yeni_dizi2,ise 2. elemandan itibaren 2 eleman alıyor, yani elemanları "Şahin" ve "Gür".
Son kullanımda ise değişik bir şey var,fonksiyona son parametre verilmemiş, eğer fonksiyona son parametre verilmezse,verilen 2. parametreden itibaren dizinin sonuna kadar olan bütün elemanlar atılır.Yani
$yeni_dizi3 dizisinde 2.elemandan itibaren $dizi dizisinin sonuna kadar olan bütün elemanlar atılır.Bu da "Şahin" ve "Gür" demek oluyor.
array_merge : Verilen iki veya daha fazla diziyi birleştirip bir dizi geri dönderir.
$dizi = array_merge ($yeni_dizi,$yeni_dizi2);
$dizi2= array_merge ($yeni_dizi,$yeni_dizi2,$yeni_dizi3);
?> |
Oldukça basit bir kullanımı var di mi ?
Herneyse bu açıklamalardan sonra gelelim, sınıf yapımızı kullanan bir örnek yazmaya, aşağıdaki koda bir bakın:
//örnek kullanım
$filem=new filemanager("deneme.txt");
$filem->add_record(array("Mustafa","Karabulut","Programci"));
$filem->add_record(array("Erdal","güler","The Bozo"));
$filem->add_record(array("Sahin","Gür","WEpmaster"));
$filem->add_record(array("Hakan","Mustak","Coder"));
$filem->add_record(array("billy","GAtez","Windowzcu"));
$silinecek= $filem->find_record("Mustafa");
echo "$silinecek kaydi silinecek...";
$filem->delete_record($silinecek); //her zaman bunu yaparak bitirmemiz gerekiyor
$filem->update_file();
?> |
Gördüğünüz gibi sınıf yapınısını bir kere yazdıktan sonra,sınıfı metodları kullanarak oldukça şık,zarif kodlar ortaya çıkabiliyor. Kod karmaşıklıktan kurtulup daha okunabilir bir hale geliyor. Kendinizi sanki PHP'nin built-in sınıflarını ve fonksiyonlarını kullanıyor gibi hissediyorsunuz.Ayrıca başkaları da sizin sınıf ve metdolarınızı kullanarak kendi kodlarını yazabiliyor. Bu da kodun taşınabilir ve tekrar tekrar kullanılabilirliğini artırmış oluyor.
Herneyse,bu örnek ile beraber, NYP'ya bir adım atmış olduk. Yukarıdaki sınıf yapısını daha da geliştirebiliriz aslında. Mesela constructor fonksiyonda,sınıfın error özelliğini kullandık ama diğer fonksiyonlarda kullanmadık. $this->error kullanılarak sınıfa get_last_error,get_all_errors,error_exists gibi kontrol metodları ekleyebilirsiniz. Bu metodları kullanarak fonksiyonların istenmeyen bir iş yapmasını engelleyebilirsiniz. Mesela olası bir dosya açılma hatası olmuşsa,delete_record metodunun çalışmasını durdurabilirsiniz.
function error_exists(){
if (isset($this->error)){
return true;
} else {
return false;
}
}
function delete_record($num){
if (!$this->error_exists){
// islemleri yap
}
}
?> |
Aynı şekilde diğer metodlarıda istenmeyen durumlara karşı koruyabilirsiniz.
Şimdilik bu kadar. Gelecek yazıda görüşmek üzere.Bu yazı hakkındaki eleştirilerinizi,görüşlerinizi ve yayınlanmasını istediğiniz yazı konularını hem forumlarımıza yazabilir hemde mkarabulut@ceviz.net adresine postalayabilirsiniz.
Hiç yorum yok:
Yorum Gönder