VERİ TABANI YÖNETİMİ-DBASE

1-VERİ TABANI 

VERİ TABANI : Belirli bir tarzda organize edilmiş bilgiler koleksiyonudur.
VERİ TİPLERİ :

1-) Karaktersel (Alfasayısal)Veriler

ASCII karakterlerini kapsar. 1 ile 254 arası sayıda karakterden oluşabilir.
(Bursa, Okul0115a ,#, s, “123”)

2-) Sayısal (Numeric) Veriler

Sayısal değerler, dört işlem yapabildiğimiz değerlerdir. Ondalık veya tamsayı olabilir.
(123, 845)

3-) Tarih Tipi Veriler

Tarih gösteren verilerdir.Otomatik olarak 8 karakter uzunluğundadır. Normalde gg/aa/yy
formatındadır. SET KONTROL komutları kullanılarak gg/aa/yy formatına dönüşüm yapılabilir.
(05/28/95)

gg aa yy
g- gün a-ay y-yıl

4-) Memo Tipi Veriler

Bu türden olan veriler herhangi bir metni yani text’ i içeren verilerdir. Bu tip verilere ait
sahalar diğer sahalardan farklı şekilde işlenir. Çalışılan dosya çağrıldığında bu sahaya
ilişkin bilgiler görünmez, özel olarak o sahaya girilerek içeriği görülebilir. Kısa not şeklinde
bir veri tipi olarak tanımlayabiliriz.

5-) Logical (Mantıksal) Tip Veriler

Mantıksal bir sahanın içeriği yalnızca doğru veya yanlış olabilir. Başka alternatif yoktur.
(Doğru veya Yanlış) (True veya False) ( Yes veya No)

VERİ TABANI KÜTÜĞÜNÜN ANA PARÇALARI:

a-) Veri Alanları

Bir veri alanı, veri tabanı kütüğünün içinde hep aynı tipte veri tutan depolama birimidir.

Örneğin öğrencilere ait sicil bilgilerinin saklandığı bir veri tabanı kütüğünde

Yalnızca Öğrenci No.larının saklandığı alan adı OGRNO alanı

Yalnızca İsimlerin saklandığı alan adı ADSOY alanı

Yalnızca Telefonların saklandığı alan adı TELNO alanı

Her bir alanda tek bir tipte veri depolanmaktadır. Bütün öğrenci numaraları tek bir alanda,
bütün isimler tek bir alanda ve yine bütün telefonlar da tek bir alanda saklanmakta ve
bu alanlara alanın içeriğine uygun olmayan veri girilmemektedir.

b-) Veri Kayıtları

Veri tabanı kütüğüne girilen bilgilerdir. Veri tabanı kütüğünde her kayıt tek bir kişiye veya
nesneye aittir. Örneğin dört adet ile ait bilgileri sakladığımız oldukça basit bir kütük olan

“il” kütüğünü ele alalım.

  

 

 

 

 

 

 

 

 

 

 

 

Kayıt No 

 

 

ILKOD

ILADI

NUFUSU

1

01

ADANA

2100000

2

16

BURSA

2000000

3

34

İSTANBUL

8000000

4

67

ZONGULDAK

750000

 

 

 

 


Her bir kayıtta sadece tek bir kişi veya nesneye ait bilgilerin depolanacağı kuralına uygun
olarak, yukarıdaki örnekte birinci kaydın sadece ADANA iline , ikinci kaydın sadece BURSA
iline üçüncü kaydın sadece ISTANBUL iline ve yine dördüncü kaydın ise sadece
ZONGULDAK iline ait bilgileri içerdiğine dikkat edelim.

 

 

 

 

Yine yukarıdaki örnekte ILKOD, ILADI, NUFUSU başlıklarının her birisi ayrı birer VERİ ALANI
ve her bir ile ait bilgiler ise ayrı birer VERİ KAYDI’ dır. Başka bir deyişle yukarıdan aşağıya
her sütün birer VERİ ALANI iken, soldan sağa doğru her satır ise ayrı birer VERİ KAYDI’dır.

 

 

 VERİ TABANI KÜTÜĞÜNÜN YAPISI:

Veri tabanı yapısı, bir veri kütüğünün içindeki her alanın ayrıntılı tarifini içerir. Veri tabanı
kütüğünün yapısı şu şekildedir:

a-) Field Name (Alan Adı)

b-) Type (Alan Tipi)

c-) Width (Alan Genişliği)

a-) Field Name (Alan Adı) : Alfabetik (A-Z arası)bir değerle başlayıp sayısal bir değerle
devam edebilir. Karakterler arasında “ _ “ sembolü ile ayırma yapılabilir. Bunların dışındaki
karakterler kabul edilmez. Aynı isim birden fazla alana verilemez. Aynı alan adı yazılırsa
uyarılarak bir süre bekletilir. Bir alan adı için kullanılabilecek toplam karakter uzunluğu
10 karakterdir. Bir alan adının uzunluğu 128 byte’ ı , bir kayıttaki alanların toplam uzunluğu
ise 4000 byte’ ı geçemez.

b-) Type (Alan Tipi) : Beş adet alan tipi vardır. Bunlar Character , Numeric, Date, 
L
ogical, Memo alan tipleridir. Alan tiplerini seçmek için tiplerin ilk harfini yazmamız
veya ara çubuğuna (space bar) basmamız yeterlidir.

c-) Width (Alan Genişliği) :

Character 1-254 arası uzunlukta karakter alabilir

Numeric 1-19 arası uzunlukta karakter alabilir

Date 8 karakter uzunluğunu otomatik olarak alır

Logical 1 karakter uzunluğunu otomatik olarak alır

Memo 10 karakter uzunluğunu otomatik olarak alır

2-DBASE KOMUTLARI  

1-) VERİ TABANI DOSYASI OLUŞTURMAK:

DBASE ortamına girmek yani dbase’ i çalıştırmak için disk veya disketimizde aşağıdaki
dosyaların bulunması gerekmektedir:
DBASE.EXE
DBASE.MSG
DBASE.LD1
DBASE.OVL
DBASEINL.OVL
ASSIST.HLP
HELP.DBS

Yukarıdaki dosyalar disk veya disketimizde mevcut ise DBASE yazıp ENTER tuşuna
basarak Dbase ortamına girebiliriz.

CREATE komutunu kullanarak bir veri tabanı dosyası oluşturma işlemine
başlayabiliriz. Komutun Genel yazılımı şu şekildedir:

 

CREATE dosya adı

CREATE DENEME
CREATE KART
CREATE ORNEK

CREATE ORNEK yazıp ENTER tuşuna bastığımızda
karşımıza aşağıdaki türden bir ekran gelir:

Field Name “ISIM” yazıp ENTER tuşuna basınız. Type bölümünde yine ENTER tuşuna
basınız.Width için “ 10 ” yazıp ENTER tuşuna basınız. Yaptığımız bu işlemler ile ORNEK adlı
veri tabanı kütüğünde “ISIM” adında ve en fazla 10 karakter uzunluğunda bilgi girilebilecek
bir alan tanımlamış olduk. Böyle devam ederek aşağıdaki ekrana ulaşalım yani kütüğün
diğer alanlarını da aşağıdaki örneğe uygun olarak tanımlayalım.

Alan giriş tanımları sona erince CTRL+END tuşlarına basarız.

Press ENTER to confirm. Any other key to resume.

Mesajında ENTER tuşuna basarsanız oluşturduğunuz veri tabanı kütüğünü
(ORNEK.DBF adlı dosyayı) disk veya disketinize kaydetmiş olursunuz.
ENTER tuşundan başka herhangi bir tuşa basarsanız
kayıt yapılmaz. Kayıt işleminden sonra aşağıdaki mesaj ekranda görüntülenir.

Input data records now? (Y/N)

“Y” tuşuna basarsanız kütüğe bilgi girmeye başlarsınız. “N” tuşuna basarsanız
dbase nokta iletisine dönülür.

CREATE komutu ile bir dosya oluşturduğumuzda, daha önce aynı adla oluşturulmuş
bir dosya varsa o dosyanın içeriği sıfırlanır.

DBASE kullanarak oluşturduğumuz veri tabanı dosyalarının uzantısı “DBF” olur.


2- BİR DOSYAYI AÇMAK

Önceden oluşturulmuş bir dosyayı içindeki bilgileri yok etmeden açmak için
USE komutunu
kullanabiliriz. Komutun genel yazılımı şu şekildedir:
USE dosya adı

USE DENEME
USE KART
USE ORNEK

USE ORNEK yazıp ENTER tuşuna bastığımızda daha önceden CREATE komutunu
kullanarak oluşturup sakladığımız ORNEK.DBF adlı veri dosyasını ana bellekte aktif
hale getiririz,
yani açarız.

 

3- DOSYAYA KAYIT İLAVE ETMEK:

APPEND komutunu kullanarak dbase nokta iletisi konumundayken istenildiği anda,
ana bellekte o anda aktif olan yani açık olan kütüğe yeni bilgi ekleyebiliriz.

USE ORNEK yazıp dosyamızı açtıktan sonra, APPEND yazıp ENTER tuşuna basarak
daha önce oluşturduğumuz ORNEK adındaki dosyaya bilgi ilave edelim ve dosyamızın
içeriği aşağıdaki gibi olsun.

4- KAYITLARI GÖRÜNTÜLEMEK:

DISPLAY (DISP) komutunu kullanarak dbase nokta iletisi konumundayken istenildiği
anda, ana bellekte o anda aktif olan yani açık olan kütüğün kayıtları ekran yada yazıcıdan 
görüntülenebilir.

DISP yazıp ENTER tuşuna bastığımızda açık olan kütüğün o anda üzerinde bulunulan
kaydı görüntülenir

DISP record 3 yazıp ENTER tuşuna bastığımızda açık olan (aktif olan) kütüğün
3 numaralı kaydı görüntülenir

DISP ALL yazıp ENTER tuşuna bastığımızda açık olan (aktif olan) kütüğün bütün
kayıtları görüntülenir.

DISP ALL ISIM,SOYAD,TELEFON yazıp ENTER tuşuna bastığımızda açık olan
(aktif olan) kütüğün bütün kayıtlarının sadece, ISIM, SOYAD ve TELEFON bilgileri
görüntülenir.Kütüğün ISIM, SOYAD, TELEFON alanlarının dışında başka alanları varsa,
o alanlara ait bilgiler görüntülenmez.

DISP record 3 ISIM,SOYAD,TELEFON yazıp ENTER tuşuna bastığımızda açık
olan (aktif olan) kütüğün 3 nolu kaydının sadece, ISIM, SOYAD ve TELEFON bilgileri
görüntülenir.kütüğün ISIM, SOYAD, TELEFON alanlarının dışında başka alanları varsa,
o alanlara ait bilgiler görüntülenmez.

DISP ALL ISIM,SOYAD,TELEFON FOR “BAKIRKOY” $ ADRES

yazıp ENTER tuşuna bastığımızda açık olan (aktif olan) kütüğün bütün kayıtları içinden
sadece ADRES alanında BAKIRKOY kelimesi geçen kayıtlara ait, ISIM, SOYAD ve TELEFON
bilgileri görüntülenir.kütüğün ISIM, SOYAD, TELEFON alanlarının dışında başka alanları
varsa, o alanlara ait bilgiler görüntülenmez.

DISP ALL FOR SUBSTR(TELEFON,2,1)=”5” yazıp ENTER tuşuna bastığımızda
açık olan kütüğün bütün kayıtları içinden sadece TELEFON alanının (telefon numaralarının)
ikinci karakteri 5 olan kayıtlara ait tüm bilgiler görüntülenir.

DISP ALL ISIM,SOYAD,TELEFON FOR SUBSTR(TELEFON,2,1)=”5”
yazıp ENTER tuşuna bastığımızda açık olan kütüğün bütün kayıtları içinden sadece
TELEFON alanının (telefon numaralarının) ikinci karakteri 5 olan kayıtların ISIM, SOYAD ve
TELEFON bilgileri görüntülenir.Kütüğün ISIM, SOYAD, TELEFON alanlarının dışında başka
alanları varsa,o alanlara ait bilgiler görüntülenmez.

5- KAYITLARI LİSTELEMEK:

LIST komutunu kullanarak dbase nokta iletisi konumundayken istenildiği anda, ana
bellekte o anda aktif olan yani açık olan kütüğün kayıtları ekran yada yazıcıdan 
listelenebilir.
 

LIST yazıp ENTER tuşuna bastığımızda açık olan kütüğün bütün kayıtları listelenir.  

LIST ISIM,SOYAD,TELEFON yazıp ENTER tuşuna bastığımızda açık
olan kütüğün bütün kayıtlarının sadece, ISIM, SOYAD ve TELEFON bilgileri listelenir.
Kütüğün ISIM, SOYAD, TELEFON alanlarının dışında başka alanları varsa, o alanlara
ait bilgiler listelenmez.

6- KAYITLARI GÖRÜNTÜLEMEK ve DEĞİŞTİRMEK:

EDIT komutunu kullanarak dbase nokta iletisi konumundayken istenildiği anda, ana
bellekte o anda aktif olan yani açık olan kütüğün kayıtlarını ekranda görüntüleyebilir
ve kayıtlar üzerinde
değişiklikler yapabiliriz.

EDIT yazıp ENTER tuşuna bastığımızda açık olan kütüğün, o anda aktif olan kaydını
görüntüleyip üzerinde değişiklikler yapabiliriz. Yani kütüğün başındaysak ilk kaydı,
kütüğün sonundaysak ise son kaydı görüntüleyip değiştirebiliriz.

EDIT record 3 yazıp ENTER tuşuna bastığımızda açık olan kütüğün, 3 nolu
kaydını görüntüleyip üzerinde değişiklikler yapabiliriz.

7- KAYITLARI GÖRÜNTÜLEMEK  ve DEĞİŞTİRMEK:

BROWSE (BROWS) komutunu kullanarak dbase nokta iletisi konumundayken
istenildiği anda, ana bellekte o anda aktif olan yani açık olan kütüğü, alanları yan yana
olarak ekranda
listeleyip görüntüleyebilir ve kayıtlar üzerinde değişiklikler yapabilir yada
yeni kayıt girişi yapabiliriz.
BROWSE komutunu kullanabilmemiz için dosyada en azından bir adet kaydın mevcut
olması gerekmektedir. İstenilen alanda düzeltme yapmak için kursoru düzeltilecek alan
üzerine getirip değişiklik yapabilirsiniz.

8- İSTENİLEN KAYDA GİTMEK:

GO komutunu kullanarak dbase nokta iletisi konumundayken istenildiği anda, ana
bellekte o anda aktif olan yani açık olan kütüğün istediğimiz kaydına gidebiliriz.

GO 3 yazıp ENTER tuşuna bastığımızda açık olan kütüğün, 3 nolu kaydına gideriz.

GO TOP yazıp ENTER tuşuna bastığımızda açık olan kütüğün, İLK kaydına
(yani kütüğün başına) gideriz.

GO BOTTOM yazıp ENTER tuşuna bastığımızda açık olan kütüğün, SON kaydına
(yani kütüğün sonuna) gideriz.

SKIP komutunu kullanarak dbase nokta iletisi konumundayken istenildiği anda,
ana bellekte o anda aktif olan yani açık olan kütüğün kayıtları arasında istediğimiz
sayıda İLERİ yada GERİ gidebiliriz.

SKIP 3 yazıp ENTER tuşuna bastığımızda açık olan kütükte o anda bulunduğumuz
kayıttan 3 kayıt ileriye gideriz.

SKIP -3 yazıp ENTER tuşuna bastığımızda açık olan kütükte o anda bulunduğumuz
kayıttan 3 kayıt geriye gideriz.

9- KAYIT SİLMEK:

DELETED (DELE) komutunu kullanarak dbase nokta iletisi konumundayken ,
ana bellekte o anda aktif olan yani açık olan kütüğün istediğimiz kaydını silinmek üzere
işaretleriz. Bunun anlamı silinen kaydın başına “ * ” koymaktır.
DELE komutu ile silinmek üzere işaretlenen yani başına “ * ” konulan kayıtlar istenilirse
dikkate alınır , istenilirse dikkate alınmaz.

SET DELETED ON yazılırsa, DELETED komutu kullanılarak silinmek üzere işaretlenmiş
olan kayıtlar işlemlerde dikkate alınır.

SET DELETED OFF
yazılırsa, DELETED komutu kullanılarak silinmek üzere işaretlenmiş
olan kayıtlar işlemlerde dikkate alınmaz.

DELE RECORD 3 yazıp ENTER tuşuna bastığımızda açık olan kütüğün, 3 nolu kaydını
silinmek üzere işaretleriz.


10- SİLİNEN KAYITLARI KURTARMAK:

DELETED (DELE) komutu kullanılarak silinmek üzere işaretlenmiş kayıtları kurtarmak yani
kayıtların başındaki silinecek anlamına gelen “ * ” işaretini kaldırmak için RECALL komutunu
kullanırız.

RECALL RECORD 3 yazıp ENTER tuşuna bastığımızda açık olan kütüğün, daha önce
silinmek üzere DELE komutu ile işaretlenmiş 3 nolu kaydını eski haline getiririz yani
başındaki “ * ” işaretini kaldırırız.

10- SİLİNEN KAYITLARI TAMAMEN YOK ETMEK:

DELETED (DELE) komutu kullanılarak silinmek üzere işaretlenmiş kayıtları yok etmek yani
RECALL  komutu kullanılsa bile geri getirilemeyip dosyadan fiziksel olarak tamamen silinmesini
sağlamak için PACK komutunu kullanırız.

PACK yazıp ENTER tuşuna bastığımızda açık olan kütüğün, daha önce silinmek üzere DELE
komutu ile işaretlenmiş bütün kayıtlarını
bir daha geri getirilemeyecek şekilde, tamamen
yok ederiz.

11- BİR DOSYANIN TÜM KAYITLARINI YOK ETMEK:

Bir veri tabanı dosyasında bulunan bütün kayıtları dosyadan fiziksel olarak tamamen silmek
yani dosyanın içindeki bütün kayıtları yok etmek için ZAP komutunu kullanırız. Bu komut
dosyanın içindeki bütün kayıtları yok edeceği için çok dikkatle kullanılmalıdır.

ZAP yazıp ENTER tuşuna bastığımızda açık olan kütüğün bütün kayıtlarını bir daha geri
getirilemeyecek şekilde, tamamen yok ederiz.

12- BİR DOSYANIN YAPISINI GÖRMEK:

Bir dosyanın kayıt yapısını görmek için LIST STRU veya DISP STRU komutunu
kullanırız.LIST STRU komutu ile DISP STRU komutu arasındaki fark çok sayıda alana sahip
dosyaların yapısını görüntülerken ortaya çıkar. DISP STRU komutu bir ekran dolduğu zaman
bir tuşa basmanız için beklerken, LIST STRU komutu beklemez ve dosyanın yapısını sonuna
kadar döker bu arada bilgi ekrandan hızla geçeceği için dosya yapısının tamamını sağlıklı
biçimde incelemekte zorlanabiliriz.

DISP STRU yada LIST STRU yazıp ENTER tuşuna bastığımızda açık olan kütüğün
kayıt yapısını görebiliriz. Yukarıdaki örnekte oluşturduğumuz ORNEK.DBF adlı dosyanın
içeriğini bu komutları kullanarak görmek istesek aşağıdaki gibi bir görüntü elde ederiz.

13- BİR DOSYANIN YAPISINI DEĞİŞTİRMEK:

Bir dosyanın yapısını daha önce girilen bilgilerimizi kaybetmeden değiştirebilmek için 
MODI STRU 
komutunu kullanırız. Yukarıdaki örneği dikkate aldığımızda telefon numaralarını
girerken “9” karakter uzunluğunun yetmediğini (ülke ve şehir kodlarını da yazınca) daha
uzun telefon numaraları girmemiz gerektiğini düşünelim. Bu durumda TELEFON alanının
uzunluğunu örneğin 15 ‘e çıkarmak için MODI STRU komutunu kullanırız.

14- TÜM KAYITLARDA BİR ALANIN YAPISINI DEĞİŞTİRMEK:

Veri tabanı dosyasındaki herhangi bir alandaki bütün kayıtlara ait bilgileri değiştirmek için
REPLACE komutunu kullanırız. Komutun genel yazılımı :

REPLACE all DEĞİŞECEK ALAN ADI with NE ŞEKİLDE DEĞİŞECEĞİ

REPLACE all BUNU değiştir BU ŞEKİLDE

Yukarıdaki örneği dikkate aldığımızda telefon numaralarının tamamının başına örneğin “3”
getirmek için REPLACE all TELEFON with “3” +TELEFON yazıp ENTER tuşuna basmamız
yeterlidir.

15- DOSYANIN BİR KOPYASINI ALMAK:

Açık olan bir dosyanın başka bir isimle yeni bir kopyasını almak için COPY TO komutunu
kullanırız. Komutunu Genel Yazılımı şu şekildedir:

COPY TO Yeni Dosya Adı

16- DOSYANIN YAPISINI BAŞKA BİR DOSYAYA KOPYALAMAK:

Açık olan bir dosyanın içindeki kayıtlar( bilgiler) aktarılmadan, o dosyanın sadece yapısını
(sadece alanlarının adlarını, tiplerini ve uzunluklarını) başka bir dosyaya aktarmak için
COPY STRUCTURE TO
komutunu kullanırız. Komutunu Genel Yazılımı şu şekildedir:

COPY STRUCTURE TO Yeni Dosya Adı

17- AÇIK OLAN BÜTÜN DOSYALARI KAPATMAK:

Açık olan bütün dosyaları kapatmak için CLOSE ALL komutunu kullanırız.

18- EKRANI TEMİZLEMEK:

Ekranı temizlemek için CLEAR komutunu kullanırız.

19- DBASE ORTAMINDAN ÇIKMAK:

Dbase ortamından çıkmak QUIT komutunu kullanırız.

3-DBU PROGRAMININ TANITIMI

Database(veri) ve index dosyaları üzerinde işlem yapmamızı sağlayan çok kullanışlı bir yardımcı
programdır. Dbase nokta iletisinde komutlar kullanarak yapmak zorunda olduğumuz işlemlerin
hemen hemen tamamını bu programı kullanarak daha hızlı ve pratik yapma imkanımız vardır.
DBU yazıp ENTER tuşuna bastığımızda karşımıza aşağıdakine benzer bir ekran gelecektir.

F1- Help :Program ile ilgili yardım almak için kullanılır.

F2- Open :
Open-Database
: Önceden oluşturulmuş olan database kütüğünü (DBF) aktif hale
getiriyor, yani açıyor.

Open-Index : Önceden oluşturulmuş olan index dosyasını (NTX veya NDX)
aktif hale getiriyor, yani açıyor.

Open-View : Önceden oluşturulmuş olan görüntüyü açıyor.

F3- Create :

Create-Database : Bir database (DBF) kütüğünü ilk defa oluşturabilir veya var olan bir
kütüğün alanlarının yapısını (kütük yapısını) değiştirebiliriz.

Create-Index : Yeni index dosyası oluşturabilir veya var olan indeksi değiştirebiliriz.

F4- Save :

Save-View : Görüntüyü saklamak için kullanırız.

Save-Struct : Kütük yapısını saklamak için kullanırız.

F5- Browse :

Browse-Database : Aktif olan kütüğün bütün kayıtlarını üzerinde işlem yapabilmemiz için
bize gösterir. Kayıtlar üzerinde istediğimiz değişiklikleri yapabildiğimiz gibi mevcut kayıtları
silinmek üzere işaretleyebilir ya da kütüğe yeni kayıt ekleyebiliriz.

Browse-View : Görüntüyü kullanarak değişiklikler yapabiliriz.

F6- Utility :

Utility-Copy : Bir kütüğün istediğimiz koşulu sağlayan kayıtlarını yeni bir kütüğe aktarmak
amacıyla kullanabiliriz.

Utility-Apppend : Çalıştığımız kütüğe başka bir kütükten kayıt ekleyebiliriz.

Utility-Replace : Kütüğün istediğimiz alanlarının içindeki bilgileri değiştirebiliriz.

Utility-Pack : Silinmek üzere işaretlenmiş kayıtları yok ederiz, tamamen sileriz.

Utility-Zap : Kütüğün tüm kayıtalarını sileriz yani içindeki bilgileri yok ederiz.

Utility-Run : Dos komutlarını DBU içindeyken çalıştırabiliriz.

F7- Move :

Move-Seek : İndeksi olan database dosyalarının kayıtları arasında arama yapabiliriz.

Move-Goto : İstenilen kayda, kaydın record nosunu vererek ulaşabiliriz.

Move-Locate : İndex kullanmadan belirli bir koşulu sağlayan kayıtlara ulaşmak için kullanırız

Move-Skip : Kayıt atlamamızı sağlar.

F8- Set :

Set-Relation  : Birden fazla DBF dosyasında ortak alanları sayesinde aynı anda hareket
etmemizi sağlar.

Set–Filter     : Filtre oluşturur.

Set-Fields     : Kütüğün alanlarının sırasını (yerlerini) değiştirir.

4-DBASE-CLIPPER PROGRAM KOMUTLARI

Örnek programlarda kullanacağımız veri tabanı kütüğü ORNEK.DBF aşağıda listelenmiştir.

 

Field Name

Type

Width

Dec

ADSOY

C

25

 

MAAS

N

10

0

TARIH

D

8

 

BKOD

C

1

 

 

 

 

 

 

 

 

 

 


DO WHILE……ENDDO DÖNGÜ YAPISI

DO WHILE <koşul>

<komutlar>

ENDDO

DO WHILE <koşul>

<komutlar>

LOOP

<komutlar>

ENDDO

DO WHILE <koşul>

<komutlar>

EXIT

<komutlar>

ENDDO

DO WHILE <koşul>

DO WHILE <koşul>

<komutlar>

ENDDO

ENDDO

Koşul doğru olduğu sürece komutlar işleme

girer.

LOOP deyimi ile DO WHILE döngüsü içinde

Karşılaşılırsa, LOOP deyimi ile ENDDO

arasındaki komutlar işleme alınmaz ve

DO WHILE döngüsünün başına dönülür.

EXIT deyimi ile DO WHILE döngüsü içinde

Karşılaşılırsa, EXIT deyimi ile ENDDO

arasındaki komutlar işleme alınmaz ve

DO WHILE döngüsünün dışına çıkılır.

İçiçe DO WHILE döngüsü kullanıldığında

Birbirini kesme olmaması gerekir. İşleme

En içteki döngüden dışa doğru devam edilir.

ÖRNEK-1

İsim ve soyadınızı ekranda 9 kere tekrarlayan ve her defasında kaçıncı kez isminizi tekrarladığını gösteren programı yazınız.

CLEAR

SET TALK OFF

X=1

ADSOY=”ERDİNÇ KAHRAMAN”

Do WHILE x<=9

? adsoy,x

x=x+1

ENDDO

CLEAR : Ekranı temizler

SET TALK OFF : Dbase yorumlayıcısında kullanılan komut ve deyimlerin sonuçlarını saklar.

? : Değişkeni ekranda yazdırır.

ÖRNEK-2

ORNEK.DBF kütüğündeki kayıtları “kütük başından sonuna doğru” , kayıt numaralarıyla beraber ekranda sıralayan programı yazınız. (Sadece adsoy alanını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

? adsoy , RECNO( )

SKIP

ENDDO

RETURN

USE ORNEK : ORNEK.DBF adlı dosyayı çağırır( Ana bellkte aktif hale getirir)

GO TOP : Kütüğün en başına gider.

SKIP : Bir kayıt ileriye doğru atlatır.

RETURN : Programı sonuna geldiğini ve artık çalışabileceğini gösterir.

ÖRNEK-3

ORNEK.DBF kütüğündeki kayıtları “kütük sonundan başına doğru” , kayıt numaralarıyla beraber ekranda sıralayan programı yazınız. (Sadece adsoy alanını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO BOTTOM

Do WHILE .NOT. BOF( )

? adsoy , RECNO( )

SKIP -1

ENDDO

RETURN

GO BOTTOM : Kütüğün en sonuna gider.

SKIP -1 : Bir kayıt geriye doğru atlatır.

BOF ( ) : Kütük Başı

ÖRNEK-4

1 1

1 2

1 3

2 1

2 2

2 3

3 1

3 2

3 3

Yukarıdaki matrisi içiçe döngü kullanarak döken programı yazınız.

CLEAR

SET TALK OFF

x=1

y=1

Do WHILE x<=3

Do WHILE y<=3

? x , y

y=y+1

ENDDO

y=1

x=x+1

ENDDO

RETURN

IF…….ELSE……..ENDIF KOŞUL YAPISI

IF <koşul>

<komutlar>

ENDIF

IF <koşul>

<komutlar1>

ELSE

<komutlar2>

ENDIF

Koşul doğruysa komutlar işleme girer, yanlışsa

İşleme girmez.

Koşul doğruysa <komutlar1> işleme girer ve

ENDIF deyimi ile bloktan çıkılır.

Koşul yanlışsa <komutlar2> işleme girer ve

bloktan çıkılır.

ÖRNEK-1

ORNEK.DBF kütüğündeki bkod=1 olan kayıtları , kayıt numaralarıyla beraber ekrana döken programı yazınız. (Sadece adsoy ve bkod alanlarını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

IF BKOD=”1”

? adsoy , bkod, RECNO( )

ENDIF

SKIP

ENDDO

RETURN

ÖRNEK-2

ORNEK.DBF kütüğündeki maaşı 300.000.000 dan küçük olan kayıtları , kayıt numaralarıyla beraber ekrana döken programı yazınız. (Sadece adsoy ve maas alanlarını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

IF MAAS<300000000

? adsoy , maas, RECNO( )

ENDIF

SKIP

ENDDO

RETURN

ÖRNEK-3

ORNEK.DBF kütüğündeki maaşı 300.000.000 dan küçük ve bkod=1 olan kayıtları , kayıt numaralarıyla beraber ekrana döken programı yazınız. (Sadece adsoy , bkod ve maas alanlarını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

IF MAAS<300000000

IF BKOD=”1”

? adsoy , bkod, maas, RECNO( )

ENDIF

ENDIF

SKIP

ENDDO

RETURN

ÖRNEK-4

ORNEK.DBF kütüğünde kişinin maaşı 150.000.000 dan küçük veya 150.000.000 a eşitse kişinin adını soyadını ve maaşını görüntüleyip yanına “AZ KAZANIYOR” , ve kişinin maaşı 150.000.000 ‘dan büyük ise kişinin adını soyadını ve maaşını görüntüleyip yanına “İYİ KAZANIYOR” yazan programı yazınız. (Sadece adsoy ve maas alanlarını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

IF MAAS=<150000000

? adsoy , maas, “AZ KAZANIYOR”

ELSE

? adsoy , maas, “İYİ KAZANIYOR”

ENDIF

SKIP

ENDDO

RETURN

ÖRNEK-5

ORNEK.DBF kütüğünde sadece bkod=1 olan kayıtlar için kişinin maaşı 150.000.000 dan küçük veya 150.000.000 a eşitse kişinin adını soyadını ve maaşını görüntüleyip yanına “AZ KAZANIYOR” , ve kişinin maaşı 150.000.000 ‘dan büyük ise kişinin adını soyadını ve maaşını görüntüleyip yanına “İYİ KAZANIYOR” yazan ve programı yazınız. (Sadece adsoy ve maas alanlarını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

IF BKOD=”1”

IF MAAS=<150000000

? adsoy , maas, “AZ KAZANIYOR”

ELSE

? adsoy , maas, “İYİ KAZANIYOR”

ENDIF

ENDIF

SKIP

ENDDO

RETURN

ÖRNEK-6

ORNEK.DBF kütüğünde sadece bkod=1 olan kayıtlar için kişinin maaşı 150.000.000 dan küçük veya 150.000.000 a eşitse kişinin adını soyadını ve maaşını görüntüleyip yanına “AZ KAZANIYOR” , ve kişinin maaşı 150.000.000 ‘dan büyük ise kişinin adını soyadını ve maaşını görüntüleyip yanına “İYİ KAZANIYOR” yazan ve bkod=1’den farklı olan kayıtlar için ise kişinin adını soyadını görüntüleyip yanına “BKODU 1’DEN FARKLI” ifadesini yazan programı yazınız. (Sadece adsoy ve maas alanlarını görüntüleyin).

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

IF BKOD=”1”

IF MAAS=<150000000

? adsoy , maas, “AZ KAZANIYOR”

ELSE

? adsoy , maas, “İYİ KAZANIYOR”

ENDIF

ELSE

? adsoy , maas, “BKODU 1’DEN FARKLI”

ENDIF

SKIP

ENDDO

RETURN

DO CASE……CASE……..ENDCASE

İçiçe IF deyimleri ile birden fazla koşulu kontrol edebildiğimiz gibi, aynı işlemi DO CASE…..ENDCASE blokları ile de yapabiliriz. DO CASE bloklarında tanımlanan koşullardan sadece birisi doğruysa, onunla ilgili deyimler işleme girer. Kullanılması içiçe IF deyimlerinden daha kolaydır. Program işlemesi sırasında da daha hızlı çalışır.

DO CASE

CASE <koşul-1>

<komutlar-1>

CASE <koşul-2>

<komutlar-2>

…………………………….

…………………………….

…………………………….

CASE <koşul-n>

<komutlar-n>

[OTHERWISE]

<komutlar-x>

ENDCASE

Koşul-1 doğruysa komutlar-1

Koşul-2 doğruysa komutlar-2

Koşul-n doğruysa komutlar-n işleme girer.

OTHERWISE hiçbir koşulun sağlanamaması durumunda işleme girer ve komutlar-x çalışır.

ÖRNEK-1

ORNEK.DBF kütüğünde bkod alanını kullanarak kişilerin adlarını soyadlarını ve unvanlarını döken programı yazınız.

bkod =1 ise ünvanı MÜDÜR bkod =2 ise ünvanı ŞEF bkod =3 ise ünvanı MEMUR

CLEAR

SET TALK OFF

USE ORNEK

GO TOP

Do WHILE .NOT. EOF( )

DO CASE

CASE bkod=”1”

YAZ=”MÜDÜR”

CASE bkod=”2”

YAZ=”ŞEF”

CASE bkod=”3”

YAZ=”MEMUR”

ENDCASE

? adsoy , YAZ

SKIP

ENDDO

RETURN

 

 SQL (Structured Query Language)

    İlişkisel Veritabanı Yönetim Sistemleri (Relational Database Management Systems -RDBMS) modeli ilk önce
1970 yılında Dr. E. F .Codd tarafından tarif edilmiştir. SQL veya Structured English Query Language (SEQUEL), IBM
firması tarafından Codd’un modelini kullanmak için geliştirilmiştir. SEQUEL sonraları SQL olmuştur. 1979 yılında,
Relational Software (şu an, Oracle Corporation), SQL’in ilk ticari uygulamasını geliştirmiştir. Bugün,SQL, ilişkisel
veritabanı yönetim sistemleri standardı olarak kabul edilmektedir.

SQL, ilişkisel veritabanlarındaki bilgileri orgulamak için kullanılan dildir. SQL, bütün kullanıcıların ve ygulamaların
veritabanına erişmek için kullandıkları komutlar bütünüdür. Uygulama programları ve veritabanı araçları kullanıcılara
çoğu durumda SQL kullanmadan veritabanına erişim imkanı sunmaktadırlar fakat bu uygulamalar da geri planda
SQL kullanmaktadırlar.

Oracle SQL’i, standartlara uygundur. Daha da ötesinde, Oracle, SQL standartlarının gelişmesinde motor güç olan
bir kurumdur. American National Standarts Institue (ANSI) ve International Standarts Organization (ISO) tarafından
belirlenen son SQL standardı, SQL-92’dir. SQL-92’de, üç aşamalı uygunluk vardır. Bunlar;
.ilk seviye (Entry Level)
.Orta seviye (Intermediate Level)
.ileri seviye’dir (Full Level)

Oracle7, ilk seviye uygunluğuna sahiptir. SQL, ilişkisel veritabanları ile uygulamaların diyaloğunu sağlamaktadır.
SQL, temelde verilerle mantıksal seviyede çalışmaktadır. Yani, bir tablodan bir kaç kayıt seçebilmek için, o kayıtları
seçebilecek bir şart belirtilir. Şarta uyan bütün kayıtlar bir basamakta gelir ve bunlar kullanıcıya gösterilebildiği gibi,
bir başka SQL’e veya bir uygulamaya da gönderilebilir. Kayıtların tek tek nasıl geldiği ve fiziksel olarak eritabanının
neresinde ve nasıl tutulduğu ile SQL ilgilenmemektedir.
SQL komutları ile
.veri sorgulama
.bir tabloya kayıt ekleme, değiştirme ve silme
.veritabanı nesnelerini (database objects) yaratma, değiştirme ve silme
.veritabanına ve nesnelerine erişimi kontrol etme
.veritabanı bütünlüğünü ve tutarlılığını sağlama işlemleri yapılabilmektedir.

SQL komutları bir veya daha fazla satır olabilmektedir. SQL cümlelerinin sonuna noktalı virgül (;) konmaktadır.
irden fazla satır olan komutlarda en son satırın sonuna ”/” işareti isteğe bağlı olarak konabilmektedir. PL/SQL, Oracle’ın SQL komutlarına yapısal dillere ait özellikleri (begin, end, ioop, for, if, elsif, vb.) eklediği kendi standardı
olan bir dildir. ORACLE SQL, SQL *PLUS, PL/SQL komutlarının kullanılabildiği Oracle ürünüdür.
ORACLE SQL, SQL *PLUS, PL/SQL ve eklemiş olduğu bir dildir. PUSQL ile, veritabanı ile ilgili çok önemli
işlemler yapılabilmektedir. SQL bilinmeden, PL/SQL ile hiçbir işlem yapılamaz, bu yüzden önce SQL iyi bir şekilde
öğrenilmelidir.

 

 

 

SQL cümlelerinde kullanılan tabloların yapısı ve içeriği

 

scott.jpg (18564 bytes)

Empno

Ename

Job

Mgr

Sal

Hiredate

Comm

Deptno

7369

SMITH

CLERK

7902

800

17.12.1980

 

20

7499

ALLEN

SALESMAN

7698

1600

20.02.1981

300

30

7521

WARD

SALESMAN

7698

1250

22.02.1981

500

30

7566

JONES

MANAGER

7839

2975

02.04.1981

 

20

7654

MARTIN

SALESMAN

7698

1250

28.09.1981

1400

30

7698

BLAKE

MANAGER

7839

2850

01.05.1981

 

30

7782

CLARK

MANAGER

7839

2450

09.06.1981

 

10

7788

SCOTT

ANALYST

7566

3000

19.04.1987

 

20

7839

KING

PRESIDENT

 

5000

17.11.1981

 

10

7844

TURNER

SALESMAN

7698

1500

08.09.1981

0

30

7876

ADAMS

CLERK

7788

1100

23.05.1987

 

20

7900

JAMES

CLERK

7698

950

03.12.1981

 

30

7902

FORD

ANALYST

7566

3000

03.12.1981

 

20

7934

MILLER

CLERK

7782

1300

23.01.1982

 

10

 

Deptno

Dname

Loc

10

ACCOUNTING

NEW YORK

20

RESEARCH

DALLAS

30

SALES

CHICAGO

40

OPERATIONS

BOSTON

 

 

 

 

 

 

 

İÇİNDEKİLER

 

 

 

 

 

        SQL’e giriş
Fonksiyonlar
Karakter fonksiyonları
Sayısal fonksiyonlar
Tarih fonksiyonları
Dönüştürme (Conversion) fonksiyonları
Değişik türlerde parametre kabul edebilen fonksiyonlar
Grup fonksiyonlarr
Birden fazla tabloyu sorgulama (Join)
Equi-Joins
Non-Equi-Joins
Outher Joins
Tabloyu kendisi ile birleştirme
Sorguda küme işlemleri kullanma (Union, intersect, minus)
İç içe sorgu cümleleri
Nasıl işlenir ?
ANY/ALL işleci
HAVING işleci
Sıralı liste üretme
Dikkat edilmesi gereken noktalar
EXIST işleci
Veri tanımlama Dili (Data Definition Language)

Tablo yaratma komutu (CREATE TABLE)
Tablo kolon türleri
Tablo tanrmlarını değiştirme (ALTER TABLE)
Tablo silme (DROP TABLE)
Tablo ismini degiştirme (RENAME)
Tablo tanımnr görme (DESCRIBE)

Veri Kullanma Dili

 

 

 

 

 

        Tabloya yeni kayıt ekleme (INSERT)
Başka bir tablodan kayıt kopyalama
Kayıt değiştirme (UPDATE)
Kayıt silme (DELETE)
İşlemleri bir süreç içerisinde toplama
(Transaction processing and COMMIT/ROLLBACK)
Tutarlı kayıt okuma (Read consistency)
Eşzamanlı işlemler ve kaynakların paylaşımı (LOCK)
Kaynak kilitleme türleri
ROWID yapay kolonunun kullanrmı
INDEX kuilanımı
Index kullanma nedenleri
Index türleri (unique, non-unique, single/concatenated)
Index yaratma (CREATE INDEX)
Index silme (DROP INDEX)

1. SQL’E GiRiŞ

 

 

 

 

 

    Onceleri SEQUEL (Structred English QUEry Language) olarak adlandırılan bu dilin adı, daha sonra ingilizce
söylenişine uygun olarak SQL olarak değiştirildi. SQL, bilgisayar uzmanı olmayan ve yüksek düzeyli, işlemsel
olmayan (non-procedural) bir dil aracılığıyla veri tabanı ile iletişim kurmak isteyen kullanıcı kitlelerine yönelik bir
veri tabanı dilidir.

SQL Komut Kümesi

 

 

 

 

 

Komut                Acıklama
SELECT             Verileri getirmek için kullanılır.
INSERT              Yeni kayıt eklemede kullanılır.
UPDATE             Var olan bir kaydı değiştirmek üzere kullanılır.
DELETE             Var alan bir kaydı silmek için kullanılır.
CREATE             Veri tabanında yeni bir nesne yararmak için kullanılır.  (Table, View, Index, Synonym vb.)
ALTER                 Veri tabanındaki nesne üzerinde değişiklik yapar. (Omeğin yeni bir kolon eklemek gibi)
DROP                  Veri tabanındaki bir nesneyi siler.
GRANT                Kullanıcılara erişim yetkilerinin verilmesinde kulanılır.
REVOKE            Verilen erişim yetkilerinin geri alınmasında kullanılır.

SQL komulan nasıl yazılır
.Yazılan SQL cümlesi bir yada daha fazla satır olabilir.
.SQL cümlesi içerisinde yer alan cümlecikler genelde farklı satırlara yazılır.
.Komut kelimeleri bölünerek alt satırdan devam edilemez.
.SQL komutları büyük yada küçük harflarle yazılabilir.
.Her SQL cümlesi noktalı virgül (;) ile bitirilir.

Basit SELECT ifadeleri

 

 

 

 

 

        En basit biçimiyle bir SELECT ifadesi
1. Istenilen tablonun kolonlarının belirtildiği bir SELECT cümleciği,
2. Hangi tablodan veri seçileceğini ifade eden bir FROM cümleciği içermelidir.
SELECT DEPTNO,ENAME,MGR FROM EMP;

 

DEPT NO

ENAME

MNG

10

KING

 

20

JONES

7839

30

BLAKE

7839

10

CLARK

7839

20

SCOTT

7566

20

FORD

7566

20

SMITH

7902

30

ALLEN

7698

30

WARD

7698

30

MARTIN

7698

30

TURNER

7698

20

ADAMS

7788

30

JAMES

7698

10

MILLER

7782

Eğer tablodaki bütün kolonlar seçilek istenseydi, * ile hepsi ifade edilebilirdi.
SELECT * FROM EMP

Aritmetik ifadeler     Aritmetik ifadeler içerisinde kolon isimleri, sabit sayılar ve aritmetik işleçler kullanılabilir.
~ Açıklama
+ toplama
– çıkrama
* çarpma
/ bölme
Aritmetik ifade içerisinde “*” ve “/” eşit öncelikli, “+” ve “-“ye göre daha önceliklidir. “+” ve “-” de eşit nceliklidirler. Cncelikleri tam ifade etmek için parantezler kullanılabilir.
SELECT SAL *12, COMM FROM EMP;
SAL kolonunun 12 ile çarpılmış biçimi getirilir.

Kolon isimlendirme Kolonların başlıkları SQl cümlesinde yazıldıkları biçimi ile getirilirler. Bunu değiştirmek mümkündür.
SELECT ENAME, SAL *12 ANNSAL, COMM FROM EMP;
Kolon başlığı olarak SAl *12 yerine ANNSAL kullanılacak.
Değiştirilen kolon başlıkları SQl cümlesi içerisinde artık yeni isimleri ile kullanılırlar.

Birleştirme işleci (||) Kolonlardan gelen değerleri yan yana yapıştırmak mümkündür. “11” Işleci ile
kolonlar arasında boşluk olmadığına dikkat ediniz.
SELECT EMPNOIIENAME EMPLOYEE FROM EMP;
EMPLOYEE
7839KING
7566JONES
7698BLAKE
7782CLARK

Literaller Literailer veriler ile birlikte çıkmasını istediğimiz karakterlerdir.
SELECT EMPNOII’-‘IIENAME CALISAN,’Calistigi bolum’, DEPTNO BLM. FROM EMP;

CALISAN

Calistigi bolum

BLM

7839-KING

Calistigi bolum

10

7566-JONES

Calistigi bolum

20

7698-BLAKE

Calistigi bolum

30

7782-CLARK

Calistigi bolum

10

7788-SCOTT

Calistigi bolum

20

7902-FORD

Calistigi bolum

20

7369-SMITH

Calistigi bolum

20

7499-ALLEN

Calistigi bolum

30

752l-WARD

Calistigi bolum

30

7654-MARTIN

Calistigi bolum

30

7844-TURNER

Calistigi bolum

30

7876-ADAMS

Calistigi bolum

20

7900-JAMES

Calistigi bolum

30

7934-MILLER

Calistigi bolum

10

Fonksiyonlar     Fonksiyonlar aldıkları kolonun yada sabit değişkenin değerini yeni bir biçime dönüştürürler. NULL değerlerin yakalanması NULL değeri olmayan anlamı taşır ve herhangibir işleme giren bu değer mutlaka NULL üretir ve istenmeyen bir sonuç alınmasına yol açabilir. Bunu engellemek için NVL fonksiyonu kullanılır.
SELECT SAL *12-NVL(COMM,O) YILLIK FROM EMP;
Eğer NVL fonksiyonu kullanılmamış olsa idi COMM değeri olmayan bütün kayırlar için SAL *12-COMM esaplamasından NULL geri döndürülecekti. NVL fonksiyonu içerisine yazılan kolonun değeri NULL ise NULL yerine ne kullanılacağını belirler. Omekte COMM kolonunun NULL değerleri için sıfır kullanılmaktadır.

DISTINCT ifadesi Eğer seçilen kolon aynı satırdan birden fazla getiriyorsa, bunlardan fazla olan satırları atmak mümkündür.
SELECT DISTICT DEPTNO FROM EMP;
Bu sorgu bir bölümde birden fazla çalışan olduğu halde çalışanlar tablosundan sadece bölüm numaralarını seçmekte ve tekkarlı satırları elemektedir.

ORDER BY ifadesi Seçilen kolonların hangi sırada geleceğini belirlemek amacıyla kullanılır.
SELECT ENAME,JOB FROM EMP ORDER BY ENAME;
Ornekte çalışanlar isimlerilerine göre sıralı olarak getirilmektedir.
ORDER BY ENAME ~ : Küçükten büyüğe sıralar
ORDER BY ENAME ~ : Büyükten küçüğe sıralar
Birden fazla kolon sıralanmak istendiğinde kolon isimleri virgül ile ayrılarak yazılır. (ODER BY DEPTNO.SAL DESC gibi). Sıralama sırasında NULL değerleri sıralama nasıl olursa olsun ilk sırada yer alırlar.

WHERE ifadesi Kayıtlar arasından sadece istenilen koşulları taşıyanların seçilebilmesini sağlamak amacıyla WHERE ifadesi kullanılır. Koşulu vermek için mantıksal işleçler kullanılır.
~ Anlamı
‘=’ eşittir
‘>’ büyüktür
‘<‘ küçüktür
‘>=’ büyük eşittir
‘<=’ küçük eşittir
SELECT DNAME,DEPTNO FROM DEPT DEPTNO WHERE DEPTNO>20;
20’den büyük olanları seç

SQL işleçleri
islec anlamı
BETWEEN …AND …iki değer arasında (değerler dahil)
IN (Iiste) Iistedeki değerler içinden en az biri
LlKE Benzer ise
IS NULL Boş değer ise
BETWEEN işleci
                SELECT ENAME,SAL FROM EMP WHERE SAl BETWEEN 1 000 AND 2000;
                Değeri 1000’e eşit ve 1000’den büyük ve 2000’e eşit ve 2000’den küçük olanları seçer.
IN İşleci
                SELECT EMPNO,ENAME,SAl,MGR FROM EMP WHERE MGR IN (7902, 7566, 7788);
                MGR 7902 yada 7566 yada 7788 olan kayıtlar seçilir.
LlKE İşleci
                Bazı durumlarda tam karşılaştırma yapmak işimize yaramayabilir. Omeğin adı ‘A’ harfi ile başlayanları
seçmek iştediğimizde. Bu durumda llKE işleci kullanılır. Karşılaştırmada kullanılacak sabit içerisinde
özel semboller kullanılır.
Sembol Anlamı
% Sıfır yada daha fazla karakterler
Bir karakter
SELECT ENAME FROM EMP WHERE ENAME llKE ‘S%’;
Omekteki SQL cümlesi ‘S’ harfi ile başlayan isimleri getirir.
SELECT ENAME FROM EMP WHERE ENAME llKE ‘-‘;
Ikinci ömekteki SQl cümlesi ise dört harfli isimleri getirir.
/%’ ve ‘-‘ sembolleri bir sabit içerisinde aynı anda değişik kombinasyonlarla kullanılabilir.

IS NULL işleci
Bir kolon değerinin NUll olup olmadığını anlamanın tek yolu bu işleci kullanmaktır. ‘=NUll’ işleci kullanmak aynı şey değildir ve hiçbir sonuç vermez.
SELECT ENAME,MGR FROM EMP WHERE MGR IS NULL;
Yukarıdaki ömek yöneticisi olmayan çalışanların Iistesini üretir.
Negatif Test
    Bir koşulu sağlayan değil de sağlamayanlar seçilmek isteniyor olabilir. Bu durumda işlecin anlamının tersine
çevrilmesi gerekir.
~ Anlamı
!= eşit değildir (V AX için)
,,= eşit değildir (IBM için)
<> eşit değildir

SQL isleci Anlamı
NOT BETWEEN     Verilen değerler arasında olamyan değerler
NOT IN (Iiste)         Listedeki değerler içerisinde olmayan
NOT LlKE              Benzer olmayan
IS NOT NULL         Boş olmayan

Sorguda birden fazla koşul kullanma AND (ve) ve OR (ya da) işleçleri birden fazla verilmiş olan koşul
ifadelerini birleştirmek amacıyla kullanılır. AND işleci arasında bulunduğu her iki koşul ifadesinin de doğru olmak
zorunda olduğunu, OR işleci arasında bulunduğu her iki koşul ifadesinden sadece birisinin doğru olmasının
yeterli olduğunu ifade etmek için kullanılır.

Aynı SQL cümlesinde hem AND hem de OR işleçleri koşullar arasında istenilen kombinasyonda kullanılabilir.
AND işleci her zaman OR işlecine göre daha önceliklidir ve daha önce işletilir. OR işlecini AND işlecine göre
öncelikli hale getirebilmek için parantezlerden “()” faydalanılır.
SELECT EMPNO,ENAME,JOB,SAL
FROM EMP
WHERE SAL BETWEEN 1 000 AND 2000
AND JOB=’CLERK’.

 

 

 

 

 

 

 

 

FONKSİYONLAR

 

 

    Fonksiyonlar aldıları değerleri, kendilerine yüklenmiş olan göreve göre yeni bir biçime dönüştürürler.

Fonksiyonlar aşağıdaki gibi sınıflandırılabilir.
.Karakter fonksiyonları
.Sayısal fonksiyonlar
.Tarih fonksiyonları
.Dönüştürme fonksiyonları
.Herhangibir tür veri üzerinde işlem yapabilen fonksiyonlar
.Grup fonksiyonları

Karakter Fonksiyonları
    Karakter türü değişken ya da sabitleri alarak yüklenmiş olduğu göreve göre bunlar üzerinde işlem yapar ve
karakter ya da sayısal bir değer döndürür.

LOWER(kolon/sabit) : Giriş olarak okuduğu karakter dizisini küçük harflere
önüştürür. ‘kolonlsabit’ şeklindeki gösterim bir tek parametre girileceğini ve bu parametrenin bir kolon adı ya da
bir sabit karakter dizisi olabileceğini gösterir.

SELECT LOWER(DNAME),LOWER(‘SQL’) FROM DEPT;

UPPER(kolonlsabit) : Parametre olarak alınan karakterleri büyük harfe dönüştürür.
İfadenin büyük harf veya küçük harf olması sonucu değiştirmez, her durumda byük harfe çevirir.

INITCAP(kolonlsabit) : Parametre olarak verilen karakter dizisi içerindeki her kelimenin baş harfini büyük harfe diğer harflerini küçük harfe dönüştürür.

LPAD(kolon/sabit,n,’karakter dizisi’) : Parametre olarak verilen kolon ya da sabiti
yazmadan önce başına n adet istenilen karakter dizisinden basar. Eğer karakter dizisi verilmez ise boşluk ekler.

SELECT LPAD(DNAME,20,’*’),LPAD(DNAME, 15) FROM DEPT;

PAD(DNAME,20,’*’)

LPAD(DNAME,15)

***********ACCOUNTING

ACCOUNTING

*************RESEARCH

RESEARCH

*******************SALES

SALES

**********OPERATIONS

OPERATIONS


RPAD(kolonlsabit,n,’karakter dizisi’) : Parametre olarak verilen kolon ya da sabitin
sonuna n adet istenilen karakter dizisinden basar. Eğer karakter dizisi verilmez ise boşluk ekler.

SELECT LPAD(DNAME,20,’*’),LPAD(DNAME, 15) FROM DEPT;

RPAD(DNAME,20,’*’)

RPAD(DNAME,15)

ACCOUNTING**********

ACCOUNTING

RESEARCH************

RESEARCH

SALES******************

SALES

OPERATIONS**********

OPERATIONS

    SUBSTR(kolonlsabit,poz,n) : Verilen kolon yada sabit karakter dizisinin istenilen
pozisyonundan başlayarak n adet karakteri geritir.

SELECT SUBSTR(‘Cengiz Çakmak’,4,3) FROM DUAL;

INSTR(kolonlsabit1’karakter dizisi’) : Verilen kolon ya da sabit karakter dizisi
içerisinde istenilen karakter ya da karakter dizisinin ilk
geçtiği konumu döndürür.

L TRIM(kolonlsabit,’karakter dizisi’) : Istenilen karakteri ya da istenilen karakterleri
verilen kolon ya da sabit karakter dizisinin başından siler. Dizinin başında yer alan silinecek karakter ard arda
yer aldığı sürece silinir. Eğer hiçbir karakter verilmez ise dizinin başındaki boşluklar silinir.

RTRIM(kolonlsabit,’karakter dizisi’) : L TRIM ile aynı işlemi yapar; tek farkı islenilen
karakteri (ya da karakterler) dizinin sonundan siler.

LENGTH(kolonlsabit) : Verilen karakter dizisinin toplam kaç karakter uzunlukta
olduğunu döndürür.

TRANSLATE(kolonlsabit1eski,yeni) : Verilen karakter dizisi içerisinde ‘eski’
parametresi olarak girilecek karakterleri bularak ‘yeni’ olarak girilecek olan karakterler ile yer değiştirir.

Sayısal Fonksiyonlar
Sayısal fonksiyonlar sayısal değerleri parametre olarak alır ve yine sayısal değerler üretirler.

ROUND(kolonlsabit,n) : Verilen değeri virgülden sonra n basamağını dikkate
alarak yuvarlar. Eğer n değeri negatif girilirse virgülün soluna kalan n adet rakam yuvarlanır.

ROUND(45.923,1) –> 45,9
ROUND(45.923) –> 46
ROUND(45.923,1) –> 45,3
ROUND(42.323,-1) –> 40

TRUNC(kolonlsabit,n) : Virgülden sonraki n basamak sıfırlanır. Eğer n değeri
negatif girilirse virgülün solunda kalan n adet rakam sıfırlanır.

CEIL(kolonlsabit) : Verilen değerden büyük en yakın tamsayıyı döndürür.

FLOOR(kolonlsabit) : Verilen değerden küçük en yakın tamsayıyı döndürür.

POWER(kolonlsabit,n) : Verilen değerin n’inci kuvvetini alır.

SQRT(konlsabit) : Verilen değerin kare kökünü bulur.

SIGN(kolonlsabit) : Eğer verilen değer 0 ise 0, negatif ise -1 , pozitif ise +1 değeri döndürür.

ABS(kolonlsabit) : Verilen değerin mutlak değerini döndürür.

MOD(d1 ,d2) : d1 ‘in d2’ye bölümü sonucu oluşan kalan değerini döndürür .

Tarih Fonksiyonları     Oracle DA TE türünde tanımlanmış alanlar içerisinde saniye düzeyine kadar tarih bilgisini saklayabilir. Fakat giriş ve çıkıŞ sırasında tarih formatı ayarlanarak bu detayda bilgi girişine gerek duyulmadan tarih bilgisi
üzerinde istenilen işlemler yapılabilir.

Tarih : Yüzyıl, Yıl, Ay, Gün, Saat, Dakika, Saniye,

Oracle veri tabanının başlanğıç olarak kullandığı tarih formatı (değiştirilmediği sürece) DD-MON-YY şeklindedir.
Eğer veri tabanı türkçe modunda çalıştırılıyorsa ayların kısaltmaları türkçe olarak yapılacaktır (MA YIS : MAY,
HAZIRAN : HAZ gibi).

Veri tabanından sistem tarihini de okumak aşağıdaki SQL sorgusu ile mümkündür.

SELECT SYSDATE FROM SYSTEM.DUAL;

Bu sorgu DUAL isimli sahte bir tablo kullanarak o andaki sistem tarihini okumamızı sağlamaktadır.

Tarih üzerinde aritmetik işlemler
tarih+sayı : Tarihe istenilen gün sayısı eklenir.
tarih-sayı : Tarihten istenilen gün sayısı çıkartılır.
tarih1-tarih2 : Iki tarih arasındaki gün sayısını bulunur
tarih+sayıl24 : Istenilen saat sayısını tarihe eklenir.

MONTHS_BETWEEN(tarih1,tarih2) : Iki tarih arasında kaç ay olduğunu hesaplar. Eğer tarih2 tarih1 ‘den daha büyükse sonuç negatif olarak üretilir.

ADD_MONTHS(tarih,n) : Istenilen tarihe n ay ekler.

NEXT_DAY(tarih,gün) : Verilen tarihten bir sonraki haftanın istenilen gününün tarihini döndürür. Girilen gün bir numara yada günün adı olabilir. ‘FRIDAV’ ve 6 aynı günü ifade eder. Günler pazar gününden itibaren sayılmaya başlanır. Omeğin pazartesi günü için 2 girilmelidir.

LAST_DAY(tarih) : Girilen tarihin ayının son gününün tarihini döndürür.

ROUND(tarih) : Girilen tarihin saat kısmını yuvarlar. Bu genelde saat bilgisi içeren tarihlerin arşılaştırılmasında faydalı olur.

ROUND(tarih,’MONTH’) : Girilen tarihi ay bilgisine kadar yuvarlar. Ayın 15’şinden önceki günler ayın ilk gününün tarihini, sonraki günler için sonraki ayın ilk gününün tarihini getirir.

ROUND(tarih,’VEAR’) : Girilen tarihi yıl bazında yuvarlar. Girilen tarih yılın ilk yarısını gösteriyor ise o yılın ilk gününün tarihi geri dönderilir, değilse bir sonraki yılın ilk gününün tarihi döndürülür.
TRUNC(tarih,’MONTH’) : Verilen tarihin ayının ilk gününün tarihini bulur.
TRUNC(tarih,’VEAR’) : Verilen tarihin yılının ilk gününün tarihini bulur.

Dönüştürme Fonksiyonlan

TO_CHAR(sayıltarih,[‘format]) : Verilen rakam ya da tarihi istenilen formatta karaktere dönüştürür.

TO_NUMBER(‘karakterler’) : Karakter türünde verilmiş olan rakamları sayısal türe dönüştürür.

TO_DATE(‘karakter’ ,’format’) : Formatı belirli karakter halindeki bir tarihi tarih türüne dönüştürür.

Tarih Formatlan  (TO_DATE ile kullanılabilen)

ELEMAN

Anlamı

yyyy

Dört Basamaklı Yıl

yyy

Yılın son üç basamağı

yy

Yılın son iki basamağı

Y

Yılın son basamağı

RR

Farklı Dil İçin yılın son iki basamağı

Q

Ocak-Mart i

MM

İki basamaklı ay

RM

Romen rakamı ile ay

MONTH

Ayın uzun ismi

MON

Ayın kısa ismi

ww

Yılın hangi haftası olduğu(1-53)

w

Ayın hangi haftası olduğu(1-5)

DDD

Yılın günü (1-366)

DD

Ayın günü (1-31)

D

Haftanın günü(1-7)

DAY

Günün uzun adı (Pazartesi)

DY

Günün kısa adı (Pzt)

HH

veya Günün saati (1-12)

HH12

Günün saati (1-12)

HH24

Günün Saati (0-23)

MI

Dakika(0-59)

SS

Saniye(0-59)

SSSSS

Gec nraki sagece yarısından sonra saniye sayısı

Ornek : TO-DATE(’27-0CT -95′,’DD-MON-RR’)

Sayı Formatlan

ELEMAN

ÖRNEK

Anlamı

9

9999

Yazılacak sayının uzunluğunu belirler

0

0999

Eğer sayı küçükse boşluk yerine sıfır basar

$

$999

Rakam başına dolar işareti ekler

B

B99999

Sıfır olan sayıları basmaz

S

S9999

Poz. sayıların başına + neg. ise – işareti ekler.

PR

99999PR

Negatif ise <…> şeklinde yazar

D

99D99

Ondalıklı sayıları bu şekilde ayırır

G

9G999

Grup ayrıcını G harfinin olduğu yere basar

C

99999C

Rakamın yanına parabirimi kısaltmasını yazar

L

9999L

Ülke için kullanılan parabirimi kısaltmasını yazar.

,

9,999

istenilen pozisyona virgül basılır

.

999.99

ondalıklı kısımlar nokta ile ayrılır

V

999V99

Gelen sayıyı 10’un n’inci kuvveti ile çarpar. n V harfinden sonraki 9’Iarın sayısıdır.

EEEE

9.999EEEE

8ilimsel olarak yazar

RN yada rn

RN rn

Girilen sayıyı büyük yada küçük romen rakamları ile 1 ile 3999 arası için   yazar.

Değişik türlerde parametre kabul edebilen fonksiyonlar
DECODE     Bu komut ile kolon isimlerini koşullara bağlayarak verilerin durumuna gôre değişik kolon isimlerini seçmek
mümkündür. Yapısal dillerdeki ‘if-then-else’ yapısının ilkel bir ômeğidir.
DECODE(kolon/ifade,ara1,sonuc1,[ara2,sonuc2, …,]default)
SELECT ENAME,JOB,
DECODE(JOB,’CLERK’,’WORKER’,’MANAGER’,’BOSS’,’UNDIFIENED’)
DECODE_JOB FROM EMP

ENAME

JOB

DECODE_JOB

SMITH

CLERK

WORKER

ALLEN

SALESMAN

UNDIFIENED

WARD

SALESMAN

UNDIFIENED

JONES

MANAGER

BOSS

MARTIN

SALESMAN

UNDIFIENED

BLAKE

MANAGER

BOSS

CLARK

MANAGER

BOSS

SCOTT

ANALYST

UNDIFIENED

KING

PRESIDENT

UNDIFIENED

TURNER

SALESMAN

UNDIFIENED

ADAMS

CLERK

WORKER

JAMES

CLERK

WORKER

FORD

ANALYST

UNDIFIENED

MILLER

CLERK

WORKER

14 satırları seçildi.

Grup Fonksiyonlan     Grup fonksiyonları veri tabanından seçilen bir dizi satır üzerinde işlem yapar ve sonuç olarak kendisine
yüklenmiş olan göreve göre özet bir bilgi üretir. AVG([DISTINCTIALL] kolon) : Verilen kolon değerlerinin
ortalamasını bulur.

COUNT([DISTINCTIALL] kolonl*): Verilen kolonun NULL olmayanlarının sayısını getirir. Eğer * kullanılırsa toplam kaç satır sorgulandığı bulunur.

MAX([DISTINCTIALL] kolon) : Maximum değeri getirir.

MIN((DISTINCTIALL] kolon) : Minimum değeri getirir.

SUM([DISTINCTIALL] kolon) : Verilen kolon toplamını bulur.

SELECT COUNT(*) FROM EMP WHERE DEPTNO = 20;

20 numaralı bölümde kaç kişi olduğunu bulur.

GROUP BY ifadesi GROUP BY ifadesi ile sorgulanan satırlar belirli guruplara ayrılarak bu gruplar üzerinde grup fonksiyonları kullanılır.
SELECT JOB,AVG(SAL) FROM EMP
GROUP BY JOB;
J

JOB

AVG(SAL)

ANALYST

3000

CLERK

1037.5

MANAGER

2758.3333

PRESIDENT

5000

SALESMAN

1400


Her iş için ayrı ayrı ne kadar ortalama maaş verildiğini hesaplar.

SELECT DEPTNO,JOB,AVG(SAL) FROM EMP
GROUP BY DEPTNO,JOB;

DEPT NO

JOB

AVG(SAL)

 

10

CLERK

1300

 

10

MANAGER

2450

 

10

PRESIDENT

5000

 

20

ANALYST

3000

 

20

CLERK

950

 

20

MANAGER

2975

 

30

CLERK

950

 

30

MANAGER

2850

 

30

SALESMAN

1400

 

9 satırları seçildi.

Her bölümdeki farklı işler için ne kadar ortalama maaş verildiğini hesaplar. Grup fonksiyonları ile birlikte kullanılan kolon isimleri mutlaka GROUP BY ifadesi içinde yer almalıdır. Tersi durumda hatalı bir SQL cümlesi yazılmış olur.

 


 

© www.cengizcakmak.8m.com 2000. Hazırlayan: Cengiz ÇAKMAK , Kaynak: Osman Nihat ŞEN (ORACLE kitabından)

 

 

 

 

Tabloların Oluşturulması     

 

 

Oluşturulması gereken tablolar ve aralarındaki ilişkiler aşağıda verilmiştir. Ayrıca tabloların üzerine tıklayarak örnek verileri de görebilirsiniz. Tabii ki veriler örnektir. Gerçek bir veritabanında kurum ve personel tabloları yüzbinlerce olabilir. Ayrıca SQL komutunun hızlı çalışabilmesi için birbirleriyle ilişki kurulmuş tablolar indexlenmelidir.
iliskiler.jpg (41033 bytes)
Burada örnek bir veritabanı tasarlanmıştır. Bir kuruluşun ülke çapında yayılmış şuıbeleri olsun. Bu şubelerde çalışan elemanların genel bilgileri ,maaş bilgileri ve hangi bölümde çalıştıklarına ilişkin bilgileri tutmaya çalışalım.
Primary Key Alanlar:
Per_No,Kur_Kodu,Ilce_Kodu,Il_KoduDep_Kodu  (Bu alanlara girilen değerlerin tekrarlanmaması için tanımlanır.)

 

 

 

 

 

 

Ders 1           Il tablosuna gözat (sorgularda kullanılan tablo)

il_kodu

il_adi

1

Adana

2

Adıyaman

3

Afyon

4

Ağrı

5

Amasya

6

Ankara

7

Antalya

8

Artvin

9

Aydın

10

Balıkesir

 

 

 

Basit SQL Cümleleri

 

Mevcut bir tablodan istenilen şartları sağlayan kayıtların seçilmesi için SELECT kullanılabilir.
Genel Kullanım Şekli:
SELECT [Tablodan istenen alan isimlerinin yazılacağı bölüm]
FROM [Verilerin bulunduğu tablo isimlerinin yeraldığı bölüm]
WHERE [Koşul Yazılacak bölüm]
GROUP BY [Kayıtları gruplayıp getirmek için kulanılacak cümlecik]
HAVING [Grup bulunan SQL cümleciklerinde grup içinde şart kullanmak için]
ORDER BY Kayıtlarının sıralanması için kullanılacak bölüm]

Bu cümleciğe şu soruları sormamız mümkündür;
SELECT (Hangi alanları ?)
FROM (Hangi tablo ya da tablolardan)
WHERE (Hangi şartlarda ?)
GROUP BY (Nasıl bir gruplama ?)
ORDER BY (Hangi sırada ?)

Öncelikle bir tablonun yapısını görmek için;
DESC il;
İsim     Null?       Tip
—-    ——— —-
IL_KODU            NUMBER(2)
IL_ADI               VARCHAR2(14)


Bu bilgiler ışığında basit bir SQL cümlesiyle işe başlayabiliriz.
SELECT * FROM IL;
IL tablosundan tüm alanları getir..

IL_KODU IL_ADI
———- ————–
1 Adana
2 Adıyaman
3 Afyon
4 Ağrı
5 Amasya
6 Ankara
7 Antalya
8 Artvin
9 Aydın
10 Balıkesir

10 satırları seçildi.

SELECT IL_ADI FROM IL;
Personel tablosundan tüm kayıtların perno,adı ve soyadı alanlarını listele..

IL_ADI
————–
Adana
Adıyaman
Afyon
Ağrı
Amasya
Ankara
Antalya
Artvin
Aydın
Balıkesir

10 satırları seçildi.

Sorguda koşul vermek gerektiğinde bir takım karşılaştırmalar yapmamız gerekir. Karşılaştırma işlemine geçmeden önce karşılaştırma operatörlerini bir inceleyelim. Sorguda istediğiniz koşulu aşağıda görülen operatörlerle yapabiliriz.

=        :eşit
>        :Büyük
>=      :Büyük eşit
<        :Küçük
<=      :Küçük eşit
!=       :Farklı

Şimdi de IL tablosundan belli koşullara uyan kayıtları listelemeye çalışalım;
SELECT * FROM IL WHERE IL_KODU=6;

IL_KODU IL_ADI
———- ——
6 Ankara

SELECT * FROM IL WHERE IL_KODU<5; Il tablosundan il_kodu 5 ten küçük kayıtlar seçildi

IL_KODU IL_ADI
——— ——–
1 Adana
2 Adıyaman
3 Afyon
4 Ağrı

SELECT * FROM IL WHERE IL_KODU<5; Il tablosundan il_kodu 5 veya 5 ten küçük kayıtlar seçildi

IL_KODU IL_ADI
———- ——–
1 Adana
2 Adıyaman
3 Afyon
4 Ağrı
5 Amasya

SELECT * FROM IL WHERE IL_KODU!=5; Il tablosundan il_kodu 5 ten farklı olan kayıtları listele..

IL_KODU IL_ADI
——— ———-
1 Adana
2 Adıyaman
3 Afyon
4 Ağrı
6 Ankara
7 Antalya
8 Artvin
9 Aydın
10 Balıkesir

Where cümleceğinden sonra koşul bir tane olmak zorunda değildir. Koşul sayısını artırabiliriz. Ancak kullanılacak koşullar arasında mantıksal bir bağlaç olması gerekir. Bunlar;
AND       : Koşulun sağlanması için şartlardan ikisinin de sağlanması gerekir.
OR          : Koşulun sağlanması için şartlardan yalnız birinin sağlanması yeterlidir.

SELECT * FROM il WHERE Il_kodu=5 AND il_kodu=7;

Bu sorguda ben Il_kodu 5 ve 7 olan kayıtları listele dedim ama sonuçte hiç bir kayıt dönmeyecektir. Çünkü Il_kodu hem 5 hem de 7 olan hiç bir kayıt yoktur.

SELECT per_no,per_adi,per_soyadi FROM personel WHERE per_adi=’ALİ’ AND per_departman=’SATIŞ’;

Burada ise kişinin adı ALİ olacak ve departmanı SATIŞ olacak. Yani Satış departmanında çalışan ALİ ‘leri listeleyen bir sorgu.

SELECT * FROM il WHERE il_kodu=5 OR il_kodu=7;

IL_KODU IL_ADI
———- ——-
7 Antalya
5 Amasya

Il_kodu 5 olan VEYA il_kodu 7 olan kayıtları listele ifadesini kullandığımda ise hem 5 hem 7  olan kayıtları listeledi.

Oracle SQL Plus’ta koşul hanesinde eğer string bir alan karşılaştırılacaksa ; sabit ifadeleri tek tırnak içinde belirtmeliyiz.

SELECT * FROM il WHERE il_adi=’ANKARA’; gibi..

WHERE şart cümleciği içinde yukarıdaki karşılaştırma operatörlerini kullanabildiğimiz gibi ayrıca operatörlerden de söz edebiliriz

BETWEEN a1 AND a2         :a1 ve a2 arasındaki kayıtlar
NOT BETWEEN a1 AND a2 :a1 ve a2 arasında olmayan kayıtlar
IN(a1,a2,a3,…)               : Listede belirtilen herhangi bir değeri içeren kayıtlar
NOT IN(liste)                   : Listede belirtilen herhangi bir değeri içermeyen kayıtlar
LIKE                               :Karakter ifadelerde alan içeriğinin bir bölümünü sağlayan kayıtlar
NOT LIKE                        :Karakter ifadelerde alan içeriğinin bir bölümünü sağlamayan kayıtlar
IS NULL                          :Boş olan kayıtlar
IS NOT NULL                    :Boş olmayan kayıtlar

SELECT * FROM il WHERE il_kodu BETWEEN 3 AND 7;

IL_KODU IL_ADI
———- ——–
3 Afyon
4 Ağrı
5 Amasya
6 Ankara
7 Antalya

SELECT * FROM il WHERE il_kodu NOT BETWEEN 3 AND 7;

IL_KODU IL_ADI
——— ———-
1 Adana
2 Adıyaman
8 Artvin
9 Aydın
10 Balıkesir

SELECT * FROM il WHERE il_kodu IN(3,5,8,105);

IL_KODU IL_ADI
———- ——-
3 Afyon
5 Amasya
8 Artvin

SELECT * FROM il WHERE il_kodu NOT IN(3,5,8,105);

IL_KODU IL_ADI
———- ————–
1 Adana
2 Adıyaman
4 Ağrı
6 Ankara
7 Antalya
9 Aydın
10 Balıkesir

LIKE Karakter alan içinde bulunan değerin yalnızca bir kısmını sorgulamak için kullanılır. Burada  % ifadesi de genelde kullanılır. Büyük küçük harf ayrımı yapılacağından sorgu yazılırken buna dikkat edilmesi gerekir. Eğer Access kullanılıyorsanız % yerine * kullanmalısınız. Ayrıca string ifadeleri  tek tırnak içine değil çift tırnak içine almalısınız.

SELECT * FROM il WHERE il_adi LIKE “A*”; il_adi A ile başlayan kayıtlar. (Access için)

SELECT * FROM il WHERE il_adi LIKE ‘A%’; il_adi A ile başlayan kayıtlar.

IL_KODU IL_ADI
———- ——–
1 Adana
2 Adıyaman
3 Afyon
4 Ağrı
5 Amasya
6 Ankara
7 Antalya
8 Artvin
9 Aydın

SELECT * FROM il WHERE il_adi LIKE ‘%a’; il_adi a ile biten  kayıtlar.

IL_KODU IL_ADI
——- ——-
1 Adana
5 Amasya
6 Ankara
7 Antalya

SELECT * FROM il WHERE il_adi LIKE ‘%s%’; il_adi içinde s harfi geçenler

IL_KODU IL_ADI
——– ———
5 Amasya
10 Balıkesir

 

 

 

 

 

 

 

 

 

 

 

 

 

Ders 2          

 

personel, kurum,departman tablolarına gözat

personel

per_no

per_adi

per_soyadi

per_kurum_kodu

40651092

MEHMET

AKYÜREK

111943

46404046

FATMA

ŞAHİN-ONAY

111943

48693196

İHSAN

ATEŞ

111918

49691388

AKGÜL

YILMAZ

111918

49696089

ABDULLAH

ESER

111943

50643261

MEHMET İHSAN

PEKMEZOĞLU

111918

64697143

ARİF

EFE

111906

41941157

AYSEL

KAYGUN

268532

42691389

KOCA

ŞİRİN

111607

43241232

OSMAN

KARAPINAR

111715

43691338

BEKİR

AYDIN

280543

43695150

MUSTAFA

DÜLDÜL

374215

43911080

MEHMET EMİN

ÇOKAN

473392

44557104

MUSTAFA

ÖZLÜ

473487

44691441

MEHMET

KARAMAN

244170

44691443

MUSA KAZIM

ÖRNEK

111656

44731206

SEVGİ GÜLŞEN

ÖNDERLİ

111597

45696146

MEHMET

YILDIZ

111607

45833157

ŞAHMAN

YILDIRIM

444123

45836109

HALİL

YILDIZ

113680

46661279

ZEYNEL

BUTEV

443703

46697250

ABDİ

TOPAKTAŞ

443715

46833136

İMAM

ERDOĞDU

211562

47506028

GÜLTEN

TURHAN

111835

47696097

SADULLAH

KARTAL

111872

47835108

ALİ

AYATA

268532

47849033

OSMAN

DENİZ

443715

47922026

AHMET

BİNARDAN

246886

48566170

ZEKİ

TORAMAN

473152

48703024

OSMAN

YAPÇA

336860

49696114

TASİN

GÜNGÖR

342828

49697408

KEMAL

AKTAŞ

215822

49702033

MUSTAFA

DÜNDAR

113680

49844045

M.EMİN

ÖNER

270814

49882068

HAYDAR

TEKİN

111668

49997023

ÖMER

DEMİRCAN

473259

50580089

YUSUF

DOĞANER

270814

50691303

HAMZA

KURTOĞLU

111668

50691638

SALİH

OBA

444123

50694061

CEZMİ

KIZILKAYA

111872

50697508

OSMAN

ÇOŞKUNOĞLU

111752

50697512

MEHMET

GÖZÜKARA

111536

50697537

RAHİME

KARAKUŞ

443703

50896193

MAHMUT

DAYIKARACA

352006

51354054

HANİFE

ÇAPÇI

790157

51580060

BEKIR

KELEŞER

270814

51691471

HANDAN

TATLI

111656

51691597

ESİN

CANAK

374107

51691640

KEMAL

KALKAN

111536

51693200

OSMAN

OZAN

113680

 

 

 

 

 

 

 

Kurum

 

 

kur_kodu  

kur_ilce_kodu  

kur_adi

111918  

100  

İl Milli Eğitim Müdürlüğü

111906  

100  

İl Eğitim Araçları ve Donatım Merkezi(ASO)

111943  

100  

Sağlık Eğitim Merkezi

733321  

101  

Süreyya Nihat Oral İlköğretim Okulu

323158  

101  

Adasokağı Lisesi

816584  

101  

Oğuz Kağan Köksal Görme Engelliler ilköğ.O

817959  

101  

Bahçeşehir İlköğretim Okulu

818894  

101  

Cumhuriyet Anaokulu

846449  

101  

Seyhan İlköğretim Okulu

846425  

101  

Yenişehir İlköğretim Okulu

846437  

101  

2000 Evler İlköğretim Okulu

320703  

101  

Şakirpaşa Lisesi

348168  

102  

Öğretmen Evi

375149  

102  

Büyüksofulu İlköğretim Okulu

337147  

102  

Sinanpaşa İlköğretim Okulu

337302  

102  

Akören İlköğretim Okulu

214088  

102  

Halk Eğitim Merkezi

111955  

102  

İlçe Milli Eğitim Müdürlüğü

428712  

104  

Kurtkulağı Orhanekinci İlköğretim Okulu

428773  

104  

Besocak İlköğretim Okulu

428797  

104  

Ataturk İlköğretim Okulu

428819  

104  

Ayse Malaz İlköğretim Okulu

428832  

104  

Fevzı Cakmak İlköğretim Okulu

428820  

104  

Dumlupınar İlköğretim Okulu

442710  

106  

Tortulu Ziyelli İlköğretim Okulu

442709  

106  

Yerebakan İlköğretim Okulu

442663  

106  

Tokmanaklı İlköğretim Okulu

442651  

106  

Sahmuratlı İlköğretim Okulu

442161  

106  

Çandırlar-Bekirhacılı İlköğretim Okulu

442053  

106  

Akkaya İlköğretim Okulu

441993  

106  

Belenköy İlköğretim Okulu

442041  

106  

Akoluk İlköğretim Okulu

790001  

107  

OTLUK İLKÖĞRETİM OKULU

790050  

107  

Ü.ORTAEĞRİÇAM İLKÖĞRETİM OKULU

790108  

107  

ALAYBEYİ İLKÖĞRETİM OKULU

337255  

107  

Mehmet Akif İlköğretim Okulu

374264  

107  

Cumhuriyet İlköğretim Okulu

322883  

107  

İmamoğlu Çok Programlı Lisesi

826526  

107  

Hürriyet İlköğretim Okulu

392081  

109  

Örcün İlköğretim Okulu

392093  

109  

Çevlik İlköğretim Okulu

 

 

 

 

 

 

 

 

Depertman

 

 

 

 

 

 

 

 

Dep Kodu

Dep Adi

 

 

1

Muhasebe

 

 

2

Satış

 

 

3

İnsan Kaynakları

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Alan (Sütun Birleştirmek ve sütunlara isim vermek)

 

Liste alırken bazı alanları birleşik olarak almanız gerekebilir. Personel Tablomuzda kişinin adı ve soyadı farklı alanlarda kayıtlı ve biz bu iki alanı birleşik almak istiyoruzbu durumda || (pipe) ifadesini kullanmalıyız.

SELECT per_no,per_adi||per_soyadi from personel where per_kurum_kodu=111918;

PER_NO

PER_ADI||PER_SOYADI

48693196

İHSANATEŞ

49691388

AKGÜLYILMAZ

50643261

MEHMETPEKMEZOĞLU

Yalnız burada isim ve soyad arasında boşluk eklemediğimiz için isim soyadı birleşik yazdı. Aynı mantıkla boşluğu da ekleyebiliriz.(tek tırnak içerisinde iki adet boşluk)

SELECT per_no,per_adi||’   ‘||per_soyadi from personel where per_kurum_kodu=111918;

PER_NO

PER_ADI||”||PER_SOYADI

48693196

İHSAN ATEŞ

49691388

AKGÜL YILMAZ

50643261

MEHMET  PEKMEZOĞLU

Şimdi oldu yalnız bir problemimiz daha var liste başlığının kötü görüntüsü onu da aşağıdaki şekilde çözebiliriz. (Sütunlara isim tanımlama)

SELECT per_no,per_adi||’   ‘||per_soyadi AdSoyad from personel where per_kurum_kodu=111918;

PER_NO

ADSOYAD

48693196

İHSAN ATEŞ

49691388

AKGÜL YILMAZ

50643261

MEHMET  PEKMEZOĞLU

İki alanı birleştirmek zorunda değiliz sabit bir ifadeyi de ekleyebiliriz.

SELECT il_kodu,il_adi||’  ‘||’Kenti’ FROM il WHERE il_kodu<6;

IL_KODU

IL_ADI||”||’KENTI’

1

Adana Kenti

2

Adıyaman Kenti

3

Afyon Kenti

4

Ağrı Kenti

5

Amasya Kenti

 

 

Birden fazla tablo ile Sorgu Yazmak

 

İlişkisel veritabanlarında, tablolara en hızlı ulaşım ve verilerin az yer kaplaması düşünülerek tasarım yapılır. Bu anlamda biz de tablo tasarımlarımızı bu ölçülere dikkat ederek yapmaya çalıştık. Verilen örnek veri tablolarında personel ile kurum dikkate alınacak olursa;
Personel tablosunda per_no,per_adi,per_soyadi,per_kuurum_kodu yer alıyor. Kurum adı değil kurum kodu yer alıyor. Peki neden ?

PER_NO

PER_ADI

PER_SOYADI

PER_KURUM_KODU

48693196

İHSAN

ATEŞ

111918

49691388

AKGÜL

YILMAZ

111918

50643261

MEHMET

PEKMEZOĞLU

111918

111918 koduna sahip kurumda üç kişi çalışıyor. Bu sayı tabii ki gerçek bir veritabanında yüzlerce olabilir. Eğer biz personel tablosuna kurum kodu değil de kurum adını girseydik her personel için bir kurum adı hanesi yer alacaktı ve aşağıda görüldüğü gibi personel başına kurum adi için ‘İl Milli Eğitim Müdürlüğü’ veri girilecekti ve toplam 25 Byte ‘lık bir yer gerekecekti. Oysa biz personel tablosuna kurum adı yerine kurum kodu girerek 4 byte ile bu veriyi ifade edebiliyoruz.

KUR_KODU

KUR_ILCE_KODU

KUR_ADI

111918

100

İl Milli Eğitim Müdürlüğü

111906

100

İl Eğitim Araçları ve Donatım Merkezi(ASO)

111943

100

Sağlık Eğitim Merkezi

Peki bu durumda biz personelin çalıştığı kurumu görüntülemek istersek ne yapmalıyız ? İşte bu durumda SQL yazarken birden fazla tablodan yararlanmak zorundayız. Yukarıda görülen personel tablosundaki per_kurum_kodu ile kurum tablosundaki kur_kodu alanları bağlantı alanlarıdır. SQL yazarken bu iki alanı join etmeliyiz;

SELECT per_no,per_adi,per_soyadi,kur_adi
FROM personel,kurum
WHERE per_kurum_kodu=kur_kodu and kur_kodu=111918;

PER_NO

PER_ADI

PER_SOYADI

KUR_ADI

48693196

İHSAN

ATEŞ

İl Milli Eğitim Müdürlüğü

49691388

AKGÜL

YILMAZ

İl Milli Eğitim Müdürlüğü

50643261

MEHMET

İHSAN PEKMEZOĞLU

İl Milli Eğitim Müdürlüğü

Select :Personel tablosundan per_no,per_adi,per_soyadi ve kurum tablosundan kur_adi listelenecek alanlar..
From :personel,kurum tablosundan alınacak..
Where: per_kurum_kodu=kur_kodu na eşitse  ve per_kurum_kodu=111918 ise..

Burada ilk bağlantılı bir SQL komutunu gerçekleştirmiş olduk.

Birleştirilecek tablo sayısı ikiden çok (örneğin onlarca) olabilir. Yukarıda personelin çalıştığı kurumu görüntülrmiştik. Departman tablomuzla da bağlayarak kişilerin çalıştığı bölümü de görüntüleyelim.

SELECT
per_no,per_adi,per_soyadi,dep_adi,kur_adi
FROM

personel,departman,kurum
WHERE

per_departman=dep_kodu and
per_kurum_kodu=kur_kodu and
kur_kodu=111918;

PER_NO

PER_ADI

PER_SOYADI

DEP_ADI

KUR_ADI

48693196

İHSAN

ATEŞ

Satış

İl Milli Eğitim Müdürlüğü

50643261

MEHMET

PEKMEZOĞLU

Satış

İl Milli Eğitim Müdürlüğü

49691388

AKGÜL

YILMAZ

İnsan Kaynakları

İl Milli Eğitim Müdürlüğü

Personellerimizin maaşları da MAAS isimli bir tabloda tutuluyor. Bu tabloda primary key olmayacak çünkü bir personelin her hay aldığı maaş bu tabloya yazılacak. Yani bir yıl için düşünülecek olursa bir kişiye ait 12 adet kayıt bu tabloda yer alacatır. Biz bu tür ilişkilere master-detail diyoruz. Burada master personel tablosu detail ise maas tablosudur. Bu durumda bir kişiye ait maaş dökümlerini almak istediğimizde personel ve maaş tablolarını kullanmak suretiyle aşağıdaki SQL cümleciğini yazabiliriz.

SELECT per_no,per_adi,per_soyadi,maas_ay,maas
FROM personel,maas
WHERE per_no=maas_kodu and per_no=48693196;

PER_NO

PER_ADI

PER_SOYADI

MAAS_AY

MAAS

48693196

İHSAN

ATEŞ

1

26000

48693196

İHSAN

ATEŞ

2

27000

48693196

İHSAN

ATEŞ

3

33000

48693196

İHSAN

ATEŞ

4

2000

Yukarıda görüldüğü gibi maaş tablosunda ilgili kişiye ait 4 adet kayıt olduğundan 4 kayıt görüntülendi. Maaş tablosunda kişinin hangi ayda ne kadar ücret aldığı belli ancak ayların ismi değil kaçıncı ay olduğu görünüyor. Ağer ayların ismini de görüntülemek için aylar isimli tabloyu da kullanmalıyız.

SELECT per_no,per_adi,per_soyadi,ay_adi,maas
FROM personel,aylar,maas
WHERE per_no=maas_kodu and

maas_ay=ay_kodu and
per_no=48693196;

PER_NO

PER_ADI

PER_SOYADI

AY_ADI

MAAS

48693196

İHSAN

ATEŞ

Ocak

26000

48693196

İHSAN

ATEŞ

Şubat

27000

48693196

İHSAN

ATEŞ

Mart

33000

48693196

İHSAN

ATEŞ

Nisan

2000

devam edecek…

Prolog – 3

Tablo 7.3: Liste eşleştirme örnekleri

Liste 1

Liste 2

Değişken eşleştirme

[X, Y, Z]

[kedi, eti, yedi]

X=kedi, Y=eti, Z=yedi

[7]

[X | Y]

X=7, Y=[]

[1, 2, 3, 4]

[X, Y | Z]

X=1, Y=2, Z=[3,4]

[1, 2]

[3 | X]

Yanlış (Neden?)

7.2.4. Listelerin Kullanılması

Listeler gerçek anlamda rekursiv bileşik veri yapıları olduklarından bunların kullanılmaları için rekursiv algoritmaların kullanılması gerekir. Liste işlemesinin en temel yöntemi, listenin son elemanına ulaşıncaya kadar listenin her elemanını incelemektir. Bu tür işlemde kullanılması gereken algoritmalar genelde iki cümleden oluşurlar. Bir cümle, baş ve kuyruk olarak ikiye bölünebilen listeler için, ikincisi ise boş listeler için kullanılır.

Örneğin aşağıdaki programda bir listenin elemanlarını nasıl görüntüleyeceğimizi görelim:

DOMAINS

benim_listem = string*

PREDICATES

benim_listemi_yaz(benim_listem)

CLAUSES

benim_listemi_yaz ([]).                /*Liste boş ise yapılacak bir şey yok.*/

benim_listemi_yaz ([Bas|Kuyruk]):-write(Bas), nl,

benim_listemi_yaz (Kuyruk).

GOAL benim_listemi_yaz([“Visual”, “Prolog”, “4.0”]). 

Bu programdaki benim_listemi_yaz ([“Visual”, “Prolog”, “4.0”] sorgusuyla Bas=”Visual”, Kuyruk=[“Prolog”,”4.0″] değerlerini alır ve Visual değeri yazılır. Daha sonra benim_listemi_yaz yüklemi rekursiv olduğu için [“Prolog”, “4.0”] kısmı yeniden bölünür. Bu kez Bas=Prolog, Kuyruk=4.0 olur ve Prolog değeri görüntülenir. Rekursiv işlem bir kez daha “4.0” için uygulanır ve bu defa Bas=4.0, Kuyruk=[] olur. Kuyruk kısmı boş liste olduğundan sadece 4.0 görüntülenir. Rekursiv çağrı bu kez boş liste için yapılır, fakat listenin Baş ve Kuyruk kısımlarının eşleşebilecekleri değer olmadığından, program akışındaki benim_listemi_yaz([]) cümlesi çağrılır ve program bir şey yapmadan normal şekilde durur. benim_listemi_yaz ([]) şeklindeki cümle, programın normal bir biçimde durmasını sağlar.

7.2.5. Liste Elemanlarının Sayılması

Bir listenin kaç elemandan oluştuğunu nasıl bulabiliriz? Bunun için kullanılması gereken temel mantık şudur.

Liste boş [] ise, listedeki toplam eleman sayısı 0’dır.

Bunun dışındaki listelerin eleman sayısı 1+ Kuyruk Uzunluğu ile bulanabilir. Prolog’da karşılığı aşağıda verilmiştir.

DOMAINS

liste=integer*

PREDICATES

liste_uzunlugu(liste, integer)

CLAUSES

liste_uzunlugu([], 0).

liste_uzunlugu([_|Kuyruk],Eleman_sayisi):-liste_uzunlugu(Kuyruk, Kuyruk_uzunlugu),

Eleman_sayisi=Kuyruk_uzunlugu+1.

GOAL liste_uzunlugu([1, 2, 3], Eleman_sayisi).

İlk cümledeki [_|Kuyruk] boş olmayan bütün listelerle eşleşebilir. Bizim için önemli olan kısım listenin kuyruk kısmı olduğu için baş kısmı yerine anonim değişken kullanılmıştır.

GOAL liste_uzunlugu([1, 2, 3], Eleman_sayisi).

sorgusu ikinci cümle ile eşleşir ve Kuyruk=[2, 3] olur. Daha sonraki adım Kuyruk uzunluğunu hesaplamaktır. Bu yapıldığı zaman Kuyruk=2 olur. Uzunluk=kuyruk_uzunluğu+1 olduğundan Uzunluk=3 olur.

Liste_uzunlugu yüklemi kendisini çağırarak [2, 3] listesinin uzunluğunu bulur. Bunun için

·       Cümledeki kuyruk=[3] değerini alır.

·       Kuyruk_uzunlugu=Eleman_sayisi değerini alır.

Her rekursiv cümlenin kendisine ait değişken kümesi olduğundan, cümledeki kuyruk_uzunlugu ve sorgudaki kuyruk_uzunlugu birbirine karışmadığı unutulmamalıdır.

Bu durumda bütün mesele [3] uzunluğunu bulmaktır. Bu 1 olduğu için buna 1 ilave edilirse [2, 3] için toplam uzunluk 2 olur. [3] listesinin uzunluğu için liste_uzunlugu yüklemi kendisin tekrar çağırır. Bu kez [3] listesinin kuyruk uzunluğu Kuyruk=[] olur. Kuyruk uzunluğunu hesaplamak için ise liste_uzunlugu([], Kuyruk_uzunlugu) ilk cümle ile eşleşir ve Kuyruk_uzunlugu=0 olur. Şimdi bilgisayar bu değere, yani 0’a 1 ilave ederek [3]’ün uzunluğunu bulur. Buna 1 ilave ederek [2, 3]’ün uzunluğunu bulur. Nihayet buna da 1 ilave ederek [1, 2, 3] listesinin toplam uzunluğunu bulur.

Şimdi bu işlemlerin tamamını sıralayarak konuyu biraz daha netleştirelim.

Liste_uzunlugu([1, 2, 3], Eleman_sayisi1).

Liste_uzunlugu([2, 3], Eleman_sayisi2).

Liste_uzunlugu([3], Eleman_sayisi3).

Liste_uzunlugu([], 0).

L3=0+1=1

L2=L3+1=2

L1=L2+1=3

7.2. Sondan Rekursiyona Yeniden Bakış

Rekursiv bir çağrı, cümledeki son adım olamayacağı için liste_uzunlugu’nun sondan rekursiv olamayacağı bellidir. Bunu sondan rekursiv yapmanın yolu vardır.

Burada problem olan şey, kuyruk uzunluğu bilinmeden bir listenin toplam uzunluğunun hesaplanamayışıdır. Yani bu probleme bir çözüm bulunabilirse, liste_uzunlugu yüklemini sondan rekursiv yapmak mümkündür. Bunun için liste_uzunlugu yükleminin üç argümanının olması gerekir.

1.     Birincisi, her seferinde kırpılarak sonunda boş bir liste elde edilecek listenin kendisi.

2.     Bir diğeri, liste uzunluğunu saklayacak boş bir değişken

3.     Sonuncusu ise 0 ile başlayan ve her seferinde değerinin 1 arttığı bir sayaç değişken.

Geriye sadece boş olan liste kaldığı zaman bu sayaç hiçbir değişkene atanmamış olan sonucu alır.

DOMAINS

liste=integer*

PREDICATES

liste_uzunlugu(liste, integer, integer)

CLAUSES

liste_uzunlugu([], Sonuc, Sonuc).

liste_uzunlugu([_|Kuyruk], Sonuc, Sayac):-

Yeni_sayac=Sayac+1,

liste_uzunlugu(Kuyruk, Sonuc, Yeni_Sayac).

GOAL liste_uzunlugu([1, 2, 3], Uzunluk, 0), write (“Uzunluk =”, Uzunluk), nl.

Verilen bir listedeki elemanlar üzerinde işlem yaptıktan sonra bu elemanların yerine hesaplanan elemanlardan oluşan başka bir liste oluşturmak mümkündür. Aşağıdaki örnekte listenin her elemanını 1 ilave ederek yeni bir liste elde edilmiştir.

DOMAINS

liste = integer*

PREDICATES

yeni_deger_ilave_et(liste, liste)

CLAUSES

yeni_deger_ilave_et([], []).  /* İlk şart*/

yeni_deger_ilave_et([Bas|Kuyruk],[Bas1|Kuyruk1]):- /* Bas ve Kuyruk ayrılması*/

Bas1=Bas+1,            /* Listenin ilk elemanına 1 ilave et*/

yeni_deger_ilave_et(Kuyruk, Kuyruk1).  /* elemanı listenin geriye kalanıyla çağır*/

GOAL yeni_deger_ilave_et([1, 2, 3], Yeni_Liste).

Yukarıda yapılan işlemler, sözel olarak aşağadaki şekilde yazılır.

Boş bir listenin bütün elemanlarına 1 ilave etmek için sadece başka bir boş liste oluştur.

Boş olmayan herhangi bir listenin bütün elemanlarına 1 ilave etmek için, listenin baş kısmına 1 ilave et ve ilave edilen bu değeri yeni listenin başı olarak al. Daha sonra kuyruk kısmının bütün elemanlarına 1 ilave et ve yeni değerleri de yeni listenin kuyruk kısmı olarak al. Sonucu Yeni_liste olarak ekranda görüntüle.

Verilen liste [1, 2, 3] olduğu için:

1.     Önce Baş ve Kuyruk kısımları ayrılır ve sırasıyla [1] ve [2, 3] olurlar.

2.     Sonuç listenin baş ve kuyruk kısımlarına Bas1 ve Kuyruk1 değerlerini ata. Burada Bas1 ve Kuyruk1’in henüz değer almadığına dikkat edilmelidir.

3.     Bas kısmına 1 ilave et ve Bas1’i elde et.

4.     Rekursiv olarak Kuyruk kısmındaki bütün elemanlara 1 ilave et ve Kuyruk1’i elde et.

Bu yapıldığı zaman Bas1 ve Kuyruk1 kendiliğinden sonuç listesinin Bas ve Kuyruk kısmı olur. Bunları birleştirmek için ayrı bir operasyon gerekmez. Dolayısıyla rekursiv çağrı gerçekten de prosedürün son adımı durumundadır.

Örnek:

Bir listedeki sayıları tarayıp negatif olanları eleyen program

DOMAINS

liste=integer*

PREDICATES

negatifleri_ele(liste, liste)

CLAUSES

negatifleri_ele([], []).

negatifleri_ele([Bas|Kuyruk], IslenmisKuyruk):-

Bas<0, !, negatifleri_ele(Kuyruk, IslenmisKuyruk).

negatifleri_ele([Bas|Kuyruk], [Bas|IslenmisKuyruk]):-

negatifleri_ele(Kuyruk, IslenmisKuyruk).

GOAL negatifleri_ele([2, -45, 3, 4, -5, -45], Yeni_Liste).

Aşağıdaki yüklem, bir listenin her elemanını başka bir listeye iki kez aktarmaktadır.

elemanlari_ikile([], []).

elemanlari_ikile([Bas|Kuyruk], [Bas, Bas|Ikilenmis_Kuyruk]):-

elemanlari_ikile(Kuyruk, İkilenmis_Kuyruk).

7.3. Liste Elemanlığı

Ahmet, Mehmet, Hasan ve Nejla isimlerini eleman olarak içeren bir listede, örneğin Ahmet isminin var olup olmadığını öğrenilmek istensin. Yani isim ve bir isim arasında bir ilişki sorgulansın. Bunun için kullanılan bir yüklem vardır.

uye(isim, isimlistesi).  /*Burada ‘isim’ listede geçen bir isimdir.*/

DOMAINS

isim_listesi = isim*

isim = symbol

PREDICATES

nondeterm uye(isim, isim_listesi)

CLAUSES

uye(Isim, [Isim|_]).

uye(Isim, [_|Kuyruk]):- uye(Isim, Kuyruk).

GOAL uye(ahmet, [ mehmet, ahmet, hasan, nejla]).

Yukarıdaki örnekte önce birinci cümleyi inceleyelim. uye(Isim, [Isim|_]) cümlesindeki Isim değişkeni listenin öncelikle baş kısmında araştırılır. Eğer eşleşme sağlanırsa üyeliğin var olduğu sonucuna varılır ve olumlu sonuç görüntülenir. Listenin kuyruk kısmı bizi ilgilendirmediği için burada anonim değişken kullanılmıştır.

Eğer aradığımız isim listenin baş kısmı ile eşleşmezse bu kez listenin kuyruk kısmını incelemek için ikinci cümle kullanılır.

7.4. Listeleri Birleştirme

Aşağıdaki iki cümleyi tekrar inceleyelim. Bu iki cümleye prosedürel ve dekleratif olarak bakmak mümkündür.

uye(Isim, [Isim|_]).

uye(Isim, [_|Kuyruk]):- uye(Isim, Kuyruk).

Bu cümlenin dekleratif olarak anlamı şudur:

Eğer cümlenin baş kısmı Isim değişkenine eşitse, bu durumda Isim, listenin bir elemanıdır. Bu durum doğru değilse, Isım değişkeni kuyruk kısmının üyesi ise Isim listenin bir elemanıdır.

Prosedürel olarak bu iki cümle şöyle yorumlanabilir.

Bir listedeki herhangi bir elemanı bulmak için, listenin baş kısmını; aksi takdirde, bu listenin kuyruk kısmının bir üyesini bulunuz.

Bu iki durumu denemek için uye(2, [1, 2, 3, 4]) ve uye[X, [1, 2, 3, 4]) sorgularını kullanınız. İlk sorgu, bir durumun doğru olup olmadığını sorgulamak için kullanılırken, ikinci sorgu listenin bütün üyelerini bulmak için kullanılmaktadır.

7.5. Rekursiyona Prosedürel Bir Bakış

Bu kısımda bir listeyi başka bir listeye ekleyen bir yüklem oluşturulacaktır. Ekle yükleminin üç argümanla birlikte tanımlanması gerekir.

Ekle(Liste1, Liste2, Liste3)

Ekle yüklemi Liste1’i Liste2’ye ilave ederek Liste3’ü elde eder. Eğer Liste1 boş ise, bu durumda 1. Listeyi 2. Listeye ilave etmek bir şeyi değiştirmez. Yani:

Ekle([], Liste2, Liste2).

Eğer liste1 boş değilse,

Ekle([Bas|Kuyruk1], Liste2, [Bas|Kuyruk3]):-ekle (Kuyruk1, Liste2, Kuyruk3]).

Liste1 boş değilse, rekursiv olan yüklem her seferinde bir elemanı Liste3’e transfer eder. Liste1 boş olduğunda ilk cümle Liste2’yi liste3’ün sonuna ilave eder.

Örnek:

DOMAINS

sayilar=integer*

PREDICATES

ekle(sayilar, sayilar, sayilar)

CLAUSES

ekle([], Liste, Liste).

ekle([Bas|Kuyruk1], Liste2, [Bas|Kuyruk3]):-

ekle (Kuyruk1, Liste2, Kuyruk3).

GOAL ekle ([1, 3, 5], [2, 4, 6], Yeni_Liste).

Yukarıdaki programı sadece birleştirilen iki listenin sonucunu almak için değil, aynı zamanda sonuç listesini yazıp ilk iki liste için geçerli bütün alternatifleri bulmak için kullanmak mümkündür. Örneğin GOAL ekle (Birinci_Liste, Ikinci_liste, [2, 4, 5, 6]). Denendiğinde toplam 5 çözüm bulunur. Ayrıca GOAL ekle ([3, Ikinci_eleman],Liste_2, [3, 4, 5, 6]) şeklindeki bir sorgu ile birinci listenin, örneğin ikinci elemanı ve ikinci listenin tamamını bulmak da mümkündür.

7.6. Bütün Çözümleri Bir Defada Bulma

Rekursiyon ve geriye iz sürme işlemlerini karşılaştırırken rekursiyonun daha avantajlı olduğu daha önce belirtilmişti. Bunun nedeni, rekursiyon esnasında argümanlar vasıtasıyla aradaki adımlarda elde edilen verilerin saklanabilmesidir. Öte yandan geriye dönüş işlemi bir sorguyu sağlayan bütün çözümleri bulabilirken, rekursiyon bunu yapamaz.

Bunun için Prolog’un hazır yüklemlerinden olan findall yüklemi kullanılır. Findall bir sorguyu kendi argümanlarından biri olarak alır ve bu sorgunun bütün çözümlerini tek bir liste altında toplar. Findall yükleminin toplam 3 argümanı vardır.

·       İlk değişken, örneğin Degisken_Ismi, yüklemden listeye aktarılacak değişkenin hangisi oldugunu gösterir.

·       İkinci değişken, örneğin yeni_yuklem, değerlerin alınacağı yüklemi gösterir.

·       Üçüncü argüman, örneğin Yeni_Degisken, geriye dönüş işlemiyle elde edilen değerlerin listesi tutan bir değişkendir. Yeni_degisken değerlerinin ait olduğu bir tip tanımının kullanıcı tarafından yapılmış olması lazımdır.

Bir gruptaki yaş ortalamasını bulan bir program, aşağıdaki şekilde yazılabilir.

DOMAINS

isim, adres = string

yas = integer

liste = yas*

PREDICATES

nondeterm kisi(isim, adres, yas)

toplam_liste(liste, yas, integer)

calistir

CLAUSES

toplam_liste([], 0, 0).

toplam_liste([Bas|Kuyruk], Toplam, N):-

toplam_liste(Kuyruk, S1, N1),

Toplam=Bas+S1, N=1+N1.

kisi(“Oktay DUYMAZ”, “Cumhuriyet Cad.”, 36).

kisi(“O.Faruk AKKILIÇ”, “Nail Bey Mah. “, 30).

kisi(“Hakay TAŞDEMİR”, “Firat Cad. No: 17”, 28).

calistir:-

findall(Yas, kisi(_,_, Yas), L),

toplam_liste(L, Toplam, N),

Ortalama=Toplam/N,

write(“Ortalama = “, Ortalama), nl.

GOAL calistir.

Programdaki findall cümlesi L listesini oluşturarak kisi yükleminden elde edilen bütün yaşları buraya aktarır.

7.7. Bileşik Listeler

Şimdiye kadar oluşturulan listelerde daima aynı türden olan elemanlar saklanmıştır. Listeler tamsayı, symbol vs.den oluşuyordu. Bir liste içerisinde farklı tipte elemanları bir arada yazmak oldukça faydalı olur. Birden fazla tipte olan elemanları bir arada tutmak için özel tanımlamaların yapılması gerekir. Bu da farklı operatörler tanımlamakla olur.

Örnek:

Domains.

Benim_listem = 1(liste); i(integer); c(char); s(string)

Liste=benim_listem*

[i(2), i(9), 1([s(“araba”), s(“bilgisayar”)]), s(“kalem”)]

Örnek:

DOMAINS

benim_listem =l(liste); i(integer); c(char); s(string)

liste=benim_listem*

PREDICATES

ekle(liste, liste, liste)

CLAUSES

ekle([], L, L).

ekle([X|L1], L2, [X|L3]):-

ekle(L1, L2, L3).

GOAL

ekle([s(sever), l([s(ahmet), s(deniz)])], [s(ahmet), s(ayse)], Sonuc),

write(“Ilk Liste : “, Sonuc, “\n”),

ekle([l([s(“Bu”), s(“bir”), s(“listedir.”)]), s(test)], [c(‘c’)],Sonuc2),nl,

write (“İkinci Liste: “, Sonuc2,’\n’).


8. AKIŞ DENETİMİ

Bir yüklem içinde değeri bilinen değişkenlere input (giriş değişkenleri), bilinmeyenlere ise output (çıkış değişkenleri) denir. Bu argümanların, input argümanları ise başlangıç değeri verilerek, output argümanları ise çıktı almak üzere uygun biçimde kullanılmasına akış biçimi denir. Örneğin bir argümanın iki değişkenle çağrılması durumunda 4 farklı akış biçiminden söz edilebilir.

(i, i)                      (i,o)                 (o,i)                 (o, o)

Programlar derlendiği zaman yüklemlerin global bir akış analizi yapılır. Ana sorgu ile başlayıp bütün programın değerlendirmesi yapılır. Bu esnada programdaki bütün yüklemlere akış biçimleri atanmış olur.

Akış analizi oldukça basittir. Çünkü program yazarken farkında olmadan aynı şey tarafımazdan da yapılmaktadır.

Örnek:

GOAL cursor(R, C), R1=R+1, cursor(R1, C).

Cursor yüklemine yapılan ilk çağrıda R ve C değişkenlerinin hiçbir değeri olmadığı için serbest değişken durumundadırlar. Dolayısıyla akış biçimi cursor(o, o) olur. R1=R+1 ifadesinde R değişkeninin değeri cursor yükleminden geleceği için, R değişkenin bağlı olduğu bellidir. Bu çağrıdan sonra R1 değişkeni değer almış olur. Eğer R değişkeni boş olsaydı, bu durumda bir hata mesajı görüntülenirdi.

Cursor yükleminin son kez çağrılmasında R1 ve C değişkenlerinin ikisi de önceden çağrıldığı için artık giriş değişkenleri olarak işlem görürler. Yani çağrının akış biçimi cursor(i, i) olur.

Burada sadece DOS Metin Modu ortamında çalışan aşağıdaki örnekler irdenelecektir.

Predicates

ozellik_degistir(Integer, Integer)

Clauses

ozellik_degistir(Yeni_ozellik,Eski_ozellik):-ozellik(Eski_ozellik), ozellik(Yeni_ozellik).

GOAL ozellik_degistir(112, Eski), write(“Merhaba”), ozellik(Eski, write(” millet”).

GOAL kısmındaki ilk çağrı ozellik_degistir(i, o) ile yapılır. Burada 112 bilinen, Eski ise bilinmeyen değişkendir. Bu durumda ozellik_degistir cümlesi Yeni_ozellik değişkeni ile çağrıldığında bunun değeri belli olduğu için input, Eski_ozellik’in değeri belli olmadığı için output olacaktır. Akış denetçisi ilk alt hedef olan ozellik(Eski_ozellik) cümlesine geldiği zaman ozellik yüklemi ozellik(o) akış biçimi ile çağrılır. Ozellik yükleminin ikinci çağrılışı ozellik(i) şeklinde olacaktır. Ana sorgudaki ozellik yüklemine yapılan çağrı input olacaktır, çünkü ozellik_degistir yükleminden alınır.

8.1. Bileşik Akış

Bir yüklemdeki değişken bileşik bir nesne ise, akış biçimi bileşik bir şekilde olabilir. Şimdi aşağıdaki örnekte olduğu gibi, bir ülke hakkında bilgilerin verildiği bir veritabanı düşünelim. Yeni bilgileri rahatlıkla ilave edebilmek için her bilgiyi kendi tipiyle saklamak istenebilir.

DOMAINS

ulke_bilgileri=alan(string, ulong); nufus(string, ulong);baskent(string, string)

PREDICATES

nondeterm ulke(ulke_bilgileri)

CLAUSES

ulke(alan(“Türkiye”,876000)).

ulke(nufus(“Türkiye”, 65000000)).

ulke(baskent(“Türkiye”, “Ankara”)).

ulke(alan(“Almanya”,840000)).

ulke(nufus(“Almanya”, 50000000)).

ulke(baskent(“Almanya”, “Bohn”)).

GOAL ulke(alan(Ad, Alan)), ulke(nufus(Ad, Nuf)).

Sorguyu aşağıdaki cümlelerle deneyiniz:

ulke (C)                                                   (o)

ulke(alan(Ulke_adi, Alani))                    (o,o)

ulke(nufus(“Türkiye”, Nuf))                    (i, o)

ulke(baskent(“Türkiye”, “Ankara”))        (i)

Son örnekteki bütün terimler bilindiği için akış biçim düz metindir.

8.2. Yüklemlerin Akış Biçimlerini Tanımlama

Yüklemler için uygun bir akış biçimi tanımlamak bazen daha güvenlidir. Yüklemlerin sadece özel akış biçimleri durumunda geçerli olacağı biliniyorsa, önceden akış biçimi tanımlamak faydalıdır. Çünkü bu durumda akış denetçisi bu yüklemlerden yanlış kullanılanı çok rahatlıkla bulabilir. Tip tanımı yapıldıktan sonra ‘-‘ işareti yazarak akış biçimi vermek mümkündür.

PREDICATES

musteri_bilgi_listesi(string, string, slist) -(i, o, o)(o, i, o)

8.3. Akış Analizini Kontrol Etmek

Analiz mekanizması, standart bir yüklemin yanlış bir akış biçimi ile çağrıldığını tesbit ettiği an hata mesajı verir. Bu hata mesajı, standart yüklemleri çağıran yüklemler tanımladığımız zaman, bunlardan akış biçimi anlamsız olanları tesbit etmede bize yardımcı olur.

Örnek:

C=A+B

ifadesinde A ve B serbest değişken olduğundan, akış denetçisi bu yüklem için akış biçimi olmadığını bildiren bir hata mesajı verecektir. Bu durumu kontrol etmek için free ve bound standart yüklemleri kullanılır.

İki sayı arasında toplama yapmak veya toplam ile ilk sayısı verilen bir durumda ikinci sayıyı bulan, bütün akış biçimleriyle çağrılabilen topla adında bir yüklem tanımlayalım.

Örnek:

PREDICATES

nondeterm topla(integer, integer, integer)

nondeterm sayi(integer)

CLAUSES

topla(X,Y,Z):-

     bound(X),

     bound(Y),

     Z=X+Y. /* (i,i,o) */

topla(X,Y,Z):-

     bound(Y),

     bound(Z),

     X=Z-Y. /* (o,i,i) */

topla(X,Y,Z):-

     bound(X),

     bound(Z),

     Y=Z-X. /* (i,o,i) */

topla(X,Y,Z):-

     free(X),

     free(Y),

     bound(Z),

     sayi(X),

     Y=Z-X. /* (o,o,i) */

topla(X,Y,Z):-

     free(X),

     free(Z),

     bound(Y),

     sayi(X),

     Z=X+Y. /* (o,i,o) */

topla(X,Y,Z):-

     free(Y),

     free(Z),

     bound(X),

     sayi(Y),

     Z=X+Y. /* (i,o,o) */

topla(X,Y,Z):-

     free(X),

     free(Y),

     free(Z),

     sayi(X),

     sayi(Y),

     Z=X+Y. /* (o,o,o) */

  /* 0’dan başlayan sayıları bulma*/

sayi(0).

sayi(X):-

     sayi(A),

     X = A+1.

GOAL topla(Ilk_sayi,7,10).

8.4. Referans Değişkenler

Akış denetçisi bir cümleyi incelerken, bu cümlenin başındaki bütün çıktı değişkenlerinin cümlenin gövdesinde bağlı olup olmadığını kontrol eter. Bir cümlede bir değişken bağlı değilse, bu değişkenin referans değişkeni olarak işlem görmesi gerekir. Bu karmaşayı gösteren bir örnek aşağıda verilmiştir.

Predicates

p(integer)

Clauses

p(X):-!.

Goal p(V), V=99, write(V).

Sorgudaki p yüklemi çıktı biçiminde çağrılır fakat clauses bölümündeki p yükleminde bulunan X değişkeni bağlı değişken değildir. Akış denetimi sırasında bu fark edildiğinde, değişkenin domains bölümündeki tip tanımına bakılır. Eğer değişken tipi referans olarak tanımlıysa problem çıkmaz. Tanımsızsa uyarı mesajı görüntülenir.

Bir cümledeki bir değişken bağlı değilse, bu durumda cümlenin herhangi bir değer aktarması mümkün değildir. Bunun yerine referans değişkenine bir pointer yollayarak daha sonra bu noktaya gerçek değerin yazılması sağlar. Bu, bu tipteki bazı değişkenlere değer aktarmak yerine, tip tanımının tamamına aynı işlemin yapılmasını gerektirir. Kayıtlara gönderilen pointerlar referans tipe ait argümanlara iletilir. Yani bileşik bir tip referans bir tip haline gelirse, bu durumda bütün alt tiplerin de referans tip olarak işlem görmesi gerekir. Bileşik bir tipin referans tip olarak tanımlanması durumunda, derleyici diğer bütün alt tipleri de referans tip olarak kabul eder.

8.4.1. Referans Tip Tanımı

Akış denetçisi program içerisinde bağımsız bir değişken bulduğunda değişken sadece bir cümleden dönüş sırasında bağımlı değilse uyarı verir. Bu durum sizin için uygunsa, bu tip tanımı otomatik olarak referans tip olarak kabul edilir. Bununla birlikte referans tip olarak tanımlamak istenen bir tipi domains bölümünde net olarak tanımlamak daha mantıklıdır.

8.4.2. Referens Tip ve İzleme Dizileri(array)

Zorlama ve ekstra eşleştirme gerektirdiği için, referans tipler programın çalışma hızında genel bir azalmaya neden olur. Fakat referans tip tanımının neden olduğu problemler daha etkili biçimde kullanılabilir ve bu tip tanımlarının etkileri azaltılabilir.

Referans tipler kullanıldığı zaman, Visual Prolog izleme dizini kullanır. Bu izleme dizini referans değişkenlerin değer aldıkları anı bildirmek için kullanılırlar. Referans bir değişkenin oluşturulması ve değer alması arasındaki herhangi bir noktaya geriye dönüş yapıldığı zaman, bu değişkenin yeniden değer almamış hale getirilmesi gerekir. Fakat bu problem düz değişkenlerle uğraşırken meydana gelmez. Çünkü bunların oluşturulması ve değer alma noktaları aynıdır. İzlemede kaydedilen her bir çağrı 4 byte (32 bit bir pointerin büyüklüğü) kullanır.

Gerektiğinde kuyruk büyüklüğü otomaki olarak arttırılır. İzin verilen maksimum büyüklük 16-bit Visual Prolog için 64K, 32-bit için ise sınırsızdır.

Standart tipleri referans tip olarak kullanmak iyi bir fikir değildir. Çünkü program kullanıcının tanımladığı bu referans tipi, aynı tip için daima geçerliymiş gibi kullanır. Bunun yerine, istenilen temel tip için referans bir tip tanımlamak daha uygundur. Örneğin aşağıdaki program parçasında kullanıcının tanımladığı tamsayi_referans_tipi tamsayılar için referans tiptir. Dolayısıyla tamsayi_referans_tipi her kullanımda referans tip olarak işlem görür. Fakat tamsayı tipindeki değişken referans tip olarak değil, normal olarak integer olarak işlem görür,.

Domains

tamsayi_referans_tipi= reference integer

Predicates

P(tamsayi_referans_tipi)

Clauses

P(_).

8.5. Referans Tip Kullanımı

Referans tip kullanımının en doğru biçimi, sadece gerekli olan birkaç yerde kullanıp geri kalan kısımların tamamında referans olmayan tipi kullanmaktır. Zaten gerekli olan durumlarda referans ve referans olmayan tipler arasında dönüşüm yapmak mümkündür. Şimdi referans olan bir tamsayıyı referans olmayan bir tamsayıya dönüştürelim.

Domains

Referans_tamsayi=reference integer

Predicates

Donustur(referans_tamsayi, tamsayi)

Clauses

Donustur(X, X).

İsmi aynı olan bir değişken referans ve referans olmayan tipte kullanıldığı zaman dönüşüm otomatik olarak yapılır. Yukarıdaki örnekte referans_tamsayi ve tamsayi arasında dönüşüm otomatik olarak yapılır. Referans bir değişkenin, referans olmayan bir değere dönüştürülebilmesi için öncelikle bir değer almış olması gerekir. Yani referans tip olarak tanımlı bir değişkeni dönüştürmek için (örneğin referans tamsayılardan referans karaktere) öncelikle bu değişkenin bir değer almış olduğundan emin olmak gerekir. Aksi takdirde serbest değişken kullanılamaz şeklinde hata mesajı görüntülenir. Referans tip tanımlarının nasıl çalıştığını tam olarak anlamak için aşağıdaki programı değişik sorgularla çalıştırılmalıdır.

DOMAINS

referans_tamsayi = integer

referans_liste= reference referans_tamsayi*

PREDICATES

nondeterm eleman(referans_tamsayi, referans_liste)

ekle(referans_liste, referans_liste, referans_liste)

CLAUSES

eleman(X, [X|_]).

eleman(X, [_|L]):-

eleman(X, L).

ekle([], L, L).

ekle([X|L1], L2, [X|L3]):-

ekle(L1, L2, L3).

GOAL eleman(1, L).

Aşağıdaki sorguları da deneyin

eleman(X, L), X=1.  Elemanları arasında 1 olan bütün listeleri bul.

eleman(1, L), eleman(2, L). Elemanları arasında 1 ve 2 olan bütün listeleri bul

X=Y, eleman(X, L),eleman(Y, L), X=3. X ve Y’nin eleman olduğu listeler

eleman(1, L), ekle(L, [2, 3], L1).

ekle(L, L, L1), eleman(1, L). 1’in iki kez eleman olduğu listeler.

8.6. Akış Biçimine Yeni Bir Bakış

Referans bir değişken serbest halde olmasına rağmen, bir yüklem çağrısı içinde çağrıldığı anda mevcut olabilir. Ülkeler hakkındaki programda ayni_baskentler:-ulke(baskent(Kent, Kent), write(Kent, ‘\n’), fail şeklindeki bir sorguyla, başkentleri ülke ismiyle aynı olan bütün ülkeleri bulmak isteyelim. Burada kent değişkeni iki kez çıktı akışı ile kullanılmıştır. Fakat bu sorgu satırının söylediği şey; Kent değişkeni değer aldığı anda ikinci değişken olan Kent’in de aynı değeri alması gerektiğidir. Bu yüzden her iki değişken çağrı yapılmadan önce yaratılıp eşleştirilir. İşte bunu yapabilmek için bunların tipi referans tipe dönüştürülür ve iki değişken çağrı anından itibaren kullanıma girerler.

Standart tip tanımlarının referans tip haline getirmenin çok yanlış bir kullanım olacağı daha önce söylenmişti. Eğer böyle bir şey yapılmak isteniyorsa, uygun bir referans tip tanımlamak daha mantıklıdır.

8.7. İkili (Binary) Ağaç Yapısının Referans Tip İle Kullanımı

Önceki sıralama işlemleri ikili ağaç yapısı ile çözülmüştü. Aynı şeyi referans tip tanımı ile daha güzel biçimde yapmak mümkündür. Ağaç yapısındaki bir dalı, bir değer aldıktan sonra değiştirmek mümkün değildir. Ağaç oluşturulurken pek çok noktanın kopyası oluşturulur. Sıralama işlemini büyük miktarda veri üzerinde yapıldığı düşünülürse, bunun hafıza taşmasına neden olabileceği görülür. Referans bir tip, ağacın dallarını serbest değişken olarak bırakarak, bu durumu düzeltebilir. Bir referans tipi bu şekilde kullanarak yeni bir dalın ilave edileceği noktanın üzerindeki dalı kopyalamaya gerek kalmaz.

Örnek:

Domains

agac = reference t(isim, agac, agac)

isim = string

PREDICATES

araya_ekle(isim, agac)

CLAUSES

araya_ekle(ID, t(ID,_,_)):-!.

araya_ekle(ID, t(ID1, Agac,_)):-

ID<ID1, !, araya_ekle(ID, Agac).

araya_ekle(ID, t(_,_,Agac)):-

araya_ekle(ID, Agac).

GOAL

araya_ekle(“Alper”, Agac),

araya_ekle(“Kasim”, Agac),

araya_ekle(“Paki”, Agac).

İlk araya_ekle(“Alper”, Agac) alt hedefi ilk kural ile eşleşir ve bileşik nesne t(“Alper”,_,_) biçimini alır. T’deki son iki argüman bağlı değişken olmasalar da t diğer alt hedefe iletilir:

araya_ekle(“Kasim”, Agac).

Bu, agac değişkenini t(“Alper”, t(“Kasim”,_,_),_) değerini aldırır. Son olarak son alt hedef araya_ekle(“Paki”, Agac) agac değişkenini t(“Alper”, t(“Kasim”,_, t(“Paki”,_,_)),_) değerine atar ve sonuçta bu değer görüntülenir.

8.8. Referans Tip Kullanarak Sıralama

Daha önce ikili ağaç kullanarak yapılan sıralama örneğini, referans ve referans olmayan tipler arasında ayrım yaparak nasıl yapabileceğini gösteren bir örnek, aşağıda verilmiştir.

DOMAINS

agac=reference t(deger, agac, agac)

deger=integer

liste = integer*

PREDICATES

araya_ekle(integer, agac)

agac_ekle(liste, agac)

nondeterm agacin_elemanlari(integer, agac)

sirala(liste, liste)

CLAUSES

araya_ekle(Deger, t(Deger,_,_)):-!.

araya_ekle(Deger, t(Deger1,Agac,_)):-

Deger<Deger1,!,

araya_ekle(Deger, Agac).

araya_ekle(Deger, t(_,_,Agac)):-

araya_ekle(Deger, Agac).

agac_ekle([],_).

agac_ekle([Bas|Kuyruk],Agac):-

araya_ekle(Bas,Agac), agac_ekle(Kuyruk, Agac).

agacin_elemanlari(_,Kuyruk):-

free(Kuyruk),!, fail.

agacin_elemanlari(X,t(_,L,_)):-

agacin_elemanlari(X, L).

agacin_elemanlari(X,t(RefStr,_,_)):-

X=RefStr.

agacin_elemanlari(X,t(_,_,R)):-

agacin_elemanlari(X, R).

sirala(L,L1):-

agac_ekle(L, Agac),

findall(X, agacin_elemanlari(X,Agac), L1).

GOAL sirala([10,9,17,21,114,5], L), write(“Liste= “, L),nl.

Bu örnekte referans tipler sadece agac değişkeninde kullanılmıştır. Diğer argümanların tamamı referans olmayan tiplerdedir.

8.9. Binary (İkili) Tip

Visual Prolog’da ikili verileri kullanmak için özel tip, ikili terimlerin elemanlarına erişmek için özel yüklemler vardır. İkili terim kullanmanın tek amacı, başka türlü anlamlı bir şekilde gösterilemeyen verileri kullanmak ve bunları saklamaktır. Binary terimleri okuma, bunları dosyaya aktarma işlemi için özel yüklemler vardır.

Binary terimlerin temel amacı mantıksal olmayan nesneler diğer programlama dillerinin içine kolayca yerleştirilmesine imkan tanımaktır. Binary terimler, geriye iz sürme mekanizması çerçevesinde Prologdaki diğer terimlerden farklı davranırlar. Geriye iz sürme mekanizması, binary terimin oluşturulduğu noktadan öncesine giderse, binary terimlerin o ana kadar aldıkları değerleri kaybederler. Geriye dönüş, herhangi bir binary terimin oluşturulduğu noktadan öncesine dönmezse, binary terimdeki değişikliklere bir şey olmaz.

8.9.1. Binary Terimlerin Kullanılması

Bir binary terim byte biçiminde bir dizi ve bu dizinin büyüklüğünü saklayan word (16 bit) veya dword(32 bit ortam) değişkenden oluşur.

Diğer dillerden çağrı yapıldığında, binary tipindeki bir terim (diğer bir dildeki fonksiyonun çağrısayla aktarılan değişken) gerçek içeriğe işaret eder. Buradaki büyüklük alanı, alanın kendisinin sahip olduğu büyüklüktür. Binary terimler 16 bit platformlarda genelde 64K ile sınırlıdır.

8.9.2. Binary Terimlerin Yazım Biçimi

Binary terimler okunup metin biçimde yazılabilir. Visual Prolog’da program satırları gibi yazılabilir. Yazılım biçimi:

$[b1, b2, ….., bn]

Burada b1, b2 vs. ilgili terimin byte olarak yazılmış halidir. Program akışı içerisinde yazıldığı zaman, buradaki her byte uygun bir pozitif biçimde desimal, hegzadesimal, oktal veya karakter olarak yazılabilir. Karakter olarak yazılan byte, program çalışırken daima hegzadesimal biçime dönüştürülür ve “0x” kısımları bulunmaz.

Örnek:

GOAL write(“Binary terimi metin biçiminde yaz: “, $[‘C’, 12, 15, 0x14, ‘e’, 5], ‘\n’).

8.9.3. Binary Terimlerin Oluşturulması

Binary terim oluşturmak için Visual Prolog’da mevcut olan yüklemler sırayla aşağıda verilmiştir.

8.9.3.1. makebinary(1)

makebinary, tanımlanan byte sayısında bir binary terim oluşturur ve içeriğini binary 0 olarak ayarlar.

…., Bin=makebinary(10), ….

Burada byte sayısı, alan büyüklüğü hariç, net büyüklük olmalıdır.

8.9.3.2. makebinary(2)

İki argüman alabilen biçiminde eleman büyüklüğü tanımlanabilir.

…., Usize=sizeof(unsigned), Bin=makebinary(10, Usize), ….

Bu yüklem, terim büyüklüğü eleman sayısının eleman büyüklüğüyle çarpımıyla belirtilen bir binary terim oluşturur. Örnekte eleman sayısı 10, eleman büyüklüğü ise sizeof(unsigned) olarak tanımlıdır. Terim içeriği 0 olur.

8.9.3.3. composebinary(2)

Mevcut olan bir pointer ve bir uzunluktan bir binary terim oluşturur. Kullanım biçimi:

…, Bin=composebinary(StringVar, Buyukluk), ….

8.9.3.4. getbinarysize(1)

getbinarysize, verinin önündeki alan büyüklüğünü hariç tutarak, bir binary terimin net büyüklüğünü byte türünden verir.

…, Buyukluk=getbinary(Bin), …

8.9.4. Binary Terimlere Erişim

4’ü giriş, diğer 4’ü de çıkış elde etmek için kullanılan 8 yüklem binary terimlere erişmek için kullanılabilir. Bunların hepsi binary terim büyüklüğü, tanımlı indeks ve istenilen maddenin büyüklüğüne (byte, word, dword veya real) bağlı olarak bu değişkenlerin doğru aralıklarda olup olmadıklarını kontrol eder. Bu yüzden bu girişleri, ikili terimlerin tanımlı sınırları dışında tanımlamak ve çağırmak hataya neden olur.

İndislerin (eleman numaraları) 0’a göre değişir. Yani binary bir terimin ilk elemanının indisi 0, en son elemanın da N-1 olur.

8.9.4.1. getentry(2)

getentry yüklemi getbyteentry, getwordentry, getdwordentry veya getrealentry biçimlerinden biri olur ve sırasıyla byte, word, dword veya real tiplerinde giriş yapıp, giriş alabilir.

Deger= getbyteentry(Bin, 3), ….

8.9.4.2. setentry(3)

getentry’ye karşılık gelen bir yüklem olup byte, word, dword eya real girişleri yapar.

…., setbyteentry(Bin, 3, Baytlar), ….

8.9.5. Binary Terimleri Eşleştirme

Binary terimler de diğer terimler gibi eşleştirilebilir. Kullanım biçimi:

…, Bin1=Bin2, ….

Eşleştirme anında terimlerden biri serbest halde ise, birbirine eşitlenirler. Her ikisi de bağlı ise, bu durumda binary terimlerin birbirine eşit olup olmadıkları kontrol edilir.

8.9.6. Binary Terimleri Karşılaştırma

Binary iki terim eşleştirilirken şu sonuçlara dikkat edilir:

Eğer büyüklükleri farklı ise, büyük olan büyük kabul edilir, değilse byte bazında karşılaştırılırlar. İki farklı byte bulunduğu anda karşılaştırma durur, sonuç toplam terimin karşılaştırılması olarak gönderilir. Örneğin $[1, 2] $[100]’den daha büyüktür fakat $[1,3]’den daha küçüktür.

Binary terimlerin bazı özelliklerini gösteren bir program aşağıda verilmiştir.

PREDICATES

binary_karsilastir_ve_eslestir

binary_karsilastir(binary, binary)

al(binary)

CLAUSES

binary_karsilastir_ve_eslestir:-

Bin=makebinary(5),

binary_karsilastir(Bin, _),

binary_karsilastir($[1,2], $[100]),

binary_karsilastir($[0], Bin),

binary_karsilastir($[1, 2, 3], $[1, 2, 4]).

binary_karsilastir(B,B):-!,

write(B, ” = “, B, ‘\n’).

binary_karsilastir(B1, B2):-

B1>B2, !,

write(B1, ” > “, B2, ‘\n’).

binary_karsilastir(B1, B2):-

B1<B2, !,

write(B1, ” < “, B2, ‘\n’).

al(Bin):-

setwordentry(Bin, 3, 255), fail.

al(Bin):-

Buyukluk=getbinarysize(Bin), X=getwordentry(Bin, 3),

write(“\nBuyukluk= “, Buyukluk, “X = “, X, ” Binary= “, Bin, ‘\n’).

GOAL

binary_karsilastir_ve_eslestir, % Binary kaşılaştırma ve eşleştirme için

KelimeBuyuklugu=sizeof(word), Bin=makebinary(4,KelimeBuyuklugu), al(Bin),

write(“Run-time hataları yanlış indeksten kaynaklanıyor:\n”), Indeks=4,

trap(Setwordentry(Bin, Indeks, 0), E,

write(Bin, “teriminin kelime indeksi”, Indeks, ” olustururken “, E, ” hatasi olustu”, ‘\n’)).

8.9.7. Terimleri Binary Terimlere Dönüştürme

Bileşik bir terimin argümanları belleğin değişik yerlerinde olabilir. Basit tipleri doğrudan kayıtlı terimde tutulurken karmaşık olanlar (pointer ile erişilenler ve global bir stack’da olanlar) içindeki göründükleri terimin yakınlarında olmayabilir. Böyle bir terimi programdan dışarıya yollamak zor olur. Çünkü terimin bütün içeriğinin kopyasını almanın açık bir yolu yoktur. Dolayısıyla bir terimdeki değişkeni başka bir değişkenle eşleştirirken sadece bu terime giden pointerin bir kopyası alınmış olur.

term_str yüklemini kullanarak, bir terimi diziye ve diziden tekrar terime dönüştürmek mümkündür. Bu ise, sadece terimi içeriğini kopyalamak için gerektiğinde, oldukça yetersiz kalır. İşte bu problemi term_bin yüklemini çözer.

8.9.7.1. term_bin(3)

term_bin, herhangi bir tipteki terim ve binary veri bloku arasında dönüşümü, terim içeriği ve pointer sabitle bilgisini tutarak, yapar. Pointerin sabitleme bilgisi, binary veriye dönüştürülmüş terimi yeniden diziye dönüştürmek için kullanılır. Kullanımı şöyledir:

term_bin(tip, Terim, Bin)            /* (i,i,o), (i,_,i) */

Tip, Terimin ait olduğu tip, Bin ise Terimin içeriğini tutan binary terimdir.

8.10. Hatalar ve İstisnalarla Uğraşma

 Kaliteli yazılımlar geliştikçe, güvenilir programlar üretmek için hataların bulunması ve tek tek ayıklanması da önemli hale gelmektedir. Visual Prolog, program çalışırken meydana gelen hataları kontrol etmek için standart yüklemlere sahiptir. Programın işleyişi esnasında meydana gelebilecek bütün hatalar DOS ortamıda PROLOG.ERR, UNIX ortamında PDCProlog.err dosyasında saklanır. Hata mesajı numarası 10000 ve yukarısı kullanıcının programında kullanması için exit kodları olarak ayrılmıştır.

Hata ve istisna durumlarıyla uğraşmak için Visual Prolog’da temel olarak trap yüklemi kullanılır. Bu yüklem, run-time hatalarını ve exit yüklemiyle harekete geçirilen istisna durumları yakalayabilir. Bu yüklem kullanarak, örneğin Ctr+Break tuşlarına basılıp basılmadığını da kontrol edilebilir.

8.10.1. exit(0), exit(1)

exit yüklemine yapılan bir çağrı, run-time hataya eşdeğerdir. Kullanım biçimleri:

exit ve exit(CikisKodu)

Argüman kullanmadan exit yüklemini kullanmak, exit(0) gibi çalışır. exit’e giden çağrı trap yükleminde doğrudan veya dolaylı olarak çalıştırılırsa, CikisKodu trap yüklemine geçer.

8.10.2. trap(3)

Üç argüman alan bu yüklem hata yakalama ve istisna yönetimini gerçekleştirir. İlk ve son argümanlar yüklem çağırma, ikinci argüman ise değişkendir. Kullanım biçimi:

trap(YuklemCagirma, CikisKodu, HataDurumundaCagrilacakYuklem)

Örneğin trap(islem(P1,P2,P3), CikisKodu, hata(CikisKodu,P1)),…. şeklindeki bir çağrı göz önüne alınırsa, işlem yüklemi çağrılırken hata oluşursa CikisKodu ilgili hatayı verirken hata yönetme yüklemi olarak tanımladığımız hata yüklemi çağrılmış olur. Hata yükleminden dönüşte ise trap yüklemi başarısız olur.

Metin modu ortamında BREAK açıkken BREAK yapılırsa, yani Ctrl+Break tuşlarına basılırsa, trap yüklemi bunu yakalar ve CikisKodu değerini olarak 0’ı görüntüler.

Örnek:

Açılmamış olan bir dosyadan dolayı hata mesajı yakalayan program aşağıda verilmiştir.

include “c:\\vip\\include\\error.con”

DOMAINS

file = giris_dosyasi

PREDICATES

hata_yakalama(integer, file)

satir_al(file, string)

CLAUSES

hata_yakalama(err_notopen, Dosya):-!,

write(Dosya, ” isimli dosya açık değil\n”),

exit(1).

hata_yakalama(Hata, Dosya):-!,

write(Dosya, “adli dosyada”,Hata, ” hatasi “, ‘\n’),

exit(1).

satir_al(Dosya, Satir):-

readdevice(Eski),

readdevice(Dosya),

readln(Satir),

readdevice(Eski).

GOAL trap(satir_al(giris_dosyasi, Ilk), Hata, hata_yakalama(Hata, giris_dosyasi)), write(Ilk).

8.10.3. errormsg(4)

errormsg yüklemi, Visual Prolog hata mesajları dosyasıyla aynı biçimde olan dosyalara erişmek için kullanılabilir. Kullanım biçimi:

errormsg(DosyaAdi,HataNo,HataMesaji,YardimMesaji)   / (i, i, o, o)/

Bu işlem için aşağıdaki program örneği kullanılabilir:

PREDICATES

hata(integer)

ana_kisim

/* ………. */

CLAUSES

hata(0):-!. % Ctrl+Break tuşuna basılınca bir şey yapma

hata(H):-

errormsg(“prolog.err”, H, HataMesaji, _),

write(“\nSayin Kullanici, Programınızda”, H, “nolu “, ErrorMsg, “hatasi meydana geldi”),

write(“\nDosyanizi”, hata.txt,” dosyasina yaziyorum”),

save(“hata.txt”).

GOAL trap(ana_kisim, CikisKodu, hata(CikisKodu)).

8.10.4. Hataların Bildirilmesi

Visual Prolog’daki bazı derleyici direktiflerini kullanarak, programlarınız içindeki run-time hataları kontrol edilebilir. Bu direktifler şu amaçlarla kullanılır:

·       Tamsayı taşma(overflow) hatalarını kontrol edip etmeme durumu

·       run-time hataları hangi ayrıntı düzeyinde verileceği

·       Yığın taşması(Stack overflow) kontrolünü yapma

Bu direktifler programın baş tarafında verilebileceği gibi, VIP çalıştırıldıktan sonra Compiler Options seçeneğiyle de verilebilir.

8.11. Hata Düzeyi

Visual Prologun, run-time hatanın oluştuğu yeri göstermeye yarayan çok güzel bir mekanizması vardır. Meydana gelen hatanın hangi düzeyde bildirileceğini, hatanın meydana geldiği yeri, derleyicinin errorlevel direktifi belirler. Kullanım biçimi şöyledir:

errorlevel=n

n’nin alabileceği değerler 0, 1 veya 2 olabilir. Bu değerlere göre derleyicinin sunacağı hata düzeyi şunları kapsar:

0   Bu durumda en küçük ve en etkin hata mesajı verilir. Fakat hatanın yeri kaydedilmez, sadece hatanın numarası verilir.

1   Default olarak kabul edilen düzey budur. Hata meydana geldiğinde hatanın meydana geldiği nokta, dosyanın başlangıcından itibaren byte türünden gösterilir.

2   Bu düzey seçildiğinde, 1 durumunda gösterilmeyen stack overflow, heap overflow, trail oveflow vs. gibi hataları görülebilir. Burada da hatanın meydana geldiği yer bildirilir.

Proje bazında çalışırken hata mesajı düzeylerini ayarlarken dikkatli olmak gerekir. Bir projede birden fazla dosya bulunacağı için, birbirine bağlı olan dosyalardaki hata düzeyleri farklı biçimde ayarlanırsa, errorlevel=0 olan bir alt dosyada hata meydana gelirse ve ana dosyada errorlevel=1 veya 2 olursa, bu durumda hatanın meydana geldiği yeri tam olarak bulmak imkansız olur.

8.11.1. lasterror(4)

lasterror, en son olan hatayla ilgili bütün bilgiyi verir. Kullanım biçimi:

lasterror(HataNo,Modul,IncDosyasi,HataYeri)

Burada Modul, hatanın meydana geldiği dosya adı, IncDosyasi ise include dosyasıdır. Bellek taşması hatalarının doğru olarak alabilmek için programın errorlevel=1 olarak derlenmesi gerekir. Sadece basit hataların mesajları alınması isteniyorsa errorlevel=1 yeterlidir.

8.11.2. Terim Okuyucudan Gelen Hataları Görme

consult veya readterm yüklemleri çağrıldığında okunacak satırda bir hata var ise, bu yüklemlerin hata mesajı vererek duracakları bilinmektedir. Hata nedenleri ise okunacak satırın uygun biçimde hazırlanmamış olmamasıdır.

Örneğin:

·       Bir diziyi sonlandırmamak

·       Symbol türünde bir karakter yerine integer bir karakter yazmak

·       Yüklem adı için büyük harfler kullanmak

·       Sabit değerleri “ “ içinde yazmamak vs.

readtermerror ve consulterror yüklemlerini kullanarak readterm veya consult yüklemlerinin okumaya çalıştığı dosyalarda ne tür hatalar meydana geldiğini kontrol edebililir.

consult ve readterm yüklemlerinden gelen hatalar trap yüklemi tarafından yakalanırsa, consulterror ve readtermerror yüklemlerini kullanarak hatanın nedenini görmek ve yazmak mümkündür.

8.11.3. consulterror(3)

consulterror, hatalı yazımın bulunduğu satırdaki hata hakkında bilgi verir. Kullanım biçimi

consulterror(Satir, HataYeri, DosyadakiYeri)

Satir, hatanın bulunduğu satır, HataYeri hatanın bulunduğu nokta, 3. parametre ise hatalı satırın bulunduğu yer verilir.

Örnek:

CONSTANTS

yardim_dosyasi=”prolog.hlp”

hata_dosyasi=”prolog.err”

DOMAINS

dom = a(integer)

liste= integer*

DATABASE – firat_dba

p1(integer, string, char, real, dom, liste)

PREDICATES

consult_hatalarini_ayiklama(string, integer)

CLAUSES

consult_hatalarini_ayiklama(Dosya, Hata):-

Hata>1400, Hata<1410, !,

retractall(_, firat_dba),

consulterror(Satir, Hatanin_Yeri,_),

errormsg(hata_dosayasi, Hata, Mesaj, _),

str_len(Bosluklar, Hatanin_Yeri),

write(Dosya, ” dosyasinin “, Satir, ” satırında “, Bosluklar, Mesaj, “meydana gelmistir”),

exit(1).

consult_hatalarini_ayiklama(Dosya, Hata):-

errormsg(hata_doyasi, Hata, Mesaj, _),

write(Dosya, ” dosyasi açılmaya çalışırken “, Mesaj, ” hatası oluştu”),

exit(2).

GOAL Dosya=”test.dba”,

trap(consult(Dosya, firat_dba), Hata, consult_hatalarini_ayiklama(Dosya, Hata)),

write(“\n Tamam \n”).

8.11.4. readtermerror(2)

readtermerror, readterm yükleminin okuduğu satırdaki hatayı verir. Kullanım biçimi:

readtermerror(Satir, HataYeri)

8.12. Break Kontrolü (Sadece Metin Modunda)

Visual Prolog’daki break mekanizmasının nasıl çalıştığına bakalım. Genelde, break için gerekli komutlar o anda çalışan programı hemen durdurmazlar. Prolog’da, istisnai durumları yöneten bir birim vardır. Sinyal ile aktif edilen bu parça bir flag yerleştirir. Visual Prolog bu flagı iki farklı durumda kontrol eder.

·       Yazılan program, break-kontrolü açık halde derlenirse, her yüklem girildiğinde break-flag durumu kontrol edilir. Break-kontrol seçeneği, VIP seçeneklerinden iptal uygun direktif seçilerek (Options/Compiler Directives/Run-time check) iptal edilebilir.

·       Library rutinlerinin bazıları break-flag kontrolü yaparlar.

8.12.1. break(1)

break, bir program çalışırken break-flag kontrolünün yapılıp yapılmayacağını belirtir. Kullanım biçimleri şöyledir.

break(on), break(off)

break(BreakDurumu)

DOS tabanlı pgogramlar için break komutundan kaynaklanan çıkış kodları daima 0 olur.

8.12.2. breakpressed(1)

break-flag kurulmuşsa, break(off) olsa veya program nobreak seçeneğiyle derlense bile, breakpressed yüklemi başarılı olur. Başarılı olunca, yakalanan en son sinyale göre bir çıkış kodu verir ve break-flagı siler.

8.13. DOS Metin Modunda Kritik Hata Kontrolü

Bu bölüm sadece DOS metin modu ortamında geçerlidir. Dolayısıyla VPI programlarına uygulanamaz.

Visual Prolog’un DOS versiyonu hata durumlarıyla ilgilenen bazı rutinler içerir. Bir DOS hatası olduğu zaman DOS, criticalerror rutinini çağrır. Visual Prolog’daki sistem ise, run-time editörü de bir dosya hatası bulduğunda fileerror yüklemini çağırır. Bu yüklemler global olarak tanımlanır ve kendinize ait cümlecikler kullanırsanız, library’deki rutinler yerine size ait rutinleri programa bağlar. Dolayısıyla hataları daha iyi kontrol etmek mümkündür. Bu durumda .EXE programlarının büyüklüğü büyük oranda azalır. criticalerror ve fileerror için global deklerasyon include dosyasında error.pre içinde hazır olarak bulunmaktadır.

8.13.1. criticalerror(4)

Visual Prolog, bu rutini DOS kritik hatalarıyla uğraşmak için tanımlar. criticalerror yüklemi kullanılmak istenirse, ERROR.PRE dosyası programa dahil edilmelidir. Tanımlanması şöyledir:

global predicates

criticalerror(HataNo, HataTuru, DiskNo, Eylem)

criticalerror yüklemi daima başarılı olmalıdır. Bu yüklem sadece .EXE dosyasından çalışır ve DOS kritik hata interrupt tutucusuyla yer değiştirir. Aşağıdaki tabloda criticalerror yükleminin argümanlarının aldığı değerler verilmiştir.


Tablo 8.4. Criticalerror yükleminin argümanlarının aldığı değerler

Argüman

Değer

Anlamı

HataNo

=   0

=   1

=   2

=   3

=   4

=   5

=   6

=   7

=   8

=   9

= 10

= 11

 

Yazma korumalı diskete yazma teşebbüsü

Bilinmeyen ünite

Sürücü hazır değil

Bilinmeyen komut

Veri içinde CRC hatası

Yanlış sürücü isteği yapı uzunluğu

Arama hatası

Bilinmeyen medya türü

Sektör bulunamadı

= 12

Yazıcıda kağıt bitmiş

Yazma hatası

Okuma hatası

Genel hata

HataTürü

=   0

=   1

=   2

Karakter araç hatası

Disk okuma hatası

Disk yazma hatası

DiskNo

=   0-25

A-Z’ye kadar sürücü

Eylem

=   0

=   1

=   2

Çalışmayı durdur

İşlemi yeniden dene

İşlemi iptal et (Tehlikeli olabilir ve tavsiye edilmez)

 

8.13.2. fileerror(2)

Metin modundaki bir dosya eylemi başarısız olunca fileerror yüklemi harekete geçirilir. Kendinize ait fileerror yüklemini tanımlarsanız, bu yüklemin başarısız olmasına izin verilmez ve bu yüklem sadece .EXE uygulamalarından çalışır. fileerror’un ERROR.PRE dosyasındaki tanımlanması şöyledir:

global predicates

fileerror(integer, string) – (i, i) language c as “_MNU_FileError”

Bu tanım tipi doğrudur. Kaynak kod Prolog’da olsa bile language c mutlaka belirtilmelidir.

8.14. Dinamik Cut

Prolog’daki cut statiktir. Geleneksel cut işleminde, program akışı ancak ! sembolüne geldiği zaman cut devreye girer ve sadece içinde bulunulan cümleleri etkiler. Dolayısıyla bir cut komutunun etkisini başka bir yükleme aktarmak mümkün değildir. Normal cut komutunun diğer bir dezavantajı da; yüklemde cut komutunu takip eden cümlelerdeki geriye dönüş noktalarını ortadan kaldırmadan, bir alt hedefteki diğer çözümleri arama ihtimalini ortadan kaldırmanın mümkün olmamasıdır.

Visual Prolog’da dinamik kesme mekanizmasında getbacktrack ve cutbacktrack yüklemleri kullanılır. Bu mekanizma sayesinde bu iki dezavantaj ortadan kalkmış olur. getbacktrack, geriye iz sürme noktalarının yığını içerisinde en üstteki pointer’i verir. Bu noktanın üstünde kalan bütün geriye dönüş noktaları silinebilir.

Bu iki yüklemin kullanımı hakkındaki örnekler, aşağıda verilmiştir.

1.     Elimizdeki veritabanında sahislarin isim ve aylık gelirleri var. Bu sahısların arkadaşlarını kaydetmiş durumdayız.

database

sahis(symbol, income)

arkadas(symbol, symbol)

Arkadaşı olan veya az bir vergi ödeyen insanların listesini görmek için aşağıdaki cümlecikleri kullanabiliriz:

sansli_insanlar(aradasi_var(P)):-sahis(P,_), arkadas(P,_).

sansli_insanlar(zengindir(P)):-sahis(P, AylikGelir), not(zengin(AylikGelir)).

Bir şahsın birden fazla arkadaşı varsa, ilk cümlecik birden fazla çözüm getirir. Bu arada dinamik cut kullanabiliriz.

sahsli_insanlar(arkadasi_var(P)):-

sahis(P,_), getbacktrack(BTOP), arkadas(P,_), cutbacktrack(BTOP).

Geriye dönüş mekanizması yapılırsa, arkadaş yüklemi birden fazla çözüm sunabilir. Fakat cutbacktrack yüklemi çağrılarak bu ihtimal ortadan kaldırılır.

Dinamik cut kullanmanın daha önemli avantajı, geriye dönüş pointerini başka bir yükleme geçirmek ve cut komutunu şartlı olarak çalıştırmaktır. Pointer pozitif tipte olup yine pozitif tipteki değişkenlere aktarılabilir.

Örnek:

Bir tuşa basıncaya kadar ekrandan girilen rakamları okuyan bir program, aşağıda sunulmuştur.

PREDICATES

sayi(integer)

sayilari_yaz(integer)

kullanici_komutu(unsigned)

CLAUSES

sayi(0).

sayi(N):-sayi(N1), N=N1+1.

sayilari_yaz(N):- getbacktrack(BTOP), sayi(N), kullanici_komutu(BTOP).

kullanici_komutu(BTOP):- keypressed, cutbacktrack(BTOP).

kullanici_komutu(_).

Derleyici, cümleleri determinism bakımından kontrol eden yüklemdeki cutbacktrack yüklemini tanımaz. Yani check_term direktifini kullanırken non-deterministic cümle uyarısı alınabilir. Dinamik kesme kullanırken çok dikkatli olmak gerekir. Çünkü programın tamamını tahrip etmek, programı çalışamaz hale getirmek mümkündür.

8.15. Programlama Stilleri

Visual Prolog’da program yazarken dikkat edilmesinde fayda olan bazı temel özellikler vardır. Bu özellikler artık kural haline gelmiştir. Etkili programlama yapabilmek için şu kurallara dikkat edilmelidir:

Kural 1. Fazla yüklem yerine daha fazla değişken kullanın

Bu kural programın okunabilirliği ile ters orantılıdır. Genelde Prolog’un dekleratif olan stili, diğer konvansiyonel yaklaşımlara göre daha az verimlidir. Örneğin, bir listenin elemanlarını tersine çeviren bir yüklem yazmak için aşağıdaki program parçası kullanılabilir:

tersine_cevir(A, B):- tersine_cevir1([], A, B).

tersine_cevir1(B, [], B).

tersine_cevir1(A1, [U|A2], B):- tersine_cevir1([U|A1], A2, B).

Kural 2. Çözüm olmadığı zaman program çalışmasının etkili bir biçimde bittiğinden emin olun

Yazdığımız bir maksimum_deger yüklemiyle bir listedeki tamsayıların büyük bir sayıya kadar düzenli olarak arttığını, daha sonra yine düzenli bir şekilde azaldığını kontrol etmek istiyoruz. Bu yüklemi kullanarak

maksimum_deger([1, 2, 5, 7, 11, 8, 6, 4]) şeklindeki bir sorgu başarılı olur. Fakat

maksimum_deger([1, 2, 3, 9, 6, 8, 5, 4, 3]) başarısız olur.

Kural 3. Geriye İz Sürme mekanizmasını mümkün olduğunca çok kullanın.

esitlik seklinde tanımlanan bir yüklemin iki listenin elemanlarını karşılaştırmak için kullanalım. Bunun için:

esitlik([], []).

esitlik([U|X], [U|Y]):- esitlik(X, Y)

kullanmak gereksizdir. Çünkü bunun yerine daha basit olan esitlik(X, X) kullanılabilir.

Kural 4. Rekursiyon veya Tekrarlama Yerine Geriye İz Sürme Mekanizmasını Kullanın

Geriye İz Sürme mekanizması bellek ihtiyacını azaltır. Bu yüzden rekursiyon yerine repeat-fail kombinasyonunu kullanmak gerekir. Bu konu hakkında birkaç örnek verelim.

Alt hedefleri tekrarlı bir şekilde kullanmak için genelde basla gibi bir yüklem tanımlayıp sonuçları hesaplamak gerekir.

Örnek:

basla:-

readln(X), islem_yap(X, Y), write(Y), basla.

Bu tür bir tanımlama gereksiz yere rekursiyon yapar. islem_yap(X,Y) non-deterministic ise sistem tarafından gereksiz olan bu rekursiyon otomatik olarak ortadan kaldırılabilir.

Bu durumda repeat…fail ikilisi kullanmak gerekir. Bunun için yukarıdaki işlemleri şöyle yazmak mümkündür.

basla:-

tekrar, readln(X), islem_yap(X, Y), write(Y), fail.

fail komutu, islem_yap yükleminine geriye dönüş yapar, buradan da tekrar yüklemine geçer, bu yüklem daima başarılı olur. Burada önemli olan şey bu döngünün dışına çıkmaktır. Genelde döngü dışına çıkmak için belli şartlar aranıldığı için, döngü içine bu şartı yazmak mümkündür. Yani:

basla:-

tekrar, readln(X), islem_yap(X, Y), write(Y), bitisi_kontrol_et(Y), !.

8.15. Cut Yüklemini Yerleştirmek

check_determ direktifi, cut yükleminin nereye yerleştirilmesi gerektiği konusunda karar verirken çok faydalıdır. Non-deterministic davranışı olan cümlecikleri deterministic hale getirip geriye dönüşü engellemek için cut kullanılmadır.

Böyle bir durumda genel bir kural olarak şunu söyleyebiliriz: cut komutunu, programın mantığını bozmayacak şekilde, mümkün olduğuca bir kuralın başına yakın bir yere konulmalıdır. Derleyici aşağıdaki iki kuralı dikate alarak bir cümleciğin deterministic veya non-deterministic olduğuna ;

2.     Cümlede cut yoksa ve cümlenin başındaki argümanlarla eşleşebilecek başka bir cümlecik varsa

3.     Cümle gövdesinde non-deterministic başka bir yükleme çağrı varsa ve non-deterministic olan bu çağrıdan sonra cut yoksa bulunarak karar verilir.


9. ÖZEL GELİŞTİRİLMİŞ PROLOG ÖRNEKLERİ

9.1. Küçük bir Uzman Sistem örneği

Bu örnekte, bazı özellikleri hakkında kullanıcıya soru sorarak 7 hayvandan biri bulunacaktır. Bu hayvanlar hakkında bilinen olgulardan hareketle geriye dönüş mekanizması kullanılarak doğru cevap bulunmaya çalışılacaktır.

DATABASE

     xpositif(symbol,symbol)

     xnegatif(symbol,symbol)

PREDICATES

     nondeterm aranan_canli(symbol)

     nondeterm canli_turu(symbol)

     soru_sor(symbol,symbol,symbol)

     sakla(symbol,symbol,symbol)

     positif(symbol,symbol)

     negatif(symbol,symbol)

     olgulari_sil

     basla

CLAUSES

aranan_canli(cita):-

     canli_turu(memelil),

     canli_turu(etobur),

     positif(sahiptir,sari_kahverengi_renklere),

     positif(sahiptir,siyah_benekler).

aranan_canli(tiger):-

     canli_turu(memeli),

     canli_turu(etobur),

     positif(sahiptir, sari_kahverengi_renkler),

     positif(sahiptir, siyah_seritli).

aranan_canli(zurafa):-

     canli_turu(tirnakli),

     positif(sahiptir,uzun_boyunlu),

     positif(sahiptir,uzun_bacakli),

     positif(sahiptir, siyah_benekler).

aranan_canli(zebra):-

     canli_turu(tirnakli),

     positif(sahiptir,siyah_seritli).

aranan_canli(devekusu):-

     canli_turu(kus),

     negatif(eylem,ucar),

     positif(sahiptir,uzun_boyunlu),

     positif(sahiptir,uzun_bacakli),

     positif(sahiptir, siyah_beyaz_renk).

aranan_canli(penguen):-

     canli_turu(kus),

     negatif(eylem,ucar),

     positif(eylem,yuzer),

     positif(sahiptir,siyah_beyaz_renk).

aranan_canli(albatros):-

     canli_turu(kus),positif(eylem,iyi_ucar).

canli_turu(memeli):-

     positif(sahiptir,tuylu).

canli_turu(memeli):-

     positif(eylem,sut_verir).

canli_turu(kus):-

     positif(sahiptir,kus_tuyleri).

canli_turu(kus):-

     positif(eylem,ucar),

     positif(eylem,yumurtlar).

canli_turu(etobur):-

     positif(eylem,et_yer).

canli_turu(etobur):-

     positif(sahiptir,sivri_disleri),

     positif(sahiptir, pencelere),

        positif(sahiptir,patlak_gozler).

canli_turu(tirnakli):-

     canli_turu(memeli),

     positif(sahiptir,toynaklar).

canli_turu(tirnakli):-

     canli_turu(memeli),

     positif(eylem,gevis_getirme).

positif(X,Y):-

     xpositif(X,Y),!.

positif(X,Y):-

     not(xnegatif(X,Y)),

     soru_sor(X,Y,evet).

negatif(X,Y):-

     xnegatif(X,Y),!.

negatif(X,Y):-

     not(xpositif(X,Y)),

     soru_sor(X,Y,hayir).

soru_sor(X,Y,evet):-!,

     write(X,” aranan canli:”,Y,’\n’),

     readln(Cevap),nl,

     frontchar(Cevap,’e’,_),

     sakla(X,Y,evet).

soru_sor(X,Y,hayir):-!,

     write(X,” aranan canli: “,Y,’\n’),

     readln(Cevap),nl,

     frontchar(Cevap,’h’,_),

     sakla(X,Y,hayir).

sakla(X,Y,evet):-

     assertz(xpositif(X,Y)).

sakla(X,Y,hayir):-

     assertz(xnegatif(X,Y)).

olgulari_sil:-

     write(“\n\nBitirmek icin space tusuna basiniz.\n”),

     retractall(_,dbasedom),readchar(_).

basla:-

     aranan_canli(X),!,

     write(“\n Aradiginiz canli bir “,X, “olabilir.”),

     nl,nl,olgulari_sil.

basla :-

     write(“\nAradiginiz canliyi bulmak mumkun degildir.\n\n”),

     olgulari_sil.

GOAL      basla.

Veritabanındaki her hayvan, sahip olduğu veya olmadığı bazı özelliklerle tanımlanmıştır. Kullanıcının cevaplayacağı sorular olumlu(A, B) veya olumsuz(A, B) şeklindedir. Sorulan bir soruya evet veya hayır şeklinde cevap aldıktan sonra, verilen cevabın veritabanına eklenmesi gerekir. Böylece program karar verirken eski bilgileri kullanır. Burada olumlu ve olumsuz olmak üzere sadece iki yüklem kullanılmıştır.

database

xpozitif(symbol, symbol)

xnegatif(symbol, symbol)

Böylece aradığımız hayvanın tüylü değilse, xnegative(vardir, tuy) şeklindeki olguyu kullandık. Pozitif ve negatif kurallar, kullanıcının verdiği cevabın önceden bilinip bilinmediğini kontrol eder.

pozitif(X,Y):-

     xpozitif(X,Y),!.

pozitif(X,Y):-

     not(xnegatif(X,Y)),

     soru_sor(X,Y,evet).

negatif(X,Y):-

     xnegatif(X,Y),!.

negatif(X,Y):-

     not(xpozitif(X,Y)),

     soru_sor(X,Y,hayir).

Pozitif ve negatif kurallarının ikinci kuralı, kullanıcıya yeni bir soru sormadan önce arada bir zıtlık olup olmadığını kontrol eder. Tanımladığımız soru_sor yüklemi kullanıcıya soru sorar ve alınan cevapları düzenler. Cevap e ile başlarsa olumlu, h ile başlarsa olumsuz olarak kabul edilir.

ask(X,Y,yes):-!, write(X,” it “,Y,’\n’), readln(Reply),nl,

frontchar(Reply,’y’,_), remember(X,Y,yes).

ask(X,Y,no):-!, write(X,” it “,Y,’\n’), readln(Reply),nl,

frontchar(Reply,’n’,_), remember(X,Y,no).

remember(X,Y,yes):-assertz(xpositive(X,Y)).

remember(X,Y,no):-assertz(xnegative(X,Y)).

clear_facts:-write(“\n\nÇıkmak için boşluk tuşuna basınız\n”), retractall(_,dbasedom),readchar(_).

9.2. Basit bir yön problemi

Türkiye’deki birkaç şehir arasındaki en uygun yolu bulmak için bir program yapalım. Program bize iki şehir arasında yol olup olmadığını sorsun. Vereceğimiz cevaba göre en uygun yolu bize göstersin. Burada geriye iz sürme ve rekursiyon metotlarını kullanacağız.

DOMAINS

sehir           = symbol

mesafe      = integer

PREDICATES

nondeterm yol(sehir,sehir,mesafe)

nondeterm guzergah(sehir,sehir,mesafe)

CLAUSES

yol(mardin,sanliurfa,190).

yol(gaziantep,mardin,320).

yol(sanliurfa,gaziantep,146).

yol(sanliurfa,elazig,348).

yol(gaziantep,elazig,540).

guzergah(_1_Sehir,_2_Sehir,Mesafe):-

yol(_1_Sehir,_2_Sehi, Mesafe).

guzergah(_1_Sehir,_2_Sehir,Mesafe):-

yol(_1_Sehir,X,Mesafe1),

guzergah(X,_2_Sehir,Mesafe2),

Mesafe=Mesafe1+Mesafe2, !.

GOAL guzergah(sanliurfa,elazig, Toplam_Mesafe).

Yol yüklemi için kullanılan her bir cümlede, bir şehirden diğerine olan yolun km cinsinden değeri verilmiştir. guzergah yüklemi ise iki şehir arasında yol olduğunu göstermektedir. Güzergahı takip eden bir sürücünün mesafe parametresiyle gösterilen miktarda gideceği belirtilmiştir. Burada güzergah yüklemi rekursiv olarak tanımlanmıştır. Güzergah, birinci cümlede olduğu gibi sadece tek yol olabilir. Bu durumda toplam mesafe sadece iki şehir arasındaki yoldur. Bir şehirden diğerine gittikten sonra ana hedefe gidiliyorsa, bu durumda toplam yol Mesafe1+Mesafe2 olur.

9.3. Hazine Avcısı

Labirent biçimindeki dehliz ve mağaralardan oluşan bir yerde gizli bir hazine bulunsun. Aynı yerden tekrar geçmeden, tehlikeye yakalanmadan giriş noktasından başlayıp emniyetli bir şekilde çıkıştan geçmek ve hazineyi almak için hangi yolu takip etmeliyiz?

Önce hazinenin yerini gösteren haritaya bakalım.

DOMAINS

oda                        =  symbol

odalarin_listesi     = oda*

PREDICATES

nondeterm galeri(oda,oda)

nondeterm komsu_oda(oda,oda)

buralara_girmek_tehlikeli(odalarin_listesi)

nondeterm git(oda,oda)

nondeterm guzergah(oda,oda,odalarin_listesi)

nondeterm eleman(oda,odalarin_listesi)

CLAUSES

galeri(giris,canavar).       

galeri(giris,cesme).

galeri(cesme,bataklik).    

galeri(cesme,gida).

galeri(cikis,hazine).         

galeri(cesme,denizkizi).

galeri(haydut,hazine).     

galeri(cesme,haydut).

galeri(gida,hazine).

galeri(denizkizi,cikis).

galeri(canavar,hazine).    

galeri(hazine,cikis).

komsu_oda(X,Y):-galeri(X,Y).

komsu_oda(X,Y):-galeri(Y,X).

buralara_girmek_tehlikeli([canavar,haydut]).

git(Baslama_noktasi,Bitis_noktasi):-

guzergah(Baslama_noktasi,Bitis_noktasi,[Baslama_noktasi]).

git(_,_).

guzergah(Oda,Oda,Gidilen_odalar):-

eleman(hazine,Gidilen_odalar),

write(Gidilen_odalar),nl.

guzergah(Oda,Cikis_yolu,Gidilen_odalar):-

komsu_oda(Oda,Sonraki_oda),

buralara_girmek_tehlikeli(Tehlikeli_odalar),

not(eleman(Sonraki_Oda,Tehlikeli_odalar)),

not(eleman(Sonraki_Oda,Gidilen_odalar)),

guzergah(Sonraki_Oda,Cikis_yolu,[Sonraki_Oda|Gidilen_odalar]).

eleman(X,[X|_]).

eleman(X,[_|H]):-eleman (X,H).

GOAL git(cikis, giris).

Buradaki her dehliz bir olguyla temsil edilmiştir. git ve guzergah yüklemleri kuralları belirler. Sorgudan elde edeceğimiz cevapta hazineyi alıp emniyetli bir şekilde dışarı çıkmak için gerekli güzergah belirtilecektir. Programdaki önemli bir özellik, rekursiv olarak tanımlı olan guzergah sayesinde gidilen odaların kataloga alınmasıdır. Çıkış odasına geldiğiniz anda üçüncü parametre o ana kadar ziyaret ettiğiniz odaları listeler. Bu odalar arasında hazine var ise, hedefe varıldı demektir. Eğer listede hazine odası yoksa, Sonraki_oda seçeneği tehlikeli odalara gidilmeyecek şekilde genişletilir.


TARTIŞMA VE SONUÇ

Yapay Zeka kavramı ortaya çıktıktan sonra, yurtdışında bu konuda çok sayıda teorik çalışma, değişik disiplinlerde kullanılan birçok uygulama program gerçekleştirilmiştir. Bu programlar sayesinde, bir insan tarafından yapılması çok zaman alabilen ve hata oranı oldukça yüksek olabilen durumlar ortadan kalkmıştır. Örneğin Digital firması yetkilileri, müşterilerinin siparişlerine göre yeni bir sistem dizaynı yaparken, bu sistemde kullanılabilecek donanım seçeneklerinin çokluğu, her bir parçanın birden fazla parça ile uyumlu çalışabilmesi veya bazı parçaların birbirleriyle hiç uyuşmaması gibi durumlardan dolayı, yapılan montajlarda büyük oranda hataların ortaya çıktığını; ancak yazılan bir uzman sistem ve parçalar hakkındaki gerçeklerden oluşan bir bilgi veritabanı ile bu durumun ortadan kalktığını, ayrıca yılda milyonlarca dolar tasarruf sağladıklarını belirtmişlerdir. Bunun haricinde farklı alanlarda kullanılmak üzere hazırlanan ve başarılı bir şekilde çalışan çok sayıda uzman sistem örneği vermek mümkündür.

Tıpta teşhis ve tedavi planlaması amacıyla bilgi tabancı sistemler, birçok alanda (Örneğin Laboratuar, Onkoloji veya Kardiyoloji gibi) kullanım sahası bulmaktadır. Diş tedavisi alanında bilgisayar kullanımı daha ziyade sadece kayıt amaçlı kullanılmaktadır. Karlsruhe’deki Diş Hekimliği Akademisi ile Bremen Üniversitesi Yapay Zeka Laboratuarı arasında işbirliği yapılarak, bir yazılım geliştirilmiştir. Bu çalışma, diş doktorları için bilgi tabanlı bir dökümantasyon ve karar verme sisteminin oluşturulmasını sağlamaktadır. Sistemin kullanılması halinde, diş hekimliği ile ilgili teşhis ve tedavi önerileri yapılabilmektedir.

Türkiye’de ise, bu alanda çok ciddi çalışmaların var olduğunu söylemek çok zordur. Gebze Yüksek Teknoloji Enstitüsü’ndeki Yapay Zeka Bölümü’nde, askeri amaçlı projeler üzerinde çalışmalar yürütülmektedir. Ayrıca Bilkent ve Orta Doğu Teknik Üniversitelerinde yürütülmekte olan TurkLang gibi büyük projeler mevcuttur. Fakat bu çalışmaların çoğu Unix ortamında yapılmakta olup, bireysel ve endüstriyel kullanıma yönelik değildir.

Yapay Zeka ve bunun alt bölümleri olarak kabul edilen Uzman Sistemler, Yapay Sinir Ağları, Tabii Dil İşlenmesi gibi alanlarda program yapmak için mantık dillerinin yanı sıra, Pascal, C++ gibi konvansiyonel programlama dilleri de kullanılmaktadır. Prolog (Programming in Logic) mantık dillerinden en popüler olanıdır. Önceleri daha çok Unix, VAX gibi işletim sistemleriyle çalışan anaçatı bilgisayarlarda kullanılan Prolog, zamanla DOS, daha sonraları ise Windows ve diğer işletim sistemlerine de aktarılmıştır. Visual Prolog, işte bu aşamalardan sonra çıkarılan, çoklu ortamlarda rahatlıkla kullanılabilen bir mantık dilidir. Visual Prolog’un diğer konvansiyonel dillerden ayrıldığı bazı özellikler şunlardır:

a)      Visual Prolog prosedürel değil tamamen dekleratif bir yapıya sahiptir. Yani çözümü aranan bir problemin nasıl çözüleceğini tanımlamak yerine, problemin kendisini tanımlamak yeterlidir. Kullanıcı tarafından verilen gerçeklere dayanarak, Prolog’da var olan Inference Engine(Karar verme motoru) istenilen problem için mümkün olan bütün çözümleri bulur.

b)      Visual Prolog’daki Geriye İz Sürme mekanizması, konvansiyonel dillerin hiçbirinde bulunmayan güçlü bir özelliktir. Bu özellik sayesinde konvansiyonel dillerdeki FOR..NEXT, DO..WHILE gibi döngüler ortadan kalkar. Prolog, bu özelliği sayesinde, çözüm aranan bir sorguya uygun bütün çözümleri kendiliğinden bulur. Bu durum, döngü komutlarının neden olabileceği hataları baştan itibaren ortadan kaldırır.

c)      Visual Prolog’un diğer bir özelliği ise, nesneler arasındaki ilişkilerin çok kolay bir şekilde tanımlanabilmesi, bu ilişkilere dayalı işlemler yapabilmesidir. Örneğin, kullanilir(“Visual Prolog”, uzman_sistemler) şeklinde ifade edilebilen ‘Visual Prolog dili uzman sistemlerde kullanılır’ cümlesini, konvansiyonel dillerle ifade etmek mümkün değildir.

Visual Prolog ile uygulama Programları yazarken, nesneler arasındaki ilişkileri ifade etmek son derece kolay olmasına rağmen, uygulamanın sonuçları hakkında Türkçe bilgi vermek ve Türkçe’de düzgün cümleler kurmak açısından bazı zorluklar mevcuttur. Bunun temel nedeni, İngilizce ve Türkçe cümle yapılarında öğelerin dizilişlerinde farklılıklar bulunmasıdır. Bu yüzden, Türkçe ifade edilen bir cümlede, özne ve yüklem arasında akıcı bir ilişki kurabilmek için, öğeler arasındaki özelliklerin önceden veritabanına yüklenmesi faydalı olacaktır. Bu çalışma sayesinde, Prolog’un Türkçe’ye uyarlanmasında karşılaşılan problemler detaylı olarak ele alınmış, problemlerin en doğru şekilde nasıl çözümlenebileceği konusunda bazı yazılımlar geliştirilmiştir.

Visual Prolog kullanarak yapay zeka konusunda çalışma yapacaklar için önemli birçok ipuçları örneklerle verildiği bu tez çalışması sayesinde, yapay zeka alanında Türkçe uygulamalarda önemli gelişmeler sağlanabilecektir.


KAYNAKLAR

(1) STERLING; Leon; SHAPHIRO, Ehud; The Art of Prolog, Advanced Programming Techniques, The MIT Press, London, England, 1992.

(2) CLOCKSIN, W.F, MELLISH, C.S, Programming in Prolog, Springer-Verlag Berlin Heidelberg, Germany, 1987.

(3) O’KEEFE, Richard A.; The Craft of Prolog, The MIT Press, London, England, 1990

(4) CASTILLO, E., ALVAREZ, E., Expert Systems: Uncertainity and Learning, Computational Mechanics Publications, Southampton, Boston, America, 1991

(5) GIARRATANO, JOSEPH. C, Expert Systems: Principles and Programming, PWS-KENT Publishing Company, Boston, America,1989.

(6) IGNIZIO, JAMES. P., Introduction to Expert Systems, McGraw-Hill, Inc., America, 1991.

(7) PDC, Visual Prolog Language Tutorial, Copenhagen, Denmark, 1996.

(8) KUŞ, M.; VAROL, A.; OĞUROL, Y.; VAROL, Y.: Verarbeitung von unsiherem Wissen mit Fuzzy-Prolog, Second Turkish-German Joint Computer Application Days, 15-16 October, Konya, 1998

(9) OĞUROL, Y.; VAROL, A.; KUŞ, M.: Anforderungen und Lösungsansätze einer transferierbaren Entwicklungsumgebung für die medizinische Wissenverarbeitung, Second Turkish-German Joint Computer Application Days, 15-16 October, Konya, 1998.

(10) VAROL, A.; VAROL, N.: ESTA İle Bilgisayar Destekli Eğitim, Beta Basım Yayım Dağıtım A.Ş., 299, 1996.

(11) VAROL, A.; VAROL, N.: ESTA Bilgisayar Yazılımı İle Uzman Sistemlerin Hazırlanması Teknikleri, Süleyman Demirel Üniversitesi, Makine Mühendisliği Dergisi, Cilt 1, Sayı 9, 67-72, 1996.

(12) KUŞ, M.; VAROL, A.; OĞUROL, Y.: Uzman Sistemin Dişçilik Alanında Kullanımına Ait Bir Uygulama, Endüstri&Otomasyon, Aylık Elektrik, Elektronik, Makine, Bilgisayar ve Kontrol Sistemleri Dergisi, Sayı: 18, 1998

(13) KUŞ, M.; VAROL, A.; OĞUROL, Y.: Uzman Sistemin Dişçilik Alanında Kullanımına Ait Bir Uygulama, Endüstri&Otomasyon, Aylık Elektrik, Elektronik, Makine, Bilgisayar ve Kontrol Sistemleri Dergisi, Sayı: 18, 1998

(14) VAROL, A.; VAROL, N.: Uzman Sistemlerde ESTA Yazılımının Önemi, Bilişim’96, 18-22 Eylül 1996 İstanbul, Bildiriler Kitabı, 289-294, 1996.

(15) VAROL, A.; VAROL, N.: Uzman Sistem Hazırlanırken Hangi Kriterler Göz Önünde Bulundurulmalı, GAP 2. Mühendislik Kongresi, 21-23 Mayıs 1998, Şanlıurfa, Bildiri Kitabı, S: 559-566,  1998.


ŞEKİLLER ve TABLOLAR

 

Şekil 1. Aile Fertlerinin Şecere Olarak Gösterilmesi……………………………………….. 88

Şekil 2. Şekil 6.1’deki ağaç yapısında Aşağıya-Doğru-Arama metodunun uygulanması.     90

Şekil 3. Binary tarama yapısı………………………………………………………………………. 94

 

Tablo 3.1: Visual Prolog’da Tipler ve Alabilecekleri değerler.…………………………. 25

Tablo 7.2. Listelerin baş ve kuyruk halinde gösterilmeleri……………………………… 100

Tablo 7.3: Liste eşleştirme örnekleri…………………………………………………………. 101

Tablo 8.4. Criticalerror yükleminin argümanlarının aldığı değerler…………………. 134

Prolog – 2

Burada Herhangi_Biri, nefret_eder(ahmet, Herhangi_biri) alt hedefinin doğru olmadığı ispatlanmadan önce Herhangi_biri argümanı sever(esra, Herhangi_biri) alt hedefindeki Herhangi_biri argümanına atanmış olur. Dolayısıyla yukarıdaki kod tam olarak arzu edildiği gibi çalışır. Yukarıdaki kısa program

sever(ahmet, Herhangi_biri):-                 /* ‘Doğru çalışmaz’*/

not(nefret_eder(ahmet, Herhangi_biri),

sever(esra, Herhangi_biri).

şeklinde yazılacak olursa, ilk önce Not ile başlayan cümlecik çağrılmış olur. Not cümleciği içinde serbest değişken tanımlamak mümkün olmadığı için, Prolog hata mesajı vermiş olur. Çünkü not(nefret_eder(ahmet, Herhangi_Biri) cümleciğindeki Herhangi_biri argümanı serbest değişkendir ve hiçbir değeri yoktur. Programdaki Herhangi_biri yerine anonim değişken olan (_) kullanılsa bile, Prolog yine yanlış bir sonuç verecektir.

sever(ahmet, Herhangi_biri):-                 /*Doğru çalışmaz*/

not(nefret_eder(ahmet, _),

sever(esra, Herhangi_biri).

Çünkü yukarıdaki cümlelerden anlaşılan şudur: Eğer Ahmet’in nefret ettiği bir şey bilinmiyorsa ve eğer esra Herhangi_biri’ni seviyorsa, Ahmet Herhangi_biri’ni sever. Anlatılmak istenen şey ise şudur: Esra’nın sevdiği ve Ahmet’in de nefret etmediği Herhangi_biri varsa, Ahmet bu Herhangi_biri’ni sever.

Not yüklemini kullanırken çok dikkatli olmak gerekir. Yanlış kullanım, ya hata mesajı alınmasına ya da program içerisinde mantıksız bir yapıya neden olacaktır.

Örnek:

PREDICATES

Nondeterm alisveristen_hoslanir(symbol)

Nondeterm kredi_kartina_sahip(symbol, symbol)

kredisi_bitmis(symbol, symbol)

CLAUSES

alisveristen_hoslanir(Kim):-

kredi_kartina_sahip(Kim,Kredi_karti),not(kredisi_bitmis(Kim,Kredi_karti)),

write(Kim, Kredi_karti, “ile alışveriş yapabilir\n”).

kredi_kartina_sahip(yavuz, visa).

kredi_kartina_sahip(yavuz, diners).

kredi_kartina_sahip(ahmet, shell).

kredi_kartina_sahip(mehmet, masterkart).

kredi_kartina_sahip(asaf_bey, akbank).

kredisi_bitmis (yavuz, diners).

kredisi_bitmis (asaf_bey, masterkart).

kredisi_bitmis (yavuz, visa).

GOAL alisveristen_hoslanir(Kim).

 

Örnek:

DOMAINS

isim,cinsiyet,meslek,cisim,yardimci,madde = symbol

yas=integer

PREDICATES

nondeterm sahis(isim, yas, cinsiyet, meslek)

nondeterm iliskili(isim, isim)

ile_oldurdu(isim, cisim)

oldurdu(isim)

nondeterm katil(isim)

sebep(yardimci)

uzerinde_leke_var(isim, madde)

sahip(isim, cisim)

nondeterm birbirine_benzer(cisim, cisim)

nondeterm sahip_oldugu_cisim(isim, cisim)

nondeterm supheli(isim)

/* * * Katil hakkındaki gerçekler * * */

CLAUSES

sahis(huseyin,55,m,arastirma_gorevlisi).

sahis(yavuz,25,m,futbolcu).

sahis(yavuz,25,m,kasap).

sahis(ahmet,25,m,yankesici).

iliskili(fatma,ahmet).

iliskili(fatma,huseyin).

iliskili(deniz,ahmet).

ile_oldurdu(deniz,sopa).

oldurdu(deniz).

sebep(para).

sebep(kiskanclik).

sebep(durustluk).

uzerinde_leke_var(huseyin, kan).

uzerinde_leke_var(deniz, kan).

uzerinde_leke_var(yavuz, camur).

uzerinde_leke_var(ahmet, cikolata).

uzerinde_leke_var(fatma,cikolata).

sahip(huseyin,tahta_bacak).

sahip(ahmet,tabanca).

/* Temel Bilgiler */

birbirine_benzer(tahta_bacak, sopa).

birbirine_benzer(demir, sopa).

birbirine_benzer(makas, bicak).

birbirine_benzer(futbol_sopasi, sopa).

sahip_oldugu_cisim(X,futbol_sopasi):-sahis(X,_,_,futbolcu).

sahip_oldugu_cisim(X,makas):-sahis(X,_,_,kuafor).

sahip_oldugu_cisim(X,Cisim):-sahip(X,Cisim).

/* Susan’ın oldürüldüğü silaha sahip herkesi şüpheli kabul edilsin */

supheli(X):-

     ile_oldurdu(deniz,Silah) ,

     birbirine_benzer(Cisim,Silah) ,

     sahip_oldugu_cisim(X,Cisim).

/* Susan ile ilişkisi olan insanlar da şüpheliler listesine girmeli */

supheli(X):-

     sebep(kiskanclik),

     sahis(X,_,m,_),

     iliskili(deniz,X).

/* Susan’ın, ilişkilerinden haberdar olduğu bayanlar da şüpheli listemizde olmalı */

supheli(X):-

     sebep(kiskanclik),

     sahis(X,_,f,_),

     iliskili(X,Erkek),

     iliskili(deniz,Erkek).

/* Şüpheli, para için katil olan bir yankesici olabilir */

supheli(X):-

     sebep(para),

     sahis(X,_,_,yankesici).

katil(Katil):-

     sahis(Katil,_,_,_),

     oldurdu(Olduruldu),

     Olduruldu <> Katil, /* It is not a suicide */

     supheli(Katil),

     uzerinde_leke_var(Katil,Devam),

     uzerinde_leke_var(Olduruldu,Devam).

GOAL

     katil(Katil_Kim).

4.8. Prosedürel Açıdan Prolog

Prolog tanımsal yapıya sahip bir dildir. Program hazırlarken problem olgular(önceden bilinen gerçekler) ve kurallarla tanımlanır. Bunu takiben bilgisayardan çözüm bulması beklenir. Pascal, BASIC ve C gibi diller ise tamamen prosedürlere dayanırlar. Bilgisayarın belli bir probleme çözüm bulabilmesi için, programcının, yapılması gereken işlemleri alt programlar ve fonksiyonlar halinde adım adım tanımlaması gerekir.

4.8.1. Kurallar ve Olguların Prosedürlere Benzerliği

Prolog’daki bir kuralı diğer dillerdeki bir procedure olarak görmek mümkündür. Örneğin

sever(ahmet, Birsey):- sever(gul, Birsey).

şeklindeki bir kural ‘Ahmet’in bir şeyi sevdiğini ispatlamak için, Gül’ün de aynı şeyi sevdiğini ispat et’ anlamına gelir. Aynı şekilde

sever(Orhan, Baklava).

şeklindeki Prolog kuralı “Orhan’ın baklava sevdiğini ispat etmek için dur” anlamındaki bir procedure olarak düşünmek mümkündür. Burada sever(Kim, Ne) şeklinde bir sorgu gelirse, Kim ve Ne serbest değişkenleri sırasıyla Orhan ve Baklava değerlerini alırlar.

Case ifadesi, boolean testleri ve goto komutu diğer dillerde mevcut olan procedure örnekleridir. Benzer işlemleri, kuralları kullanarak yapabiliriz.

4.8.2. Bir Kuralın Case ifadesi Gibi Kullanılması

Prolog’daki Kural ile diğer dillerdeki Procedure arasındaki büyük farklardan biri, Prolog’un aynı procedure için birden fazla alternatif tanımlama imkanı vermesidir.

Pascal’daki CASE ifadesi kullanıyormuş gibi, her argüman değeri için farklı bir tanım yazarak çoklu tanım kullanabilirsiniz. Prolog kuralları peşpeşe kullanarak eşleşenleri bulur ve kuralın tanımladığı işlemi yapar.

Örnek:

PREDICATES

nondeterm basilan_tus(integer)

CLAUSES

basilan_tus(1):-

nl,

write(“1 Tuşuna Bastınız.”), nl.

basilan_tus(2):-

nl,

write(“2 Tuşuna Bastınız.”), nl.

basilan_tus(3):-

nl,

write(“3 Tuşuna Bastınız.”), nl.

basilan_tus(N):-

nl,

N<>1, N<>2, N<>3, write(“Hangi Tuşa Bastığınızı Bilmiyorum”), nl.

GOAL write(“1-3 arasında bir sayı yazınız: “), readint(Sayi), basilan_tus(Sayi).

Örnekte, 1, 2 veya 3 haricindeki rakamlar girildiğinde eşleşme olamaz ve çözüm bulunmaz.

4.8.3. Bir Kural İçinde Test Yapmak

Yukarıdaki örnekte geçen basilan_tus(N) cümleciğinde; verilecek herhangi bir değere otomatik olarak N’e atanacaktır. Burada verilen sayının sadece 1-3 aralığı dışında olması durumunda ‘Hangi Tuşa Bastığınızı Bilmiyorum’ mesajının görüntülenmesi gerekir. Bu N<>1, N<>2, N<>3 alt hedefleri ile gerçekleştirilmektedir. Prolog ilk önce yazılan değerin 1-3 arasında olup olmadığını doğrulamaya çalışır. Doğru olmadığını görünce geriye dönüş işlemi yapmaya çalışır. Fakat başka alternatif olmadığı için bu cümlenin geriye kalan kısmına geçiş yapamaz.

Basilan_tus ilişkisi atanacak olan seçeneklere dayanır. Eğer basilan_tus ilişkisi argümanı serbest olan bir değişken ile çağılırsa, GOAL bu cümlelerin hepsiyle eşleşir ve ilk üç kural alternatif çözümler olarak sunulur. Son cümle ise hataya neden olur. Çünkü bağımsız bir değişkeni bir sayı ile eşleştirmek mümkün değildir.

4.8.4. Cut Komutunun Goto Gibi Kullanılması

Yukarıdaki örnek vakit kaybına neden olur. Çünkü doğrulanan bir kural bulunsa bile, Prolog’un son kuralı da test edip başka alternatif araması gerekir. Prolog’a alternatif aramaktan vazgeçmesini söylemek için Cut komutu kullanılabilir. Bunun sonucu, bize zaman ve bellek tasarrufu sağlanır.

Yukarıdaki program, şimdi de Cut komutu ile yazılsın.

PREDICATES

nondeterm basilan_tus(integer)

CLAUSES

basilan_tus(1):- !,

nl,

write(“1 Tuşuna Bastınız.”), nl.

basilan_tus(2):- !,

nl,

write(“2 Tuşuna Bastınız.”), nl.

basilan_tus(3):- !,

nl,

write(“3 Tuşuna Bastınız.”), nl.

basilan_tus(_):- !, write(“Hangi Tuşa Bastığınızı Bilmiyorum”), nl.

GOAL write(“1-3 arasında bir sayı yazınız: “), readint(Sayi), basilan_tus(Sayi).

Cut komutunun işleme girebilmesi için Prolog’un içinde Cut bulunan bir kurala gitmesi ve Cut komutunun bulunduğu noktaya kadar gelmiş olması gerekir.

Cut komutu basilan_tus(X):- X>3, !, write(“Yazdığınız rakam çok yüksek”) gibi testlerden önce gelebilir. X>3 alt hedefi doğrulandığı anda Cut komutu önemli hale gelir. Burada kuralların sırası oldukça önemlidir. 13. örnekte kurallar; arzu edilen sıraya göre yazılabilir. Çünkü onlardan sadece biri girilen bir sayı ile eşleşir. Fakat Cut kullanılan yukarıdaki örnekte, bilgisayarın write(“Hangi Tuşa Bastığınızı Bilmiyorum”) kuralına diğer üç kuralı denemeden önce kesinlikle geçmediğinden emin olmak gerekir. Çünkü buradaki Cut komutları red_cut, yani olumsuz cut, görevi görürler ve programın mantığını değiştirirler.

Eğer yukarıdaki programda X<>1, X<>2 ve X<>3 şeklindeki karşılaştırma anahtarlarını tutup her cümleye sadece bir Cut komutu yerleştirilirse, buradaki Cut komutları Green Cut olarak görev yaparlar. Cut, diğer programlama dillerinde tıpkı GOTO komutu gibi görev görür. Cut komutunun kullanımı faydalıdır, fakat içinde Cut kullanılan programları anlamak bazen zor olabilir.

4.9. Hesaplanmış Değerleri Görüntüleme

Program akışında, ilk başta herhangi bir değeri olmayan argümanlar, daha sonra belirli değerle alırlar. Örneğin

sever(orhan, gulsah).

şeklindeki bir olgu

sever(orhan, Kim)

şeklindeki bir hedef cümlesindeki Kim argümanına ‘Gulsah’ değerini atamış olur. Yani

GOAL sever(orhan, Kim) hedef cümlesindeki Kim argümanı ilk önce serbest olmasına rağmen, sever(orhan, gulsah) olgusunu çağırdığı anda olgudaki Gulsah değeri Kim argümanına atanır ve Kim argümanı sınırlı hale gelir.

Örnek:

PREDICATES

nondeterm ekrana_yaz(integer, symbol)

CLAUSES

ekrana_yaz(0, sifir).

ekrana_yaz(Sayi, negatif):- Sayi<0.

ekrana_yaz(Sayi, pozitif):- Sayi>0.

GOAL ekrana_yaz(14, Sayinin_isareti).

‘ekrana_yaz’ ilişkisinin ilk argümanı daima sabit bir sayı ve bağlı bir değişken olmak zorundadır. İkinci argüman ise sınırlı veya sınırsız bir değişken olabilir. İlk değişkene bağlı olarak sıfır, negatif veya pozitif bir sayı olabilir.

Yukarıdaki GOAL cümleciğinin bulacağı cevap elbette yes olacaktır. Çünkü 14 sıfırdan büyük bir sayıdır ve pozitiftir. Burada sadece 3. cümlecik doğrudur.

GOAL ekrana_yaz(14, negatif).

Hedef cümlesiyle aynı prosedür takip edilir ve no cevabı alınır. Prolog’un sonuç alması incelenirse,

·        İlk önce ilk cümlecik incelenir. Belirle ilişkisindeki argümanlar, yani 14 ve negatif değerleri, 0 ve sifir değerleriyle eşleşmezler.

·        İkinci cümleciğe sıra geldiğinde, Sayi 14’e eşitlenir fakat sayi<0 testi doğrulanamaz.

·        Üçüncü argümana gelindiğinde bu kez ikinci argümanlar eşleşmez, yani pozitif kelimesi negatif ile eşleşemez.

Anlamlı bir cevap almak için örneğin GOAL belirle(14, Sayinin_Isareti) kullanılırsa,

Sayinin_Isareti=pozitif

1 Solution

cevabı alınır.

Yukarıdaki örneğin çalışması esnasında, işlemler aşağıdaki sıra ile yapılacaktır.

ekrana_yaz(14, Sayinin_Isareti) hedef cümlesi, ilk cümleciğin ekrana_yaz(0, sifir) kısmıyla eşleşmez. Bu yüzden ilk cümlecik kullanılamaz.

1.     ekrana_yaz(14, Sayinin_Isareti) hedef cümlesi ikinci cümleciğin baş kısmıyla eşleşir ve Sayi=14, Sayinin_Isareti=negatif olur. Fakat hemen sonraki Sayi<0 yanlış olduğundan Prolog bu cümlecikten geriye döner ve Sayi=14 değeri iptal edilir.

2.     ekrana_yaz(14, Sayinin_Isareti) hedef cümlesi üçüncü cümleciğin baş kısmıyla eşleşir ve Sayi=14, Sayinin_Isareti=pozitif olur. Sayi>0 eşitliği de sağlandığı için Prolog artık geriye iz sürme işlemini yapmaz ve sonucu görüntüler.


5. BASİT VE BİLEŞİK NESNELER

Şimdiye kadar Prolog’da kullanılan veri nesnelerinden number, symbol, string gibi birkaç tip incelenmiştir. Bu bölümde basit ve bileşik veri türlerinin tamamı incelenecektir. Standart tip olarak tanımlanabilen veriler, bazı bileşik veri yapılarını içermezler. Bu yüzden farklı veri yapılarına göz atarak, bunların domains ve predicates bölümlerinde nasıl tanımlanabileceği göreceğiz.

5.1. Basit veri nesneleri

Basit bir veri nesnesi, bir değişken veya bir sabitten oluşabilir. Sabit, constants bölümünde tanımlanan veri tipi değil; char, integer, symbol, string gibi değişmeyen bir nesnedir.

5.1.1 Veri Nesneleri Olan Değişkenler

VIP değişkenleri A-Z arasındaki büyük bir harf veya (_) ile başlamalıdır. (Değişken isimlerinde ç, İ, ö, ğ, ş vs. gibi Türkçe karakterler kesinlikle kullanılamaz) Yalnız başına kullanılan (_) değişkeninin anonim değişken olduğunu ve herhangi bir değerle eşleşebileceği bilinmektedir. Prolog’daki değişkenler global değil, lokaldir. Yani iki ayrı cümlecikte aynı isimle -örneğin X- gösterilen bir değişken farklıdır. Eşleşme sırasında birbiriyle eşleşebilir, fakat temelde birbiri üzerinde hiçbir etkisi yoktur.

5.1.2. Veri Nesneleri Olan Sabitler

Sabitler karakter, sayı veya atom biçiminde olabilirler.

5.1.3. Karakterler

Karakterler char kelimesi ile gösterilir ve 0-9, A-Z ve a-z, ASCII 127 karakter tablosundaki değerleri alabilirler. Fakat ASCII 32 (boşluk) ve daha küçük karakterler kontrol amacıyla kullanılırlar.

Tek karakterlik bir sabit şöyle yazılır:

‘a’ ‘3’       ‘*’       {       ‘W’      ‘A’      ‘\\’=\    ‘\’’=’    ‘\225’=b (ASCII 225)

Bunların dışında başka fonksiyonları olan karakterler de vardır.

‘\n’                       Yeni satıra geçiş komutu

‘\r’                        Satır sonu

‘\t’                        Yatay sekme (tab)

5.1.4. Sayılar

Sayılar tamsayı ve reel olabilirler. Reel sayılar 10-308-10+308arasında değişirler.

Örnek:

Tamsayılar                                   Reel Sayılar

10                                                3.

-77                                               34.96

32034                                          -32769

-10                                               4*10+27

5.1.5. Atomlar

Bir atom symbol veya string olabilir. İkisi arasındaki fark genelde Prolog’un çalıştırıldığı sisteme bağlıdır.

Prolog string ve symbol tipleri arasında otomatik dönüştürme yapabilir. Dolayısıyla symbol ve string tipindeki değişkenler birbirinin yerine kullanılabilirler. Fakat programcılıkta yaygın olan adet, çitf tırnak (“) içine alınması gereken sabitleri string, çitf tırnak gerektirmeyen sabitleri de symbol olarak kabul etmektir.

Symbol: küçük harfle başlayan ve sadece harf, rakam ve _ karakterlerini içerir.

String: Çift tırnak içine alınabilen ve string sonunu belirleyen 0 (Sıfır) hariç, herhangi bir karakteri içerebilir.

Symbol                 String

Yemek                             “Yavuz AYDIN”

Ahmetin_babasi   “ 12. Cadde”

A                          “a”

PdcProlog                        “Visual Prolog Development Center”

5.2. Bileşik Veri Nesneleri ve Fonksiyon Operatörleri

Bileşik veri nesneleri, birden fazla parçadan oluşan verileri tek bir parçaymış gibi kullanma imkanı tanır. Mesela 16 Mayıs 1998 tarihi gün, ay ve yıl olarak 3 parçadan oluşan bir bilgiyi temsil eder. Bu tür bir bilgiyi tek bir parçaymış gibi kullanmaya imkan tanıyan sabitler vardır.

Örnek:

Domains

Islem_tarihi= date(string, unsigned, unsigned)

şeklindeki bir tanımdan sonra D=date(“Mayıs”, 16, 1998) şeklinde yazılabilir. Burada D bir olgu değil, symbol veya sayı gibi kullanılabilecek bir veridir. Bu tür ifadeler genelde bir fonksiyon operatörü ve takip eden 3 argüman ile başlar. Operatörler herhangi bir hesaplama yapamazlar. Sadece bir tür bileşik veri nesnelerini tanımlar ve argümanların tek veriymiş gibi tutulmasına imkan tanır.

Bileşik veri nesnelerinin argümanları da bileşik olabilir. Örneğin

Dogum_Gunu

Kisi                                  date

“Ahmet”“SAGMEN”          “Mart” 15 1976

şeklinde gösterilen bir tarihi Prolog’da

dogum_tarihi(kisi(“Ahmet”,“SAGMEN”),date(“Mart”,15,1976)) şeklinde yazılabilir.

Bu örnekte dogum_tarihi bileşik nesnesinin iki bölümü vardır: kisi(“Ahmet”, “SAGMEN”) ve date(“Mart”, 15, 1976). Buradaki operatörler kisi ve date’dir.

5.3. Bileşik Nesnelerin Eşleştirilmesi

Bileşik bir nesne basit bir değişken veya kendisine uyan diğer bir bileşik nesne ile eşleşebilir. Örneğin date(“Nisan”, 18, 1983) şeklindeki bir clause tarih clause’una tam olarak eşleşir. Aynı şekilde date(“Nisan”, 18, 1983) date(Ay, Gun, Yil) cümleciğinde Ay=Nisan, Gun=18, Yil=1983 değerlerine atanır.

5.4. Bileşik Nesneleri Eşleştirmek İçin ‘=’ Sembolünün Kullanılması

VIP iki durumda eşleştirme işlemi yapar. İlki bir Goal veya çağrı fonksiyonunun bir cümleciğin baş kısmıyla eşleşmesi durumunda meydana gelir. İkincisi ise ‘=’ işaretinin argümanlar arasında kullanılması durumunda meydana gelir.

Prolog, eşitliğin her iki tarafındaki aynı işaretli nesneleri eşleştirmek için gerekli bağlantıları yapar. Aşağıdaki örnekte, soy isimleri aynı olan iki kişiyi bulup her ikisinin adreslerini eşitleyelim.

DOMAINS

sahis=sahis(isim, adres)

isim=isim(adi, soyadi)

adres=adres(cadde, sehir, ulke)

cadde=cadde(cadde_no, cadde_ismi)

sehir, ulke, cadde_ismi=string

adi, soyadi= string

cadde_no= integer

GOAL

P1 = sahis(isim(orhan, aydin), adres(cadde(5, “1. Cadde”), “Elazig”, “Turkiye”)),

P1= sahis(isim(_, aydin), Adres),

P2= sahis(isim(oktay, aydin), Adres),

write(“Birinci Sahis =”, P1), nl,

write(“İkinci Sahis =”, P2), nl.

5.5. Birden Fazla Nesneyi Tek Nesne Olarak Kullanmak

Prolog’da yazılmış programlarda bileşik nesneleri tek bir nesne gibi kullanmak kolaydır. Bu da programcılığı oldukça kolaylaştırır. Örneğin

sahiptir(fatih, kitap(“Visual Prolog İle Programlama”, “Prof.Dr. Asaf VAROL”)).

cümlesi ‘Fatihin Prof.Dr. Asaf Varol tarafından yazılan Visual Prolog ile Programlama adlı bir kitabı var’ anlamındadır. Benzer şekilde;

sahip(fatma, sevgili(can)).

cümlesi “Fatma’nın, ismi Can olan bir sevgilisi var” anlamına gelir. kitap(“Visual Prolog İle Programlama”, “Prof.Dr. Asaf VAROL”) ve sevgili(can) cümlelerdeki bileşik nesnelerdir.

Bileşik nesne kullanmanın önemli bir avantajı, birden fazla argümandan oluşan cümleleri sadece bir argüman olarak kullanabilmektir.

Örnek:

Basit bir telefon rehberi veritabanı programı

PREDICATES

Adres_listesi(symbol, symbol, symbol, symbol, integer, integer) /*(adi, soyadi, telefonu, ay, gun, yil)*/

clauses

adres_listesi(davut, yildirim, 3128456, ocak,6, 1978).

adres_listesi(maksut, hazneci, 3154878, nisan,14, 1969).

adres_listesi’ndeki 5 argümanı

sahis(Adi, Soyadi), dogum_tarihi(Ay,Gun,Yil).

şeklinde yazmak mümkündür. Yeni şekliyle program şöyle yazılabilir:

Domains

Adi= sahis(symbol, symbol)                                           /* (Adi, Soyadı)*/

Dogum_tarihi= d_tarihi(symbol, integer, integer)          /*(Ay, Gün, Yıl)*/

Telefon_no= symbol                                                       /* Telefon no*/

Predicates

adres_listesi(adi, telefon_no, d_tarihi)

clauses

adres_listesi(sahis(davut, yildirim), 3128456, d_tarihi(ocak,6, 1978)).

adres_listesi(sahis(maksut, hazneci), 3154878, d_tarihi(nisan,14, 1969)).

Şimdi yukarıdaki küçük programa birkaç kural daha ilave edip, doğum tarihleri bugünün tarihi ile uyuşanları bulmaya çalışalım. Programda standart yüklem olan date kullanılarak bugünün tarihi bilgisayardan alınacaktır.

DOMAINS

adi = sahis(symbol,symbol)                                            /* (Adı, Soyadı) */

dogum_gunu = d_gunu(symbol,integer,integer)                        /* (Ay, Gun, Yıl) */

tel_no = symbol                                                              /* Telefon Numarası */

PREDICATES

nondeterm tel_listesi(adi,symbol,dogum_gunu)

d_gunu_ayini_bul

ay_donustur(symbol,integer)

d_gunu_ayini_kontrol_et(integer,dogum_gunu)

sahsi_yaz(adi)

CLAUSES

d_gunu_ayini_bul:-

write(“====Bu ay doğanların listesi =======”),nl,

write(” Adı\t\t Soyadı\n”),

write(“==============================”),nl,

date(_, Bu_ay, _),                                   /* Tarihi bilgisayardan oku */

tel_listesi(Sahis, _, Date),

d_gunu_ayini_kontrol_et(Bu_ay, Date),

sahsi_yaz(Sahis),

fail.

d_gunu_ayini_bul:-

write(“\n\n Devam etmek için herhangi bir tuşa basın “),nl,

readchar(_).

sahsi_yaz(sahis(Adi,Soyadi)):-

write(” “,Adi,”\t\t “,Soyadi),nl.

d_gunu_ayini_kontrol_et(Yeni_ay,d_gunu(Ay,_,_)):-

ay_donustur(Ay,Ay1),

Yeni_ay = Ay1.

tel_listesi(sahis(paki, turgut), “267 78 41”, d_gunu(ocak, 3, 1965)).

tel_listesi(sahis(arif, gurel), “338 41 23”, d_gunu(subat, 5, 1972)).

tel_listesi(sahis(mehmet_can, hallac), “512 56 53”, d_gunu(mart, 3, 1965)).

tel_listesi(sahis(cuma, cetiner), “267 22 23”, d_gunu(nisan, 29, 1963)).

tel_listesi(sahis(omer, akgobek), “355 12 12”, d_gunu(mayis, 12, 1971)).

tel_listesi(sahis(fatih, dilekoglu), “438 63 42”, d_gunu(haziran, 17, 1970)).

tel_listesi(sahis(levent, aksun), “567 84 63”, d_gunu(haziran, 20, 1972)).

tel_listesi(sahis(cengiz, gok), “255 56 53”, d_gunu(temmuz, 16, 1973)).

tel_listesi(sahis(kasim, yenigun), “132 22 23”, d_gunu(agustos, 10, 1968)).

tel_listesi(sahis(husamettin, bulut), “412 48 34”, d_gunu(eylul, 25, 1967)).

tel_listesi(sahis(arif, demir), “315 24 21”, d_gunu(ekim, 20, 1992)).

tel_listesi(sahis(sezen, demir), “233 13 12”, d_gunu(kasim, 9, 1980)).

tel_listesi(sahis(nebahat, arslan), “337 22 23”, d_gunu(kasim, 15, 1987)).

tel_listesi(sahis(leyla, aydin), “145 41 50”, d_gunu(aralik, 24, 1940)).

ay_donustur(ocak, 1).

ay_donustur(subat, 2).

ay_donustur(mart, 3).

ay_donustur(nisan, 4).

ay_donustur(mayis, 5).

ay_donustur(haziran, 6).

ay_donustur(temmuz, 7).

ay_donustur(agustos, 8).

ay_donustur(eylul, 9).

ay_donustur(ekim, 10).

ay_donustur(kasim, 11).

ay_donustur(aralik, 12).

GOAL d_gunu_ayini_bul.

Yukarıdaki program kodu incelendiğinde, bileşik nesnelerin neden faydalı olduğu açıkça görülür. Dogum_tarihi_ayi yüklemi, en yoğun kullanılan cümle durumdadır.

1.     Program ilk önce sonuçları bir pencerede görüntüler.

2.     Sonra sonuçların yorumlanacağı bir başlık kısmı görüntülenir.

3.     Daha sonra hazır fonksiyonlardan biri olan date kullanılarak bilgisayarın saatinden bugünkü tarih okunur ve ay belirlenir.

4.     Bundan sonra yapılması gereken tek şey, satırlar halinde sıralanan veritabanından isim, telefon no, doğum tarihi okutmaktır. Burada doğum tarihi sistemden okunan ay ile karşılaştırılıp aynı olanlar bulunur. adres_listesi(Sahis,_, Date) çağrısı adı ve soyadını Sahis değişkenine atar ve sahis operatörü Sahis’a atanmış olur. Date değişkeni de ilgili şahsın doğum tarihini alır. Buradaki adres_listesi bileşik bir değişken olup, bir kişi hakkındaki bütün bilgileri saklar.

5.     Daha sonra aranan kişinin doğum tarihini Date değişkenine atar. Bir sonraki alt hedefte tamsayıyla gösterilen bugünkü ay ve kişinin doğum tarihi dogum_gununu_kontrol_et yüklemine iletilir.

6.     dogum_gununu_kontrol_et yüklemi iki değişkenle birlikte çağrılır. İlk değişken bir tamsayıya, ikincisi ise dogum_tarihi’ne bağlanır. dogum_gununu_kontrol_et kuralını tanımlayan kuralın baş kısmındaki Bu_ay Mon değişkenine atanır. İkinci argüman olan Date ise dogum_tarihi(Ay, _,_) cümleciğine atanır. Sadece bugünkü tarihten ay ile ilgilendiğimiz için, gün ve yıl için anonim değişkenler kullanılmıştır.

7.     dogum_gununu_kontrol_et yüklemi ayın sembolik değerini tam sayıya dönüştürür ve bu değeri sistemden okunan ay değeri ile karşılaştırır. Karşılaştırmanın başarılı olması durumunda bir sonraki alt hedefe geçer. Karşılaştırma başarısız olursa geriye iz sürme işlemi başlar.

8.     İşlenmesi gereken bir sonraki alt hedef adini_yaz’dır. İstenilen bilgi, doğum tarihi bu ay olan kişinin ismi olduğu için, ekrana bu kişinin adı ve soyadı yazılır. Bir sonraki cümle ‘fail’ olduğu için otomatik olarak geriye iz sürme işlemi başlar.

9.     Geriye iz sürme daima en son kullanılan non-deterministic yükleme geri gider. Bizim programımızda zaten non-deterministic bir yüklem bulunduğu için işlem hemen adres_listesi’ne gider. Program burada işleme konmak üzere başka bir isim aramak için veritabanına gider. Eğer veritabanında işleme konacak başka biri kişi yoksa işlemdeki cümle başarısız olur. Prolog, veritabanındaki diğer satırları inceler ve dogum_gununu_kontrol_et kuralını tanımlayan başka bir cümle bulur.

5.6. Bileşik Nesnelerin Tiplerini Tanımlamak

Bu bölümde bileşik nesne tiplerinin nasıl tanımlanacağı üzerinde duralım.

sahiptir(ahmet, kitap(“Pascal 7”, “Ömer AKGÖBEK”))

sahiptir(ahmet, at(firtina)).

şeklinde tanımlanan ilişkiler

GOAL sahiptir(ahmet, Ne)

sorgusuyla irdelenirse Ne değişkeni iki ayrı argüman ile eşleşebilir. Bunlardani biri kitap, diğeri ise at’tır. Sahiptir yüklemi artık sahiptir(symbol, symbol) şeklinde tanımlanamaz. İkinci argüman symbol tipindeki nesnelere işaret etmez. Bunun yerine

sahiptir(isim, esyalar)

şeklinde bir yüklem tanımlamak mümkündür. Tipleri tanımlarken

Domains

esyalar= kitap(kitap_adi, yazar); at(atin_adi)

kitap_adi, yazar, atin_adi            = symbol

yazılabilir.

Yukarıdaki ‘;’ işareti ‘veya’ anlamına gelir. Bu durumda iki alternatiften bahsetmek mümkündür. Bir kitap, kitabın adı ve yazarının adıyla, bir ‘at’ ise sadece ismiyle tanımlanabilir. Kitap_adi, yazar, atin_adi değişkenlerinin tamamı symbol tipindedir.

Tip tanımlanmasına daha fazla alternatif rahatlıkla ilave edilebilir.

Örnek

DOMAINS

esyalar= kitap(kitap_ismi, yazar); at(atin_adi); araba; banka_hesabi(nakit)

kitap_ismi, yazar, atin_adi=symbol

nakit         = real

isim=symbol

PREDICATES

nondeterm sahiptir(isim, esyalar)

CLAUSES

sahiptir(ahmet, kitap(“Pascal 7.0”, “Ömer AKGÖBEK”)).

sahiptir(ahmet, at(firtina)).

sahiptir(ahmet, araba).

sahiptir(ahmet, banka_hesabi(1000)).

GOAL sahiptir(Kim, Sahip_oldugu_esyalar).

Programı derlenip çalıştırıldığında

Sahip_oldugu_esyalar=kitap(“Pascal 7.0”, “Ömer AKGÖBEK”)).

Sahip_oldugu_esyalar=at(firtina)).

Sahip_oldugu_esyalar=araba

Sahip_oldugu_esyalar= banka_hesabi(1000)).

4 Solutions

cevabı görüntülenir.

5.7. Tip Tanımlamaları Üzerine Kısa Bir Özet

Bileşik nesnelerin tip tanımları genel bir şekilde gösterilecek olursa:

Domain= alternatif1(Tip, Tip, ……); alternatif2(Tip, Tip, …..)

Burada alternatif1 ve alternatif2 farklı operatörlerdir. (Tip, Tip, …) gösterimi standart veya başka yerde ayrıca tanımlanan symbol, integer, real vs. gibi tip isimlerdir.

Not:

1.     Alternatifler birbirinden daima ‘;’ ile ayrılırlar.

2.     Her alternatif bir operatör ve bu argümana ait tip tanımlarını içerir.

3.     Eğer operatörde herhangi bir argüman kullanılmazsa, bunu alternatifN veya alternatifN( ) biçiminde yazılabilir.

5.8. Çoklu-Düzey Bileşik Nesneler

Prolog’da, birden fazla dereceden oluşan bileşik nesne kullanmak mümkündür. Örneğin

kitap(“Atatürk: Bir Milletin Yeniden Doğuşu”, “Kinross”)

olgusundaki ‘Kinross’ soyismi yerine, yazarın adını ve soyadını ayrıntılı olarak gösteren bir yapı kullanmak mümkündür.

kitap(“Atatürk: Bir Milletin Yeniden Doğuşu”, yazar(“Lord”, “Kinross”))

Daha önceden yapılan tip tanımında

kitap(kitap_adi, yazar)

yazılıyordu. İkinci argüman olan yazar, operatör durumundadır. Fakat yazar=symbol sadece bir isimi kapsadığından, yetersiz kalır. Bu durumda yazar değişkeninin de bileşik nesne olarak tanımlanması gerekir. Bunu da:

yazar=yazar(isim, soyisim)

şeklinde tanımlamak mümkündür. Şimdi tip tanımlarına geçelim.

Domains

esyalar=kitap(kitap_adi, yazar);              /*İlk derece*/

yazar=yazar(adi, soyadi)                         /*ikinci derece*/

kitap_adi, isim, soyisim=symbol             /*Üçüncü derece*/

Birden fazla dereceden oluşan bileşik nesneler kullanırken, ağaç biçiminde bir yapı kullanmak büyük kolaylık sağlar.

Kitap

Kitap_adi             yazar

                               İsim,       soyisim

Tip tanımı yapılırken bir anda ağaç yapısının sadece bir derecesi kullanılabilir. Örneğin

kitap=kitap(kitap_adi, yazar(adi, soyadi))

Şeklindeki tip tanımı yanlıştır.

5.9. Çoklu-Tipli Argümanlar

Bir yüklemin farklı tiplerde bilgi verebilmesi için bir operatör tanımının yapılması yapmamız gerekir. Aşağıdaki örnekte sizin_yasiniz cümleciği yas argümanını kabul edilmektedir. Yas argümanı ise string, real veya integer olabilir.

DomaIns

yas=i(integer); r(real); s(string)

Predicates

siniz_yasiniz(yas)

CLAUSES

sizin_yasiniz(i(Yas)):-write(Yas).

sizin_yasiniz(r(Yas)):-write(Yas).

sizin_yasiniz(s(Yas)):-write(Yas).

5.10. Listeler

Öğretim üyelerinin verdikleri dersleri liste halinde saklamak istediğimizi kabul edelim. Bunun için aşağıdaki kodun yazılması yeterlidir.

PREDICATES

profesor(symbol, symbol,symbol) /*Adı, soyadı ve verdiği ders*/

CLAUSES

profesor(asaf, varol, bilgisayar).

profesor(ali, erdogan, betonarme).

profesor(ahmet, aydogan, fizik).

Bu tür bir programda, bütün hocaların isimlerini ve verdikleri dersleri tek tek sıralamak mümkündür. Her hoca için ayrı bir olguyu veritabanına ilave etmek gerekir. Kolay görünen bu işin yüzlerce öğretim üyesi olan bir üniversite için yapıldığında ne kadar zor olduğunu açıktır. Prolog’daki liste bir veya daha fazla değer alabilir ve benzer işlerde büyük kolaylıklar sağlar. Bir listedeki değişkenlerin aldıkları değerleri ‘[]’ arasında yazmak gerekir.

DOMAINS

dersler=symbol*

PREDICATES

profesor(symbol, symbol, dersler)

CLAUSES

profesor(asaf, varol, [bilgisayar, termodinamik, iklimlendirme]).

profesor(ali, erdogan, [betonarme, statik, malzeme]).

profesor(ahmet, aydogan, (fizik, matematik, kimya]).

Şeklindeki satırlarda dersler liste tipinde bir değişken olarak tanımlanmıştır. Buradaki ‘*’ sembolü dersler değişkeninin liste tipinde olacağını gösterir. Aynı biçimde, listenin tamsayılardan oluştuğu bir değişken tipi

Domains

tamsayilar_listesi=integer*

şeklinde tanımlanabilir.

Örnek:

DOMAINS

notlar=integer*

PREDICATES

nondeterm sinav_sonuclari(symbol, symbol, notlar)

CLAUSES

sinav_sonuclari(orhan, aydin, [78, 98, 100]).

sinav_sonuclari(kasim, yenigun, [45, 54, 60]).

sinav_sonuclari(husamettin, bulut, [80, 90, 95]).

sinav_sonuclari(huseyin, karasu, []).

GOAL sinav_sonuclari(orhan,_,Aldigi_Notlar).

Programı çalıştırıldığında Orhan’ın aldığı notlar görüntülenir.


6. TEKRARLAMA VE REKÜRSİYON

Prosedür ve veri yapılarında tekrarlama işlemleri Visual Prolog’da kolay bir şekilde yapılır. Bu bölümde önce tekrarlı işlemler (döngüler ve rekursif prosedürler), daha sonra ise rekursiv veri yapıları incelenecektir.

6.1. Tekrarlı İşlemler

Pascal, BASIC veya C gibi konvansiyonel programlama dilleriyle çalışanlar, Prologla çalışmaya başladıklarında FOR, WHILE, REPEAT gibi ifadeleri göremeyince şaşırabilirler. Çünkü Prologda iterasyonu anlatan direkt bir yol yoktur. Prolog sadece iki türlü tekrarlama-geriye dönüş imkanı tanır. Bu işlemlerde bir sorguya birden fazla çözüm bulmak ve bir prosedürün kendisini çağırdığı rekürsiyon işlemine imkan tanır.

6.2. Geriye İz Sürme

Bir prosedür, istenilen bir hedef için uygun bir çözüm yerine alternatif başka çözümler aramak için geriye döner. Bunun için geriye henüz denenmemiş bir alternatifi kalan en son alt hedefe gidileceğini, bu noktadan tekrar aşağıya doğru inileceği bilinmektedir. Geriye dönüşü iptal edip tekrarlı işlemler yaptırmak mümkündür.

Örnek:

PREDICATES

nondeterm ulke_adi(symbol)

ulke_adlarini_yaz

CLAUSES

ulke_adi(“Türkiye”).

ulke_adi(“Kazakistan”).

ulke_adi(“Azerbaycan”).

ulke_adi(“Amerika”).

ulke_adlarini_yaz:-

ulke_adi(Ulke), write(Ulke), nl, fail.

ulke_adlarini_yaz.

GOAL ulke_adi(Ulke).

Yukarıdaki ulke_adi yüklemi sadece ülke isimlerini sıralar. Dolayısıyla GOAL ulke_adi(Ulke) şeklindeki bir hedefin birden fazla sonucu vardır ve ulke_adlarini_yaz yuklemi bunların hepsini görüntüler.

ulke_adlarini_yaz :- ulke_adi(Ulke), write(Ulke), nl, fail.

satırıyla söylenmek istenen şey şudur: “Bütün ülke isimlerini yazmak için, önce ulke-adi(Ulke) cümlesine cevap bul, bunu yaz, yeni bir satıra geç ve işlemi yeniden başlat.”

‘fail’ komutunun programa yüklediği görev şöyle özetlenebilir: “GOAL cümlesine uygun bir çözüm bulunduğunda, geriye dönüş yap ve başka alternatiflere bak”.

‘fail’ yerine, sonucu daima yanlış olan ve bu yüzden geriye dönüşü zorlayan başka bir alt hedef kullanmak mümkündür. Örneğin, 10=5+6 satırı her zaman yanlış olacağı için, Prolog başka alternatifler bulmak için daima geriye dönüş yapar.

Örneğimizde ilk önce Ulke=Türkiye olur ve sonuç ekrana yazılır. ‘fail’ komutuna sıra geldiğinde program, bir alt hedefe geri döner. Fakat nl veya write(Ulke) satırları için kullanılabilecek herhangi bir veri olmadığı için, bilgisayar ulke_adi(Ulke) ilişkisi için başka çözümler arar.

Ulke_adi(Ulke) ilişkisi çalıştırıldığında, önceden boş değişken olan Ulke değişkeni ‘Türkiye’ değerini almıştı. Bu yüzden bu ilişkiyi yeniden kullanmadan önce Ulke değişkeni yeniden serbest hale getirilir. Daha sonra Ulke değişkeninin alabileceği başka bir olgu aranır. İkinci oluguda bu sağlanır ve ulke_adi yüklemindeki Ulke değişkeni ‘Kazakistan’ değerini alır. Bu işlem böylece devam eder ve sonuçta şu satırlar görüntülenir.

Türkiye

Kazakistan

Azerbaycan

Amerika

4 Solutions

Eğer ulke_adlarini_yaz yüklemi ‘fail’ komutundan sonra yazılmamış olsaydı, cevap yine aynı olurdu fakat ‘yes’ yerine ‘no’ satırı görüntülenirdi.

6.3. Önceki ve Sonraki Eylemler

Bir hedef için gerekli olan bütün çözümleri sağlayan bir program, çözüm yapmadan ve yaptıktan sonra başka şeyler de yapabilir. Örneğin

1.     Yaşanacak güzel yerler

2.     Ulke_adi(Ulke) yükleminin bütün sonuçlarını yaz.

3.     Başka yerler de olabilir…

Şeklinde bir mesaj yazarak bitirebilir.

Ulke_adlarini_yaz cümlesin ulke_adi(Ulke) yükleminin bütün sonuçlarını içerir ve sonunda bir bitiş mesajı yazar.

Örnekte geçen ilk ulke_adlarini_yaz cümlesi yukarıdaki adımlardan ikincisi içindir ve bütün çözümleri yazar. İkinci cümlesi ise üçüncü adıma tekabül eder ve sadece hedef cümlesini başarılı bir şekilde bitirmek içindir. Çünkü ilk cümle daima yanlıştır.

Programı başka şekilde yazmak gerekirse:

PREDICATES

nondeterm ulke_adi(symbol)

ulke_adlarini_yaz

CLAUSES

ulke_adi(“Türkiye”).

ulke_adi(“Kazakistan”).

ulke_adi(“Azerbaycan”).

ulke_adi(“Amerika”).

ulke_adlarini_yaz:-

write(“Yaşanacak bazı yerlerin listesi..”), nl, fail.

ulke_adlarini_yaz :-

ulke_adi(Ulke), write(Ulke), nl, fail.

ulke_adlarini_yaz:-

write(“Başka güzel yerler de vardır…”), nl.

GOAL ulke_adlarini_yaz.

İlk cümledeki ‘fail’ komutu çok önemlidir. Çünkü bu komut ilk cümle çalıştırıldıktan sonra programın ikinci cümleye geçişini sağlar. Buradaki write ve nl komutlarının başka bir iş yapmaması çok önemlidir. Son ‘fail’ komutundan sonra programın ikinci cümleciğe geçişi sağlanmalıdır.

6.4. Döngülü Geriye Dönüşün Uygulanması

Geriye dönüş işlemi bir hedefin bütün çözümlerinin bulunması açısından son derece önemlidir. Birden fazla çözüm sunamayan hedefler için yine de geriye dönüş işlemi yapılabilir. Bu da tekrarlama işlemini yapar. Örneğin:

tekrar.

tekrar:-tekrar.

gibi iki cümlecik sonsuz sayıda çözüm olduğunu göstermektedir.

Örnek:

PREDICATES

nondeterm tekrar

nondeterm karakteri_ekrana_yaz

CLAUSES

tekrar.

tekrar:-tekrar.

karakteri_ekrana_yaz:-

tekrar, readchar(Harf), /*Klavyeden girilen harfi oku ve C’ye ata*/

write(Harf),

Harf=’\r’, !. /* Satır sonu tuşuna (Enter/Return) basılmadıysa devam et*/

GOAL karakteri_ekrana_yaz, nl.Yukarıdaki örnekte tekrar işleminin nasıl yapılacağını görülebilir. Karakteri_ekrana_yaz:-… kuralı, ‘Enter/Return’ basılmadığı müddetçe, klavyeden girilen kararterleri kabul edip ekranda gösteren bir prosedür tanımlamaktadır.

Karakteri_ekrana_yaz kuralının çalışma mekanizması şöyle sıralanabilir:

1.     tekrar’ı çalıştır. (Hiçbir şey yapmaz)

2.     bir karakter oku (Harf)

3.     Harf karakterini yaz

4.     Harf’in satır sonu karakteri olup olmadığını kontrol et.

5.     Eğer satır sonu elemanı ise, işlemi bitir, değilse, geriye iz sürme işlemini yap ve alternatif ara. Buradaki write ve readchar kurallarının hiçbiri alternatif sağlayamaz. Dolayısıyla geriye dönüş hemen tekrar kuralına gider, bunun ise alternatif sunması tabiidir.

6.     İşlem devam eder. Bir karakter oku, onu ekrana yaz, satır sonu elemanı olup olmadığını kontrol et.

Harf’e değer atayan readchar(Harf) yükleminin öncesine geriye dönüş yapıldığı anda, Harf değişkeni serbest hale gelir. Değişken değerinin kaybolması geriye dönüş işlemi sayesinde alternatif çözümler elde etmek için çok önemlidir. Fakat geriye dönüş işlemi başka bir iş için kullanılamaz. Çünkü geriye dönüş işlemi alternatif ararken, işlemleri birçok kez tekrar edebilir. Fakat bu tekrarlar sırasında bir tekrardan diğerine geçişte hiçbir şey hatırlayamaz. Daha önce de söylediğimiz gibi, işlemlerden sonra değer ataması yapılan değişkenlerin tamamı, geriye dönüş işlemi sırasında bütün bu değerleri kaybederler. Böyle bir döngüde sayaç gibi bir şey kullanıp toplam, kayıt sayısı vs. gibi bir değeri tutmanın kolay bir yolu yoktur.

6.5. Rekursif Prosedürler

Tekrarlama işlemin yapmanın diğer bir yolu da rekursiyondur. Kendisini çağırabilen prosedüre rekursiv prosedür diyoruz. Rekursiv prosedürler çalışırken yaptıkları işlerin sayısını, toplamını veya işlemlerin ara sonuçlarını saklayabilir ve bunları bir döngüden diğerine rahatlıkla aktarabilirler.

Örnek:

N sayısının faktoriyelini hesaplamak için

1. Eğer N=1 ise, faktoriyel=1

2. Diğer durumlarda N-1’in faktoriyelini bul ve bunu N ile çarp

şeklindeki emirleri anlayıp uygulayan bir program yazalım. Örneğin 3 sayısının faktöriyelini bulmak için 2’nin faktöriyelini, 2’nin faktöriyelini bulmak için de 1’in faktöriyelini bulmamız gerekir. 1’in faktöryeli zaten bilindiğinden yapılması gereken tek şey 2 ve 1’in faktöriyellerini N sayısı olan 3 ile çarpmaktır. Görüldüğü gibi işlemler burada sonsuza kadar gitmemektedir. Şimdi bunları Prolog ile ifade etmeye çalışalım:

PREDICATES

faktoriyel(unsigned, real)

CLAUSES

faktoriyel (1, 1):-!.

faktoriyel (X, Faktoriyel_X):-

Y=X-1,

faktoriyel(Y, Faktoriyal_Y),

Faktoriyel_X=X*Faktoriyal_Y.

GOAL X=6, faktoriyel(X, Faktoriyel).

Programı 6 sayısının faktöriyelini bulur.

Burada ilginç bir durum vardır. Bilgisayar faktöriyel işleminin yarısında iken nasıl olur da faktöriyeli hesaplar? Faktöriyel kuralını X=6 olacak şekilde çağırılırsa, faktöriyel kendini X=5 için çağırılacaktır. Bu durumda X değeri 6 mı olacak 5 mi?

Cevap şudur: Bilgisayar faktöriyel prosedürünün bir kopyasını oluşturur ve bu kopyayı çağır. Kopyanın kendini faktoriyel prosedürünün aynısıymış gibi çalışır. Sadece argümanların ve değişkenlerin kopyalarına ihtiyaç duyulur.

Bu bilgi yığın olarak hafızada saklanır ve bir kural çağrıldığında her seferinde yeniden oluşturulur. Kural non-deterministic değil ise sona erdiği zaman bellek yığını sıfırlanır.

6.5.1. Rekursiyonun Avantajları

·       Başka türlü güvenli bir şekilde ifade edilemeyen algoritmaları daha açık bir şekilde ifade edebilir.

·       Mantıksal olarak iterasyondan çok daha basittir.

·       Listeleri işlemede çok yaygın olarak kullanılır.

Rekursiyon işlemi özellikle problem içerisinde dallanmaların mevcut olduğu, yani bir problemin çözümünün bir alt probleme bağlı olduğu durumlarda çok faydalıdır.

6.5.2. Sondan Rekursiyon Optimizasyonu

Rekursiyon işleminin en önemli dezavantajı, belleği fazlaca kullanmasıdır. Bir prosedür başka bir alt prosedürü çağırdığında, çağrıyı yapan prosedürün çağrıyı yaptığı anki çalışma durumu mutlaka kaydedilmelidir. Böylece çağrılan prosedürün yapması gereken işlem bittiği zaman, çağrıyı yapan prosedür kaldığı yerden işleme devam edebilir. Bunun dezavantajı şudur: Örneğin bir prosedür kendisini 100 defa çağırırsa, her seferki durum kaydedileceği için tam olarak 100 değişik durum hafızaya alınmış olur. Hafızaya alınan her duruma stack frame (yığın alanı) denir. 16 bitlik PC DOS sisteminde bu alan 64K ile sınırlı olup, ancak 3000-4000 yığın alacak kapasitedir. 32 Bit’lik sistemlerde teorik olarak bu alan GB düzeyine kadar çıkabilir, fakat bu kez de başka engeller ortaya çıkar. Yığın alanın azaltmak için ne yapılabilir?

Bir prosedürün, başka bir prosedürü kendisinin en son adımı olarak çağırdığını düşünelim. Çağrılan prosedür görevini yaptıktan sonra, çağrıyı yapan prosedürün yapması gereken başka şey kalmaz. Çağrıyı yapan prosedürün kendisin çalışma anını kaydetmesi gerekmez, çünkü o andaki bilgi artık gereksizdir. Çağrılan prosedür biter bitmez, program akışı normal biçimde devam eder.

Bu durum daha açık olarak aşağıdaki şekilde ifade edilebilir. A prosedürünün B prosedürünü, B prosedürünün ise C prosedürünü son adım olarak çağırdığını düşünelim. B prosedürü C’yi çağırdığında, B’nin başka bir şey yapması gerekmez. Yani C’nin o anki çalışma durumunu B olarak kaydetmek yerine, B’nin kaydedilen eski durumun C’ya aktarmak, depolanan bilgi içinde uygun değişiklik yapmak mümkündür. C bittiği zaman, doğrudan A prosedürü tarafından çağrılmış gibi olacaktır.

B prosedürünün C’yi çağırmak yerine, kendisini işlemin en son adımı olarak çağırdığını düşünelim. B prosedürü yine B’yi çağırdığı zaman, çağrıyı yapan B’nin yığın bilgisi, çağrılan B’nin yığın bilgisi ile yer değiştirilmelidir. Bu ise çok basit bir işlemden yani argümanların yeni değerleri almasından ibarettir. Daha sonra işlem, prosedürün baş kısmına gider. Prosedürel olarak bu olay bir döngüdeki kontrol değerlerinin yenilenmesine benzer.

Bu işlemlere sondan rekursiyon optimizasyonu veya son-çağrı optimizasyonu adı verilmektedir.

6.5.3. Sondan Rekursiyonun Kullanımı

Prologda bir prosedürün başka bir prosedürü ‘kendisinin en son adımı olarak çağırmasının’ ne anlama geldi konusu incelenecektir.

1.     Çağrı, cümlenin en son alt hedefidir.

2.     Bu cümlenin ilk kısımlarında geriye dönüş noktaları yoktur.

Aşağıdaki örnek bu iki şartı sağlamaktadır:

sayac(Sayi):-

write(Sayi), nl,

yeni_sayi=Sayi+1,

sayac(Yeni_sayi).

İşte bu prosedür sondan rekursif bir prosedürdür ve hafızada yeni bir yığına neden olmaksızın kendisini çağırır. Dolayısıyla hafızayı tüketmez. Bu programa GOAL sayac(0) değeri verilse, 0 ile başlayan tam sayılar yazılmaya başlanır ve işlem bitmez.

Örnek:

PREDICATES

sayac(ulong)

CLAUSES

sayac(Sayi):-

write(‘\r’,Sayi),

Yeni_sayi=Sayi+1,

sayac(Yeni_sayi).

GOAL nl, sayac(0).

Bu programa GOAL sayac(0) ile çalıştırılırsa, 0’dan başlamak üzere tam sayılar yazılmaya başlanır ve işlem bitmez.

6.5.3. Sondan Rekursiyonu Engelleme

1.     Eğer rekursiv çağrı en son adım değilse, prosedür sondan rekursiv değildir. Örneğin;

PREDICATES

rakam_yaz(ulong)

CLAUSES

rakam_yaz(Sayi):-

write(‘\r’, Sayi),

Yeni_sayi=Sayi+1,

rakam_yaz(Yeni_sayi), nl.

Goal nl, rakam_yaz(0).

Rakam_say prosedürü kendisini çağırdında, kontrolün yeniden rakam_say(Sayi) dönmesi için hafızada bir yığın kaydedilir. Çünkü son alt hedef ‘nl’dir ve bunun işleme girmesi gerekir. Dolayısıyla döngü bir süre sonra hata mesajı vererek durur.

2. Sondan rekursiyonu engellemenin bir diğer yolu da rekursiyonun yapıldığı anda, geriye henüz denenmemiş bir alternatifin kalmasıdır. Bu durumda prosedürün son durumunun kaydedilmesi gerekir. Çünkü rekürsiv çağrının başarısız olması durumunda çağrıyı yapan prosedürün geriye gidip denenmemiş bir alternatifi deneyebilmesi gerekir.

Örnek:

Clauses

rakam_yaz(Sayi):-

write(‘\r’, Sayi),

Yeni_sayi=Sayi+1,

rakam_yaz(Yeni_sayi).

rakam_yaz(Sayi):-

Sayi<0, write(“Sayi sıfırdan küçüktür.”).

GOAL rakam_yaz(0).

Burada rakam_yaz cümlesi, ikinci cümle denenmeden önce kendisini çağırır. Program yine bir süre sonra hafıza tükenmesinden dolayı durur.

1.     Denenmemiş alternatifin rekursiv prosedürün kendisi için ayrı bir cümle olması gerekmez. Rekürsiv prosedürün çağırdığı başka bir cümlede bir alternatif de olabilir. Örnek:

rakam_yaz(Sayi):-

write(‘\r’, Sayi),

Yeni_sayi=Sayi+1,

Kontrol_et(Yeni_sayi).

rakam_yaz(Yeni_sayi).

Kontrol_et (Z):-Z>=0.

Kontrol_et (Z):- Z<0.

Sayi değişkeninin değeri normalde pozitiftir. Bu durumda rakam_yaz her ne zaman kendisini çağırsa, kontrol_et yükleminin ilki doğrulanır, fakat ikinci kontrol_et yüklemin henüz doğrulanmamış durumdadır. Bu yüzden rakam_yaz yüklemi, geriye dönüş işlemi sırasında kontrol etmek üzere yığın bölgesine bir kopya almak zorundadır.

PREDICATES

yanlis_sayac1(long)

yanlis_sayac2(long)

yanlis_sayac3(long)

kontrol_et(long)

CLAUSES

/* Rakam_yaz: Rekursiv çağrı son adım değildir.*/

yanlis_sayac1(Sayi):-

write (‘\r’, Sayi),

Yeni_sayi=Sayi+1,

yanlis_sayac1(Yeni_sayi), nl.

/* Rakam_yaz2: Rekursiv çağrı yapıldığı anda henüz denenmemiş bir clause var.*/

yanlis_sayac2(Sayi):-

write (‘\r’, Sayi),

Yeni_sayi=Sayi+1,

yanlis_sayac2(Yeni_sayi).

yanlis_sayac2(Sayi):-

Sayi<0,

write (“Sayı negatiftir.”).

/* Rakam_yaz3: Rekursiv çağrıdan önce çağrılan yüklemde denenmemiş bir alternatif var.*/

yanlis_sayac3(Sayi):-

write (‘\r’, Sayi),

Yeni_sayi=Sayi+1,

kontrol_et(Yeni_sayi),

yanlis_sayac3(Yeni_sayi).

kontrol_et(Z):-

Z>=0.

kontrol_et(Z):-

Z<0.

GOAL yanlis_sayac1(1458).

6.6. Rekursiyonda Cut Kullanımı

Bir prosedürün sondan rekürsiyonlu olup olmadığından kesin olarak emin olunamayacağı düşünülebilir. Rekursiv olan çağrıyı, son cümleciğin en son alt hedefi yaparak, bu problemi çözmek mümkündür. Fakat yine de hedef cümlesinin çağıracağı diğer prosedürler arasında denenmemiş başka bir alternatif olmadığını nasıl garantiye alabiliriz?

Bunu garantiye almak gerekmez, çünkü ‘!’ yani Cut komutunu kullanarak bulunabilecek bütün alternatiflerin önünü kesmek mümkündür. Cut komutunun anlamı şöyleydi. Goal cümleciği ile belirlenen yükleme uygun çözüm ararken, gelinen nokta bizim aradığımız noktadır. Artık öteye gitmeye gerek bulunmamaktadır. Alternatifler de ortadan kalktığı için, artık hafızada yığın oluşturmaya gerek kalmaz.

Yukarıdaki örnekte görülen rakam_say cümlesini, şöyle düzeltmek mümkündür (İşlemdeki ismini değiştirelim):

Cut_sayaci3(Sayi):-

Write (‘\r’, Sayi),

Yeni_sayi=sayi+1,

Kontrol_et(Yeni_sayi), !, cut_sayaci3(Yeni_sayi).

Cut komutu yanlis_sayac2 cümleciğinde aynı şekilde etkili olur. Çünkü testi negatife düşürüp ikinci cümlecikten birinciye taşır.

Cut_sayaci2(Sayi):-

Sayi>=0, !,

Write (‘\r’, Sayi),

Yeni_sayi=Sayi+1,

cut_sayaci2(Yeni_sayi).

Cut_sayaci2(Sayi):- write (“Sayi negatiftir.”).

Cut komutunu non-deterministic olan, yani birden fazla çözüm sağlayan yüklemlerle çalışırken, alınan bilginin yeterli olduğuna inanıldığı anda rahatlıkla kullanılabilir.

Aynı şey yanlis_sayac3 için de geçerlidir. Kontrol_et yüklemi işaretine bağlı olarak Sayi üzerinde biraz daha işlem yapılmasını gerektiren bir durumu göstermektedir. Fakat kontrol_et kodu non-deterministic olduğu için Cut komutu iyi bir çözümdür. Kontrol_et yüklemi şöyle yazılabilir:

Kontrol_et(Z):- Z>=0, !, /* Z’yi kullanarak işlem yapmak*/

Kontrol_et(Z):-……

Cut komutu kullanıldığı zaman bilgisayar denenmemiş bir alternatifin kalmadığına karar verir ve bu yüzden de yığın oluşturma yoluna gitmez. Aşağıdaki programda yanlis_sayac2 ve yanlis_sayac3’ün düzeltilmiş hali vardır.

PREDICATES

cut_sayaci2(long)

cut_sayaci3(long)

nondeterm kontrol_et(long)

CLAUSES

/* Rekursiv çağrı yapıldığı anda henüz denenmemiş bir seçenek var*/

cut_sayaci2(Sayi):-

Sayi>=0, !,

write(‘\r’, Sayi),

Yeni_sayi=Sayi+1,

cut_sayaci2(Yeni_sayi).

cut_sayaci2(_):-

write(“Sayi negatiftir.”).

/* Rekursiv çağrıdan önceki cümlecikte henüz denenmemiş bir seçenek var*/

cut_sayaci3(Sayi):- write(‘\r’, Sayi),

Yeni_sayi=Sayi+1,

kontrol_et(Yeni_sayi), !, cut_sayaci3(Yeni_sayi).

kontrol_et(Z):-Z>=0.

kontrol_et(Z):-Z<0.

GOAL cut_sayaci3(214).

6.7. Argümanların Döngü Değişkeni Olarak Kullanımı

Rukursiyon bölümünde verilen bir sayının faktöriyelini hesaplayan bir program geliştirilmişti. Bu durum Pascal’da şöyle ifade edilebilir:

P:=1;

For I:=1 to N do P:= P*I;

FactN:=P;

N, faktöriyeli hesaplancak olan sayı, FactN, N sayısının faktöriyeli, I değeri 1’den N’e kadar değişen döngü değişkeni ve P ise ara sayıların değerlerinin toplandığı değişkendir.

Bu programı Prolog’a aktarırken yapılması gereken ilk şey, for komutu için daha basit bir döngü kurmak ve her adımda I değişkenine ne olduğunu daha açık şekilde göstermektir. Program while ile, aşağıdaki biçimde yazılır.

P:=1;                    /* P ve I değişkenlerine ilk değeri ata.*/

I:=1;

While I<= N do               /* Döngü kontrolü*/

Begin

P:=P*I;                 /*P ve I değişkenlerine yeni değerleri ata*/

I:=I+1;

End;

FactN:=P;            /* Sayının Faktöriyelini Yaz..*/

Aynı program Prolog ile aşağıdaki gibi yazılır.

PREDICATES

faktoriyel(unsigned, real)

carpanlarin_faktoriyeli(unsigned, long, unsigned, long)

CLAUSES

faktoriyel(Sayi, Sayinin_Faktoriyeli):-

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, 1, 1).

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I,P):-

I<=Sayi, !,

Yeni_P=P*I,

Yeni_I=I+1,

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, Yeni_I, Yeni_P).

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I, P):-

I>Sayi,

Sayinin_faktoriyeli=P.

GOAL faktoriyel(5, Sayinin_Faktoriyeli).

Programın ayrıntıları aşağıda verilmiştir.

Faktoriyel cümleciğinin Sayi ve Sayinin_Faktoriyeli olmak üzere iki değişkeni vardır. Bunlardan sayı, faktöriyeli bulunacak sayı, diğeri ise bu sayının faktöriyelidir. Rekursiyon işlemi aslında carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I, P) cümlesinden meydana gelir. Bu cümledeki 4 değişkenin bir adımdan diğerine aktarılması zorunludur. Bu yüzden faktoriyel sadece carpanlarin_faktoriyeli yüklemini harekete geçirir ve sayı, sayının faktöriyeli, I ve P’nin ilk değerlerini buraya aktarır. Böylece

faktoriyel(Sayi, Sayinin_Faktoriyeli):-

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, 1, 1).

sayesinde I ve P değişkenleri ilk değerlerini almış olurlar. Burada dikkat çeken şey, faktoriyel yükleminin hiçbir değeri olmayan Sayinin_faktoriyeli değerini carpanlarin_faktoriyeli yüklemindeki sayinin_faktoriyeli değişkenine aktarmasıdır. Prologun yaptığı tek şey, iki cümlede bulunan Sayinin_faktoriyeli değişkenlerini eşleştirmektir. Aynı şey carpanlarin_faktoriyel’i yüklemindeki sayinin_faktoriyeli değişkeninin rekursiv çağrı esnasında kendisine atanmasında da olur. Son aşamada ise Sayinin_faktoriyeli bir değer alacaktır. Bu değeri aldığı zaman daha önceki bütün sayinin_faktoriyeli değişkeni aynı değeri alır. Gerçekte ise sayinin_faktoriyeli değişkeninin bir değeri vardır. Çünkü Sayinin_faktoriyeli değişkeni, ikinci cümledeki carpanlarin_faktoriyeli cümlesinden önce hiçbir zaman gerçek anlamda kullanılmaz.

Şimdi carpanlarin_faktoriyeli yüklemine gelelim. Bu yüklem, döngünün devam şartı olan I sayısının Sayi’dan az veya eşit olup olmadığını kontrol eder. Daha sonra Yeni_I ve Yeni_P değerleriyle kendisini rekursiv olarak çağırır. Burada Prolog’un başka bir özelliği ortaya çıkmaktadır. Diğer dillerin çoğunda mevcut olan

P=P+1

şeklindeki bir ifade Prolog’da yanlıştır. Bu yüzden Prolog’da bir değişkenin değerini değiştirmek mümkün değildir. Bunun yerine

Yeni_P=P+1

şeklinde bir ifade kullanmak gerekir. Bu durumda ilk cümlecik

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, I,P):-

I<=Sayi, !,

Yeni_P=P*I,

Yeni_I=I+1,

carpanlarin_faktoriyeli(Sayi, Sayinin_Faktoriyeli, Yeni_I, Yeni_P).

şeklinde yazılabilir. Buradaki Cut komutu, cümlecik yüklemde en sonda olmasa da, son çağrı optimizasyonuna imkan tanır. Zamanla I değişkeninin değeri Sayi değişkeninin değerine geçer. Bu durumda işlem P’nin o anki değerini sayinin_faktoriyeli ile eşleştirir ve rekursiyonu bitirir. Bu nokta ikinci cümlede, yani birinci cümledeki I<=Sayi testinin yanlış çıktığı zaman meydana gelecektir.

carpanlarin_faktoriyeli(Sayi, Sayinin_faktoriyeli, I, P):- I>Sayi, sayinin_faktoriyeli=P.

haline dönüşür. Sayinin_faktoriyeli=P ifadesinin ayrı bir satırda olması gerekmez. Çünkü sayinin_faktoriyeli değişkeninin yerine P değişkenini yazarak değer ataması yapılabilir. Ayrıca I>Sayi testi de gereksizdir, çünkü bunun tersi zaten birinci cümlede denenmiş olmaktadır. Bunun son hali:

carpanlarin_faktoriyeli(_, Sayinin_faktoriyeli,_, Sayinin_Faktoriyeli) olur.

PREDICATES

faktoriyel(unsigned,real)

faktoriyel(unsigned,real,unsigned,real)

CLAUSES

faktoriyel(Sayi, Sayinin_faktoriyeli):-

faktoriyel(Sayi, Sayinin_faktoriyeli,1,1).

faktoriyel(Sayi, Sayinin_faktoriyeli, Sayi, Sayinin_faktoriyeli):-!.

faktoriyel(Sayi, Sayinin_faktoriyeli,I,P):-

Yeni_I = I+1,

Yeni_P = P*Yeni_I,

faktoriyel(Sayi, Sayinin_faktoriyeli, Yeni_I, Yeni_P).

GOAL faktoriyel(12, Sayinin_Faktoriyeli).

6.8. Rekursiv Veri Yapıları

Sadece kurallar değil, aynı zamanda veri yapıları da rekursiv olabilir. Prolog bu tür yapıların kullanılmasına imkan tanıyan yaygın kullanılan tek programlama dilidir. Bir veri türü, kendisi gibi yapıları içeren başka yapıların kullanımına izin veriyorsa, bu tür veri tiplerine rekursiv denir. En temel rekursiv veri türü listelerdir. Fakat ilk bakışta rekursiv yapıda oldukları belli olmaz.

Şimdi rekursiv olan bir veri türü tanımlayıp, bunu oldukça hızlı bir sıralama programında kullanılması gösterilecektir. Bu veri türünün yapısı aşağıda ağaç yapısında verilmiştir. Görüldüğü gibi Ali ve Ayşe ile gösterilen her bir dal kendi içinde ayrıca alt dallara ayrılmıştır. Bundan dolayı da bu tür bir yapı rekursiv olarak adlandırılır.

Şekil 6.1. Aile Fertlerinin Şecere Olarak Gösterilmesi

6.9. Ağaç Biçimindeki Veri Türleri

Rekursiv veri türleri, ALGOL60 dilinden Pascal dilini çıkaran Niklaus Wirth tarafından popüler hale getirilmiştir. Bu veri tiplerini Pascal’da kullanmamış, fakat faydalarına değinmiştir.

Visual Prolog, otomatik olarak oluşturulup, pointerlar içereren gerçek rekursiv tip tanımlara imkan tanır. Örneğin aşağıdaki biçimde bir ağaç yapısı tanımlamak mümkündür.

Domains

Agac_yapisi= agac(string, agac_yapisi, agac_yapisi)

Bu ifade agac isimli bir operatör tanımlandığını, bunun da biri string, ikisi ayrıca ağac yapısında, toplam üç değişkeninin olduğunu gösterir.

Ağaç yapısındaki hiçbir veri türü sonsuza kadar gidemeyeceği, rekursiyonu da bitirmek mümkün olmadığı için bu ifade tam olarak doğru değildir. Örneğin bazı hücrelerin diğer hücrelerle bağlantıları yoktur. Prolog’da ağaç yapısındaki bir veri yapısında iki tip operatör tanımlanır. Bunlar üç ayrı argümanı olan agac veya hiçbir argümanı olmayan bos operatörleridir.

Domains

Agac_yapisi= agac(string, agac_yapisi, agac_yapisi); bos

Yukarıdaki agac ve bos adındaki yüklemlerin Prolog’da önceden tanımlı bir anlamları yoktur ve programcı bunların yerine istediği başka isimleri kullanabilir. Şimdi Şekil 6.1’de gösterilen tablonun Prolog’da nasıl ifade edilebileceği incelenecektir.

agac(“Emine”, agac(“Ali”, agac(“Hasan”, bos, bos) agac(“Fatma”, bos, bos))

agac(“Ayşe”, agac(“Fuat”, bos, bos) agac(“Leyla”, bos, bos)))

6.9.1. Bir Ağaç Yapısında Tarama Yapma

Ağaç şeklindeki yapılarda yoğun olarak yapılan işlem, ya bütün hücreleri incelemek ve hücreleri bir şekilde işlemek veya belirli bir değeri aramak ve bütün değerleri toplamaktır. Buna bir ağacı taramak adı verilmektedir.

Bunun en temel algoritmalarından biri şudur:

2.     Eğer ağaç boş ise hiçbir şey yapma

3.     Eğer dolu ise, o anki noktayı incele, buradan soldaki alt dala geç ve daha sonra sağdaki alt dalı incele.

Algoritma da tıpkı ağaç yapısı gibi rekursivdir. Soldaki ve sağdaki ağaç yapılarını orijinal ağaç gibi inceler. Prolog bunu iki cümlecik ile ifade eder, biri boş diğeri de dolu ağaç içindir.

incele(bos)

incele(agac(A, B, C)):-

incele(A), incele(B), incele(C).

Aşağıdaki ağaç tarama algoritması aşağıya-doğru-arama olarak bilinir. Çünkü Prolog her dalda mümkün olduğu kadar derinlemesine gider, bu dalın sonuna ulaştığı anda geriye döner ve başka bir dalı incelemeye başlar. (Şekil 6.2).

Şekil 6.2. Şekil 6.1’deki ağaç yapısında Aşağıya-Doğru-Arama metodunun uygulanması.

Prologun yukarıdaki ağacı nasıl tarayacağı yukarıda belirtilmiştir. Aşağıdaki program, ağaç yapısını tarayarak ağacın her elemanını ekranda görüntülenir.

DOMAINS

agac_yapisi=agac(string, agac_yapisi, agac_yapisi); bos_dal

PREDICATES

agaci_tara(agac_yapisi)

CLAUSES

agaci_tara(bos_dal).

agaci_tara(agac(Isim, Sol, Sag)):-

write(Isim, ‘\n’),

agaci_tara(Sol), agaci_tara(Sag).

GOAL

agaci_tara(agac(“Emine”, agac(“Ali”, agac(“Hasan”, bos_dal, bos_dal),

agac(“Fatma”, bos_dal, bos_dal)), agac(“Ayşe”, agac(“Fuat”, bos_dal, bos_dal), agac(“Leyla”, bos_dal, bos_dal)))).

Programı yazıp çalıştırılırsa ekranda şunlar görülür.

Emine

Ali

Hasan

Fatma

Ayşe

Fuat

Leyla

yes

aşağıya-doğru-arama Prolog’un bir veri tabanını tararken kullandığı yönteme çok benzer. Bu tarama esnasında cümlecikler ağaç şeklinde düzenlenir ve her bir dal ayrı ayrı incelenerek sorgu başarısız oluncaya kadar işleme devam edilir.

6.10. Bir Ağaç Oluşturmak

Ağaç biçiminde bir yapı oluşturmanın bir yolu operatörlerden ve argümanlardan oluşan iç içe geçmeli bir yapı yazmaktır. Prolog, hesaplama yaparak elde ettiği değerlerden bir ağaç oluşturabilir. Her bir adımda, argümanların eşleştirilmesiyle boş alt dalın içine boş olmayan bir dal yerleştirilir. Basit verileri kullanarak bir hücreli bir ağaç oluşturmak çok basittir.

agac_olustur(Sayi, agac(Sayi, bos_dal, bos_dal)).

Yukarıdaki satır Prolog için “Eğer Sayi bir sayı ise, agac(Sayi, bos_dal, bos_dal) tek hücreli bir ağaç olup veri olarak bu sayıyı içerir” anlamına gelir. Ağaç yapısı oluşturmak da en az bu kadar basittir. Örneğin

sola_yerlestir(Sayi, agac(A, _, B), agac(A, Sayi, B)).

Prosedürü üç argümandan oluşmuştur. İlk ağacı, ikinci ağacın alt dalı olarak alır ve üçüncü ağacı da sonuç olarak verir. Yapılan tek şey ise, sadece argümanları bire bir eşleştirmektir. Örneğin agac(“Ali”, bos_dal, bos_dal) şeklindeki bir yapıyı agac(“Emine”, bos_dal, bos_dal) yapısının sol alt dalı olarak yerleştirilmek istenirse, yazılması gereken tek şey şu hedefi çalıştırmaktır.

sola_yerlestir(agac(“Ali”, bos_dal, bos_dal), agac(“Emine”, bos_dal, bos_dal), T).

T’nin değeri agac(“Emine”, agac(“Ali”, bos_dal, bos_dal), bos_dal)

olur. Aşağıdaki örnekte bu teknik gösterilmiştir.

DOMAINS

agac_yapisi = agac(string,agac_yapisi,agac_yapisi); bos_dal()

PREDICATES

agac_olustur(string,agac_yapisi)

sola_yerlestir(agac_yapisi,agac_yapisi,agac_yapisi)

saga_yerlestir(agac_yapisi, agac_yapisi, agac_yapisi)

basla

CLAUSES

agac_olustur(A,agac(A,bos_dal,bos_dal)).

sola_yerlestir(X,agac(A,_,B),agac(A,X,B)).

saga_yerlestir(X,agac(A,B,_),agac(A,B,X)).

basla:-      

%Tek daldan oluşan ağaçları oluşturalım

agac_olustur(“Hasan”,Ha),

agac_olustur(“Fatma”,Fa),

agac_olustur(“Ali”,Al),

agac_olustur(“Fuat”,Fu),

agac_olustur(“Leyla”,Le),

agac_olustur(“Ayse”,Ay),

agac_olustur(“Emine”,Em),

%dalları birleştirelim

sola_yerlestir(Ha, Al, Al2),

saga_yerlestir(Fa, Al2, Al3),

sola_yerlestir(Fu, Ay, Ay2),

saga_yerlestir(Le, Ay2, Ay3),

sola_yerlestir(Al3, Em, Em2),

saga_yerlestir(Ay3, Em2, Em3),

%sonucu göster

write(Em3,’\n’).

GOAL basla.

Program yazılıp çalıştırılınca ekranda şu sonuç görüntülenir.

agac(“Emine”,agac(“Ali”,agac(“Hasan”,bos_dal,bos_dal),agac(“Fatma”,bos_dal,bos_dal)),agac(“Ayse”,agac(“Fuat”,bos_dal,bos_dal),agac(“Leyla”,bos_dal,bos_dal)))

yes

Prolog’da bir değişken herhangi bir değeri aldıktan sonra, artık bu değeri değiştirmenin bir yolu yoktur. Bundan dolayı yukarıdaki örnekte çok sayıda değişken ismi kullanılmıştır. Her yeni değer oluştuğunda, yeni bir değişken tanımlamamız gerekir.

6.11. Binary Arama Ağacı

Şimdiye kadar ağaç yapısı, bir ağaç ve elemanları arasındaki ilişkileri göstermek için kullanıldı. Temel amaç bu olsaydı, bunun yerine cümleciklerle ifade edilen olgular kullanmak mümkün olurdu. Oysa ağaç yapısının başka kullanımları da vardır. Ağaç yapılarını kullanarak veri saklamak ve istenildiğinde bu değerleri bulmak çok kolaydır. Bu maksatla oluşturulan ağaç yapısına arama ağacı adı verilir. Programcı açısından buna liste veya array tipindeki verilere bir alternatif gözüyle bakılabilir. Basit bir ağaç yapısını tararken, öncelikle o an içinde bulunulan hücreye, daha sonra bu hücrenin solu ve sağına, belirli bir değeri ararken, bir ağaç yapısındaki bütün hücrelere bakılması gerekebilir.

İşte binary arama ağacı, herhangi bir hücreye bakarak aranan bir değerin hangi alt dalda bulunacağını tahmin edebilecek şekilde tasarlanır. Bunun için veri parçaları arasında ne tür sıralama olacağının (Örneğin alfabetik veya sayısal sıralama) tanımlanması gerekir. Sol taraftaki alt dalda bulunan veri, o an içinde bulunulan hücredeki veriden önce gelir ve sağ taraftan devam edilir. Aşağıdaki akış şemasını inceleyim.

Şekil 6.3. Binary tarama yapısı

Farklı sırada yerleştirilen aynı isimlerin farklı bir ağaç şeması oluşturur. Ayrıca, şemada 10 isim olmasına rağmen, bunlardan herhangi biri en fazla 5 adımda bulunabilir.

Binary bir tarama yapısında bir hücreye bakarken, geriye kalan hücrelerin yarısını elimine edilir. Bu yüzden tarama çok çabuk ilerler. Bir Binary Tarama Yapısındaki bir maddeyi bulmak için gereken zaman ortalama olarak log2N’dir.

Bir ağaç oluştururken, işe önce boş bir ağaç ile başlanır. Daha sonra diğer parçalar teker teker ilave edilir. Bir madde ilave etmek için gereken prosedür, bir maddeyi aramak için gereken ile tamamen aynıdır.

1.     Eğer içinde bulunulan nokta boş bir ağaç ise, buraya bir madde yerleştir.

2.     Değilse, buraya yerleştirilecek maddeyi, orada saklı olan madde ile karşılaştır. Karşılaştırmanın sonucuna göre, maddeyi sol veya sağ alt dala yerleştir.

Bunun için Prolog’a 3 cümle gerekir. İlk cümle:

yerlestir(Yeni_Madde, bos, agac(Yeni_madde, bos, bos):-!.

Bunu konuşma diline “Yeni_madde’yi bos olan yere yerleştirmenin sonucu agac(Yeni_madde, bos, bos) olur.” Buradaki Cut komutu, cümlenin uygun olması durumunda başka bir cümlenin denenmemesi içindir.

İkinci ve üçüncü cümleler boş yerlere yerleştirmek için kullanılır.

Yerlestir(Yeni_Madde, bos, agac(Eleman, Sol, Sag), agac(Eleman, Yeni_Sol, Sag):- Yeni_Madde<Eleman, !, yerlestir(Eleman, Sol, Yeni_Sol).

Yerlestir(Yeni_Madde, bos, agac(Eleman, Sol, Sag), agac(Eleman, Sol, Yeni_Sag):- yerlestir(Yeni_Madde, Sag, Yeni_Sag).

Eğer Yeni_Madde<Eleman olursa, değer sol alt dala yerleştirilir; aksi takdirde sağ alt dala yerleştirilir.

6.12. Ağaca Bağlı Sıralama

Ağaç yapısı oluşturulduktan sonra, bu yapı içerisindeki bütün maddeleri alfabetik olarak elde etmek çok kolaydır. Kullanılacak algoritma aşağıya-doğru-tarama yönteminin değişik bir şeklidir:

1.     Eğer ağaç boş ise hiçbir şey yapma.

2.     Değilse, sol tarafta olan bütün değerleri, daha sonra o anki elemanı, sonra da sağ taraftaki bütün elemanları al.

Prolog diliyle, aşağıdaki şekilde ifade edilir.

Hepsini_al(bos).

Hepsini_al(agac(Madde, Sol, Sag)):-

Hepsini_al(Sol), isleme_devam_et(Madde), hepsini_al(sag).

Örnek:

Aşağıdaki programda ekrandan yazılan karakterler, daha sonra alfabetik sırayla görüntülenmektedir. Karakterler kendi aralarında büyük veya küçük olmalarına göre de sıralanmaktadır. Programda kullanılan bazı yüklemler daha sonra incelenecektir.

DOMAINS

karakter_dizisi = agac(char, karakter_dizisi, karakter_dizisi); son

PREDICATES

nondeterm basla(karakter_dizisi)

eylem(char, karakter_dizisi, karakter_dizisi)

agac_olustur(karakter_dizisi, karakter_dizisi)

yerlestir(char, karakter_dizisi, karakter_dizisi)

agaci_yaz(karakter_dizisi)

nondeterm tekrar

CLAUSES

basla(Agac):-

tekrar,nl,

write(“***********************”),nl,

write(“Agaci guncelleme  :  1 \n”),

write(“Agaci incelemek   :  2 \n”),

write(“Programi bitirmek :  7 \n”),

write(“***********************”),nl,

write(“Tercihiniz > “),

readchar(X),nl,

eylem(X, Agac, Yeni_agac),

basla(Yeni_agac).

eylem(‘1’,Agac,Yeni_agac):-

write(“Istediginiz karakterleri yaziniz, bitirmek için # karakterini giriniz: “),nl,

agac_olustur(Agac, Yeni_agac).

eylem(‘2’,Agac,Agac):-

agaci_yaz(Agac),

write(“\nDevam etmek için bir tusa basiniz..”),

readchar(_),nl.

eylem(‘7’, _, son):-

exit.

agac_olustur(Agac, Yeni_agac):-

readchar(C),

C<>’#’,!,

write(C, ” “),

yerlestir(C, Agac, Gecici_agac),

agac_olustur(Gecici_agac, Yeni_agac).

agac_olustur(Agac, Agac).

yerlestir(Yeni,son,agac(Yeni,son,son)):-!.

yerlestir(Yeni,agac(Eleman,Sol,Sag),agac(Eleman,Yeni_sol,Sag)):-

Yeni<Eleman,!,

yerlestir(Yeni,Sol,Yeni_sol).

yerlestir(Yeni,agac(Eleman,Sol,Sag),agac(Eleman,Sol,Yeni_sag)):-

yerlestir(Yeni,Sag,Yeni_sag).

agaci_yaz(son).

agaci_yaz(agac(Madde,Sol,Sag)):-

agaci_yaz(Sol),

write(Madde, ” “),

agaci_yaz(Sag).

tekrar.

tekrar:-tekrar.

GOAL write(“Yazilan karakterleri siralama “),nl, basla(son).


7. LİSTELER VE REKÜRSİYON

Çok sayıda eleman içeren nesnelerle çalışmak, yani liste işlemek, Prolog’un güçlü yönlerinden biridir. Daha önce kısaca anlatılan bu konu, burada daha ayrıntılı olarak ele alınacaktır. Listelerin ne oldukları, nasıl tanımlandıkları ve uygulama programlarında nasıl kullanılabilecekleri hakkında bazı örnekler çözülecektir. Liste işleme metoduna rekursiv ve prosedürel yönlerden yaklaşırken, Prolog’un çok önemli yüklemlerinden olan member ve append üzerinde durulacaktır.

Daha sonra verilen dahili bir sorgu için mümkün olan bütün çözümleri bulan ve görüntüleyen findall standart yüklemini incelenecektir.

7.1. Listeler

Bir listenin, çok sayıda nesne içeren bir nesne olduğu bilinmektedir. Prolog’daki bir liste, diğer dillerdeki dizilere(array) karşılık gelir. Listelerin dizilerden en önemli farkı, bir diziyi kullanmadan önce bu dizide kaç tane eleman olacağını önceden belirtmenin gerekmemesidir. Eğer birleştirilecek nesnelerin sayısı önceden biliniyorsa, bunlar tek bir bileşik veri yapısının argümanı haline getirilebilir.

Elemanları a, b ve c olan bir liste

[a, b, c]

şeklinde ifade edilir. Burada a, b ve c birer elemandır ve bu elemanlar bir virgül ile ayrılarak […..] arasında yazılırlar.

Örnekler:

[araba, ev, televizyon]

[“Mahmut AKSOY”, “Sefer KAÇAR”, “Mahmut ÜSTÜNDAĞ”]

7.2.1. Liste Tanımlanması

Liste tanımları programların domains bölümlerinde yapılır. Tamsayılardan oluşan bir liste

Domains

tamsayilar_listesi = integer*

şeklinde tanımlanır. Burada * tamsayilar_listesi argümanının tamsayılardan oluşan bir liste olduğunu gösterir. Liste tanımlarken, listeye verilen ismin Prolog’da hiçbir önemi yoktur. Önemli olan şey * ile tanımlı kelimenin bir listeyi temsil ettiğinin belirtilmesidir.

Bir listenin elemanları herhangi bir şey olabileceği gibi, başka listeler de eleman olarak kullanılabilirler. Dikkat edilmesi gereken şey, bir listedeki elemanların tamamının aynı tipde olması, bu elemanların tipinin de ayrıca tanımlanmasıdır.

Örnek:

Domains

Benim_listem = elemanlarim*

elemanlarim= integer /*real, symbol vs. olabilir.*/

Fakat bir listede bulunan standart tiplerin karışık olarak kullanılması mümkün değildir. Örneğin

benim_listem = elemanlarim*

elemanlarim= integer; real; symbol

tanımlaması yanlıştır. Fakat integer, real ve symbol tiplerinden oluşan bir liste tanımlamak için farklı operatörler kullanılabilir:

benim_listem = elemanlarim*

elemanlarim= tamsayi(integer); reel_sayi(real); karakter(symbol)

7.2.2. Bir Listenin Parçaları: Baş ve Kuyruk

Bir liste iki kısımdan oluşur. Bunlar listenin ilk elemanının oluşturduğu baş ve geriye kalan elemanların oluşturduğu kuyruk kısmıdır. Yani bir listenin baş kısmı daima sadece tek eleman, kuyruk kısmı ise daima ayrı bir listeden ibarettir.

Örnek:

[a, b, c] listesinde a listenin başı; b ve c ise kuyruk kısmıdır.

[a] listesinde listenin başı a olur. [], yani boş bir liste de listenin kuyruk kısmıdır. Boş bir listeyi baş ve kuyruk olarak ayırmak mümkün değildir. Dolayısıyla bir listenin kuyruk kısmının her seferinde ilk elemanı alınırsa, sonuçta boş bir listeye ulaşılır. Bu yüzden listeleri bileşik nesneler gibi ağaç yapısında görmek mümkündür. Örneğin [a, b, c, d] listesine bu işlem aşağıdaki gibi uygulanır.

                              liste

                              /    \

                           a    liste

                                 /    \

                               b    liste

                                     /    \

                                   c    liste

                                         /    \

                                        d     [ ]

Burada [a] ile a birbirinin aynısı değildir. Çünkü a tek başına bir eleman iken [a] tam bir bileşik yapıdadır. Çünkü  [a]

         liste

         /    \

        a     [ ]

şeklinde ifade edilir.

7.2.3. Listelerin İşlenmesi

Prologda bir listenin elemanlarını virgüle ayırmak yerine, baş ve kuyruk kısımlarını daha belirgin olarak ifade etmek için sadece baş ve kuyruk kısımları dikey çizgi ile ‘|’ ayrılır.

Örneğin:

[a, b, c] yerine [a|[b, c]] veya benzer şekilde devam edersek [a|[b|[c]]] biçimi kullanılabilir. Burada [c] listesini de baş ve kuyruk olarak ayırırsak, [a|[b|[c|[]]]] olur.

Tablo 7.2. Listelerin baş ve kuyruk halinde gösterilmeleri

Liste

Baş

Kuyruk

[‘a’, ‘b’, ‘c’]

‘a’

[‘b’, ‘c’]

[ ‘a’ ]

‘a’

[] /* Boş liste*/

[ ]

Tanımsız

Tanımsız

[[1, 2, 3], [2, 3, 4], []]

[1, 2, 3]

[[2, 3, 4], []]

 

Prolog

Prolog Dili

 

 İÇİNDEKİLER 

TEŞEKKÜR…………………………………………………………………………………………………… i

İÇİNDEKİLER…………………………………………………………………………………………….. ii

ÖZET…………………………………………………………………………………………………………. viii

ABSTRACT………………………………………………………………………………………………….. x

1.GİRİŞ………………………………………………………………………………………………………… 1

2. PROLOG’UN (PROGRAMMING IN LOGIC) TEMELLERİ……………………….. 3

2.1. Gerçekler: Bilinen olgular………………………………………………………………………….. 4

2.2. Kurallar: Verilen Gerçeklerden Hüküm Çıkarma………………………………………….. 4

2.3. Sorgulamalar: (Querries)……………………………………………………………………………. 5

2.4. Gerçekler, Kurallar ve Sorgulamaların Bir Araya Yazılması…………………………… 6

2.5. Değişkenler: Genel Cümleler……………………………………………………………………… 7

2.6. Bölüm Özeti……………………………………………………………………………………………. 8

2.7. Konuşma Dilindeki Cümlelerin Prolog Programlarına Aktarılması………………….. 9

2.8. Cümleler (Gerçekler ve Kurallar)………………………………………………………………… 9

2.9. Olgular Arasındaki İlişkiler: Yüklemler (Predicates)……………………………………. 12

2.10. Değişkenler (Genel Cümleler)………………………………………………………………… 13

2.10.1. Prolog’da Değişkenlerin Değer Alması…………………………………………….. 13

2.11. Anonim Değişkenler……………………………………………………………………………… 15

2.12. Hedefler (Sorgular)……………………………………………………………………………….. 16

2.13. Açıklama Satırları…………………………………………………………………………………. 17

2.14. Eşleştirme……………………………………………………………………………………………. 18

2.15. Bölüm özeti…………………………………………………………………………………………. 18

3. VISUAL PROLOG PROGRAMLARININ TEMEL BÖLÜMLERİ…………….. 20

3.1. Clauses(Olgular veya Kurallar)…………………………………………………………………. 20

3.2. Predicates (Yüklemler)……………………………………………………………………………. 20

3.3. Domains (Değişken Tipleri)……………………………………………………………………… 20

3.4. Goal (Hedef)…………………………………………………………………………………………. 20

3.5. Yüklem Tanımı………………………………………………………………………………………. 20

3.6. Domains (Tip tanımları) Bölümü………………………………………………………………. 22

3.7. Goal Bölümü…………………………………………………………………………………………. 25

3.8. Deklarasyon ve Kurallara Ayrıntılı Bakış…………………………………………………… 25

3.8.1. Char………………………………………………………………………………………………. 26

3.8.2. Real……………………………………………………………………………………………….. 26

3.8.3. String…………………………………………………………………………………………….. 26

3.8.4. Symbol…………………………………………………………………………………………… 26

3.9. Yüklemlerdeki Argümanların Yazılması……………………………………………………. 27

3.10. Kuralların Yazım Biçimi………………………………………………………………………… 29

3.11. Prolog ve Diğer Dillerdeki ‘if’ Komutunun Karşılaştırılması………………………. 30

3.12. Otomatik Tip Dönüştürmeler………………………………………………………………….. 30

3.13. Bir Programın Diğer Bölümleri……………………………………………………………….. 31

3.13.1. Database Bölümü…………………………………………………………………………… 31

3.13.2. Constants Bölümü…………………………………………………………………………. 31

3.13.3. Global Bölümü………………………………………………………………………………. 32

3.14. Derleyici Direktifleri……………………………………………………………………………… 32

3.14.1. Include Direktifi……………………………………………………………………………. 32

3.15. Bölüm Özeti………………………………………………………………………………………… 33

4. EŞLEŞTİRME VE GERİYE İZ SÜRME……………………………………………………. 34

4.1. Geriye İz Sürme……………………………………………………………………………………… 36

4.2. Geriye İz Sürme Mekanizmasının Ayrıntıları……………………………………………… 39

4.2.1. Geriye İz Sürmenin 4 Temel Prensibi…………………………………………………. 40

4.3. Tarama İşleminin Kontrol Edilmesi…………………………………………………………… 44

4.4. fail Yükleminin Kullanılması……………………………………………………………………. 45

4.5. Geriye İz Sürmeyi Engelleme…………………………………………………………………… 46

4.5.1. Cut Komutunun Kullanımı……………………………………………………………….. 46

4.5.2. Geriye İz Sürmeyi Engelleme……………………………………………………………. 48

4.6. Determinism ve Cut………………………………………………………………………………… 49

4.7. Not Yüklemi………………………………………………………………………………………….. 50

4.8. Prosedürel Açıdan Prolog………………………………………………………………………… 54

4.8.1. Kurallar ve Olguların Prosedürlere Benzerliği……………………………………… 55

4.8.2. Bir Kuralın Case ifadesi Gibi Kullanılması………………………………………….. 55

4.8.3. Bir Kural İçinde Test Yapmak…………………………………………………………… 56

4.8.4. Cut Komutunun Goto Gibi Kullanılması…………………………………………….. 56

4.9. Hesaplanmış Değerleri Görüntüleme…………………………………………………………. 57

5. BASİT VE BİLEŞİK NESNELER…………………………………………………………….. 60

5.1. Basit veri nesneleri………………………………………………………………………………….. 60

5.1.1 Veri Nesneleri Olan Değişkenler………………………………………………………… 60

5.1.2. Veri Nesneleri Olan Sabitler……………………………………………………………… 60

5.1.3. Karakterler……………………………………………………………………………………… 60

5.1.4. Sayılar……………………………………………………………………………………………. 61

5.1.5. Atomlar………………………………………………………………………………………….. 61

5.2. Bileşik Veri Nesneleri ve Fonksiyon Operatörleri……………………………………….. 62

5.3. Bileşik Nesnelerin Eşleştirilmesi……………………………………………………………….. 62

5.4. Bileşik Nesneleri Eşleştirmek İçin ‘=’ Sembolünün Kullanılması………………….. 63

5.5. Birden Fazla Nesneyi Tek Nesne Olarak Kullanmak…………………………………… 63

5.6. Bileşik Nesnelerin Tiplerini Tanımlamak……………………………………………………. 67

5.7. Tip Tanımlamaları Üzerine Kısa Bir Özet…………………………………………………… 69

5.8. Çoklu-Düzey Bileşik Nesneler…………………………………………………………………. 69

5.9. Çoklu-Tipli Argümanlar…………………………………………………………………………… 70

5.10. Listeler………………………………………………………………………………………………… 70

6. TEKRARLAMA VE REKÜRSİYON……………………………………………………….. 73

6.1. Tekrarlı İşlemler……………………………………………………………………………………… 73

6.2. Geriye İz Sürme……………………………………………………………………………………… 73

6.3. Önceki ve Sonraki Eylemler…………………………………………………………………….. 75

6.4. Döngülü Geriye Dönüşün Uygulanması…………………………………………………….. 76

6.5. Rekursif Prosedürler……………………………………………………………………………….. 77

6.5.1. Rekursiyonun Avantajları…………………………………………………………………. 78

6.5.2. Sondan Rekursiyon Optimizasyonu…………………………………………………… 79

6.5.3. Sondan Rekursiyonun Kullanımı……………………………………………………….. 80

6.5.3. Sondan Rekursiyonu Engelleme………………………………………………………… 80

6.6. Rekursiyonda Cut Kullanımı……………………………………………………………………. 83

6.7. Argümanların Döngü Değişkeni Olarak Kullanımı……………………………………… 85

6.8. Rekursiv Veri Yapıları…………………………………………………………………………….. 88

6.9. Ağaç Biçimindeki Veri Türleri…………………………………………………………………. 89

6.9.1. Bir Ağaç Yapısında Tarama Yapma…………………………………………………… 89

6.10. Bir Ağaç Oluşturmak…………………………………………………………………………….. 91

6.11. Binary Arama Ağacı……………………………………………………………………………… 93

6.12. Ağaca Bağlı Sıralama……………………………………………………………………………. 95

7. LİSTELER VE REKÜRSİYON………………………………………………………………… 98

7.1. Listeler………………………………………………………………………………………………….. 98

7.2.1. Liste Tanımlanması………………………………………………………………………….. 98

7.2.2. Bir Listenin Parçaları: Baş ve Kuyruk………………………………………………… 99

7.2.3. Listelerin İşlenmesi………………………………………………………………………… 100

7.2.4. Listelerin Kullanılması……………………………………………………………………. 101

7.2.5. Liste Elemanlarının Sayılması………………………………………………………….. 102

7.2. Sondan Rekursiyona Yeniden Bakış……………………………………………………….. 103

7.3. Liste Elemanlığı……………………………………………………………………………………. 106

7.4. Listeleri Birleştirme………………………………………………………………………………. 106

7.5. Rekursiyona Prosedürel Bir Bakış…………………………………………………………… 107

7.6. Bütün Çözümleri Bir Defada Bulma……………………………………………………….. 108

7.7. Bileşik Listeler……………………………………………………………………………………… 109

8. AKIŞ DENETİMİ………………………………………………………………………………….. 111

8.1. Bileşik Akış…………………………………………………………………………………………. 112

8.2. Yüklemlerin Akış Biçimlerini Tanımlama…………………………………………………. 113

8.3. Akış Analizini Kontrol Etmek………………………………………………………………… 113

8.4. Referans Değişkenler…………………………………………………………………………….. 115

8.4.1. Referans Tip Tanımı……………………………………………………………………….. 116

8.4.2. Referens Tip ve İzleme Dizileri(array)………………………………………………. 116

8.5. Referans Tip Kullanımı………………………………………………………………………….. 117

8.6. Akış Biçimine Yeni Bir Bakış………………………………………………………………… 118

8.7. İkili (Binary) Ağaç Yapısının Referans Tip İle Kullanımı…………………………… 119

8.8. Referans Tip Kullanarak Sıralama…………………………………………………………… 120

8.9. Binary (İkili) Tip…………………………………………………………………………………… 121

8.9.1. Binary Terimlerin Kullanılması………………………………………………………… 122

8.9.2. Binary Terimlerin Yazım Biçimi………………………………………………………. 122

8.9.3. Binary Terimlerin Oluşturulması………………………………………………………. 122

8.9.3.1. makebinary(1)………………………………………………………………………… 123

8.9.3.3. composebinary(2)……………………………………………………………………. 123

8.9.3.4. getbinarysize(1)………………………………………………………………………. 123

8.9.4. Binary Terimlere Erişim………………………………………………………………….. 123

8.9.4.1. getentry(2)……………………………………………………………………………… 124

8.9.4.2. setentry(3)……………………………………………………………………………… 124

8.9.5. Binary Terimleri Eşleştirme……………………………………………………………… 124

8.9.6. Binary Terimleri Karşılaştırma…………………………………………………………. 124

8.9.7. Terimleri Binary Terimlere Dönüştürme……………………………………………. 126

8.9.7.1. term_bin(3)…………………………………………………………………………….. 126

8.10. Hatalar ve İstisnalarla Uğraşma………………………………………………………… 126

8.10.1. exit(0), exit(1)……………………………………………………………………………… 127

8.10.2. trap(3)………………………………………………………………………………………… 127

8.10.3. errormsg(4)………………………………………………………………………………….. 128

8.10.4. Hataların Bildirilmesi……………………………………………………………………. 129

8.11. Hata Düzeyi……………………………………………………………………………………….. 129

8.11.1. lasterror(4)…………………………………………………………………………………… 130

8.11.2. Terim Okuyucudan Gelen Hataları Görme………………………………………. 130

8.11.3. consulterror(3)……………………………………………………………………………… 130

8.11.4. readtermerror(2)…………………………………………………………………………… 132

8.12. Break Kontrolü (Sadece Metin Modunda)……………………………………………… 132

8.12.1. break(1)………………………………………………………………………………………. 132

8.12.2. breakpressed(1)……………………………………………………………………………. 132

8.13. DOS Metin Modunda Kritik Hata Kontrolü…………………………………………… 133

8.13.1. criticalerror(4)……………………………………………………………………………… 133

8.13.2. fileerror(2)…………………………………………………………………………………… 134

8.14. Dinamik Cut………………………………………………………………………………………. 134

8.15. Programlama Stilleri……………………………………………………………………………. 136

8.15. Cut Yüklemini Yerleştirmek…………………………………………………………………. 138

9. ÖZEL GELİŞTİRİLMİŞ PROLOG ÖRNEKLERİ……………………………………. 139

9.1. Küçük bir Uzman Sistem örneği……………………………………………………………… 139

9.2. Basit bir yön problemi…………………………………………………………………………… 143

9.3. Hazine Avcısı………………………………………………………………………………………. 144

TARTIŞMA VE SONUÇ……………………………………………………………………………. 147

KAYNAKLAR………………………………………………………………………………………….. 150

ŞEKİLLER ve TABLOLAR……………………………………………………………………….. 152

ÖZGEÇMİŞ………………………………………………………………………………………………. 153

 


ÖZET

 

Yüksek Lisans Tezi

 

 

PROLOG PROGRAMLAMA DİLİ İLE MAKİNE MÜHENDİSLİĞİ ALANINDA UZMAN SİSTEMLERİN HAZIRLANMASI TEKNİKLERİ

 

 

Yavuz Selim AYDIN

 

Harran Üniversitesi

Fen Bilimleri Enstitüsü

Makina Anabilim Dalı

 

 

1998, Sayfa: 164

 

 

Günümüzde bilgisayar alanında gözlenen hızlı değişim, yeni teknolojik imkanların ortaya çıkmasına neden olmaktadır. İnsanoğlu daha bundan birkaç yıl öncesinde hayal edemediği gelişmelerin günümüzde gerçekleştiğini gördükçe hayretler içerisinde kalmaktadır. Bilgi teknolojiyle yakından ilgilenenler dahi, bu hızlı değişime ayak uydurmada zorlanabilmektedir.

Bilgisayarların insanlar gibi düşünmesine sağlamak için yoğun çalışmalar sürdürülmededir. Mümkün olduğunca insan beyni fonksiyonlarına yakın işlevleri yerine getirebilecek mikroişlemcilerin tasarımı üzerinde çalışmalar sürdürülmektedir. Bu çalışmalar beşinci kuşak bilgisayar dönemine rastladığı ve bu kuşak içerisinde Yapay Zeka (Artificial Intelligece) alanlarında önemli gelişmelerin yer aldığı görülür.

Bilgi teknolojisinin amacı, uzman kişilerin bilgilerini bilgisayarda kullanarak yeni sonuçlar elde etmektir. Uzman sistemler, yapay zekanın bir dalı olup, bir probleme uzman insan düzeyinde bir çözüm bulmak için uzman bilgisini kullanırlar.

Yapay zekada sık kullanılan programlama dillerinden biri de Prolog dilidir. Son versiyonu Visual Prolog olarak piyasaya çıkartılmıştır. Visual Prolog, ifadeler mantığının kullanarak, bilgisayara çözümü aranan problem hakkında bilinen gerçekleri ve kuralları vererek, uygun bir çözüm elde edilmesine sağlar.

Konvansiyonel programlama dillerinde, bir programcı herhangi bir problemin nasıl çözüleceğini bilgisayara adım adım tanıtmak zorundadır. Oysa bir Visual Prolog programcısının yapması gereken şey, çözüm aranan problem hakkında bilinen gerçekler ve kuralları, bunlar arasındaki ilişkileri tanımlamak, daha sonra mümkün olana bütün çözümleri bulmak görevini Prolog’a vermektir. Visual Prolog, aritmetik işlemlerin yapılmasına da imkan tanır.

Visual Prolog, C++ ve diğer bilinen programlama dilleri kadar hızlı çalışır. Hızlı bir derleyici, bilgisayar dünyasında daima aranan bir avantaj olmuştur. Visual Prolog, MS DOS, Windows 3.1, Windows 95, Windows NT, Unix ve OS/2 işletim sistemleri altında programlamaya imkan tanıyan bir çoklu ortam programlama dilidir.

Uzman sistemlerin, bütün kullanıcılara düşük maliyetli uzmanlık, insanlar için tehlikeli olan ortamlarda riski azaltma, emekli olabilen veya vefat edebilen insan uzmanlar yerine, her zaman kalıcı olan uzmanlar ve verilen kararların net açıklanabilmesi gibi güzel özellikleri vardır.

Bu çalışma, yapay zeka alanında çalışma yapan, uzman sistem tasarlamak isteyen fakat Türkçe kaynak bulamayan, kaynak kullanarak Prolog dilini öğrenmek isteyen araştırmacılara faydalı olmak amacıyla gerçekleştirilmiştir. Prologun temel mantığı, elemanların ayrıntılı anlatımı, Prologun en önemli özelliklerinden biri olan Geriye İz Sürme ve bu konuların açık biçimde kullanıldığı örnekler doyurucu bilgi sunmaktadır.

Anahtar Kelimeler: Uzman Sistemler, Yapay Zeka, Visual Prolog, Programlama Dilleri


ABSTRACT

 

 

Master Thesis

 

 

 

 

TECHNQUES ON THE DESIGN OF EXPERT SYSTEMS IN MECHANICAL ENGINEERING BY USING THE VISUAL PROLOG PROGRAMMING LANGUAGE

 

 

Yavuz Selim AYDIN

 

Harran University

Graduate School of Natural and Applied Sciences

Department of Mechanical Engneering

 

 

1998, Page: 164

 

 

Rapid advancement in the computer technology has brought new technological facilities. People are surprised to see that the technological innovations which could not even be dreamt of just a few years ago have been achieved. Even those closely involved in the Information Technology may sometimes face some difficulties in coping up with the rapid changes.

Intensive studies have been performed by scientists to enable a computer to imitate human beings in the way he thinks. Studies to design microprocessors capable of performing similar functions of human brain still continue. It is observed that such studies coincided with the evolution period of the fifth generation computers and that important improvements have been recorded in the field of Artificial Intelligence.

Information technology aims at making use of an expert’s knowledge from which new results may be retrieved. Being a subbranch of Artificial Intelligence, expert systems use the knowledge of a human expert to find a solution for a given problem at expert level.

One of the programming languages frequently used in artificial intelligence is Prolog, of which the latest version has been released as the Visual Prolog. It uses logical expressions which tell the computer the facts and rules about a problem so that a solution based on the given facts and rules could be obtained by using a deductive procedure.

In conventional programming languages, a programmer must describe the solution to a problem step by step. In the Visual Prolog, on the other hand, a programmer must only describe the facts and rules about a problem –not steps necessary for the solution- in the form of some relations and then, let the Visual Prolog find all possible solutions for that problem. Visual Prolog is capable of performing arithmetic operations as well.

Visual Prolog runs as fast as C++ and other popular programming languages. A fast compiler has always been an advantage in the computing world. The Visual Prolog is a multiplatform programming language that allows programming under MS DOS, Windows 3.1-95 and NT, Unix and OS/2 operating systems.

Experts systems have some interesting characteristics such as low cost of expertise for all users, low risks in situations dangerous for humans, ever continuing expertise despite to human experts who may retire or pass away, and clear explanation of what has been concluded.

This study has been performed for researchers who wish to carry out studies in the field of Artificial Intelligence, design expert systems in Mechanical Engineering but lack to find a source about the Visual Prolog in Turkish and like to learn this language. Many superior features of the Visual Prolog, including backtracking and recursion, have been clearly explained in this study by providing many sample programs.

Keywords: Expert Systems, Artificial Intelligence, Visual Prolog, Programming Languages


1. GİRİŞ

 

İngilizce Expert System kelimelerinden türetilerek Türkçe’ye kazandırılmış olan Uzman Sistem yazılımları alanında, ülkemizde yoğun çalışmaların yapıldığı gözlenmektedir.

Bir Uzman Sistem, Bilgisayar Destekli Eğitim amaçlı da kullanılabileceğine göre, eğitim ve öğretim için gerekli olabilecek her türlü formasyonu taşımalıdır. Öğrenme, doğrudan bilgisayardan yapılacağı için, klasik öğretmen merkezli eğitime nazaran, içeriğin daha doyurucu ve cazip özellikler taşıması gerekir. Cazip unsurlar, bilgisayar tarafından yönetilmeli ve uygun ortamlarda ekranda veya bilgisayarın çevre birimlerinde ortaya çıkabilmelidir.

Öğretilmek istenen bir konuda işlem basamaklarının sırası çok önemlidir. Öğrenciye yöneltilecek sorular çok iyi belirlenmeli ve soru sorarken öğretme mekanizması devreye alınmalıdır. Soruların sıralanışında yeterli hassasiyet gösterilmediği takdirde, hem öğrenme eksik olabilir, hem de öğrenci yanlış bilgilendirmeye sevk edilebilir.

Uzman sistem üzerinde çalışan öğrenci, bilgisayarı ile yalnız başına kalacaktır. Sürekli monoton bir ekran görüntüsü yüzünden, öğrencinin öğrenme arzusu kırılabilir, bilgisayar önünde canı sıkılabilir. O halde öğretme esnasında, öğrencinin dikkatinin konuya sevk edilebilmesi için, program arasında görsel ve işitsel yöntemlerle uygun uyarılar yapılabilmelidir.

Bilgisayar destekli eğitimin kullanılabileceği her yere ilave olarak, problemlere çözüm getirilmek istenen her sahada Uzman Sistem kullanılabilir.

Bir Uzman Sistem hazırlanırken asgari olarak aşağıdaki hususların göz önünde bulundurulması gerekir.

·      Hazırlanacak proje konusu hem güncel olmalı hem de o konuda yeterli kaynak bulunabilmelidir.

·      Konunun bol miktarda resim ve şekil içermesi, kullanıcının öğrenme hızını artıracak bir faktördür.

·      Proje başlangıcında, güzel bir sunu yazılımıyla (örneğin Power Point gibi) proje hakkında özet bilgiler verilmeli, proje tasarımcısı ve denetleyen kişilerin isimleri, resimleri ve faydalanılan kaynaklar hakkında bilgi verilmelidir.

·      Konu anlatımına geçmeden önce, güzel bir müzik eşliğinde bilgisayar, kullanıcının ismini girmesini istenmelidir. Çünkü ilerleyen konular içerisinde bazı yerlerde esprili cümlelerle bilgisayarın kullanıcıya ismi ile hitap etmesi, kullanıcının aniden dikkatini çekmeye neden olabilmekte ve kullanıcı bu durumdan fazlasıyla memnun kalabilmektedir.


2. PROLOG’UN (PROGRAMMING IN LOGIC) TEMELLERİ

Bir Prolog programı, (Basic, Fortran, Pascal, C) olduğu gibi bir dizi komut satırından değil, doğruluğu önceden bilinen gerçeklerden ve bu gerçeklerden bilgi sağlamaya yarayan kurallardan oluşur.

Prolog, cümlecikler (Horn Clauses) üzerine bina edilmiştir. Cümlecikler, yüklem mantığı denilen formal sistemin bir alt kümesidir.

Prolog’da bir Karar Motoru (Inference Engine) vardır. Bu motor, verilen bilgiyi kullanarak cevabı aranan bir problem için, mantıksal bir şekilde karar veren bir işlemdir. Karar motorundaki Kalıp Eşleştirici (Pattern Matcher) sorulara uygun olan cevapları eşleştirerek önceden bilinen ve program içine kaydedilen bilgiyi geri çağırır. Prolog, program satırları içinde sorulan bir soruyu veya hipotezi doğrulamak için, doğruluğu önceden bilinen ve veri olarak yüklenmiş olan bilgi kümesini sorgulayıp hipotezin doğruluğu hakkında karar vermeye çalışır. Kısaca söylemek gerekirse, bir Prolog programının temelini, program akışı içinde önceden verilen gerçekler ve kurallar oluşturur.

Prolog’un önemli diğer bir özelliği de şudur: Sorulan sorulara mantıklı cevaplar bulmanın yanısıra, bulduğu tek bir çözümle yetinmez, başka alternatifleri de inceleyerek mümkün olan bütün çözümleri bulur. Prolog, bir programın birinci satırından başlayıp sonuncu satırına kadar ilerleyip sadece bir çözüm bulmak yerine, zaman zaman geriye dönüş yaparak problemin her bir bölümünün çözümü için alternatif yolları da arar.

Yüklem mantığı, mantığa dayalı fikirleri yazılı bir şekilde ifade etmeye yarayacak şekilde geliştirilmiştir ve Prolog’da bu mekanizma gayet iyi kullanılır. Yüklem mantığının yaptığı ilk iş, cümlelerdeki gereksiz kelimeleri ayıklamaktır. Daha sonra cümleler-kelimeler arasındaki ilişkiler ilk sıraya, nesneler ise ilişkilerden sonra sıralanır. Bu nesneler ise ilişkilerin etkili olduğu argümanlar olarak yazılır.

Konuşma Dili                                             Prolog’daki Karşılığı

Ahmet bir insandır.                                     insan(Ahmet).

Gül kırmızıdır.                                             kirmizi(gul).

Ahmet, gülü kırmızı ise sever.                     sever(Ahmet, gul) if kirmizi(gul).

Prolog ile program yazarken, ilk önce nesneler ve bu nesneler arasındaki ilişkiler tanımlanır. ‘Ahmet gülleri sever’ cümlesindeki Ahmet ve gül kelimeleri nesne, ‘sevmek’ ise bu iki nesne arasındaki ilişkidir. Bu ilişkinin ne zaman doğru olacağını belirleyen ifadeye ise Kural denir. ‘Ahmet, gülü kırmızı ise sever’ cümlesindeki ‘sevmek’ hangi durumda Ahmet’in gülü seveceğini belirttiği için bu durumda Kural olur.

2.1. Gerçekler: Bilinen olgular

Prolog’da, nesneler arasındaki ilişkiye Yüklem denir. Tabii dilde bir ilişki bir cümle ile sembolize edilir. Prolog’un kullandığı yüklem mantığında ise bir ilişki, bu ilişkinin ismi ve bunu takiben parantez içinde yazılan nesne veya nesnelerden oluşan basit ifadelerle özetlenir. Gerçekler, tıpkı cümlelerdeki gibi ‘.’ ile biter. Aşağıdaki örneklerde ‘sevmek’ fiilinin tabii dilde ifade edilmesi gösterilmiştir.

Yasin Esra’yı sever.

Esra Cihat’ı sever.

Yasin kedileri sever.

Yukarıdaki ifadeleri olgu olarak kabul edip Prolog’daki karşılıklarını yazalım:

sever(yasin, esra).

sever(esra, cihat).

sever(yasin, kediler).

Görüldüğü gibi, gerçekler nesnelerin ve ilişkilerin değişik özelliklerini de ifade edebilirler.

2.2. Kurallar: Verilen Gerçeklerden Hüküm Çıkarma

Kurallar, gerçek olguları kullanarak bir sonuca varmak için kullanılır. Aşağıda ‘sevmek’ ilişkisinden elde edilen bazı kurallar verilmiştir:

Yasin, Esra’nın sevdiği her şeyi sever.

Hasan kırmızı olan her şeyi sever.

Bu kuralları Prolog dilinde yazmak gerekirse:

sever(yasin, hersey):-sever(esra, hersey).

sever(hasan, hersey):- kirmizi(hersey).

Buradaki :- sembolü, prosedürel dillerdeki if(eğer) anlamında olup, bir kuralın iki parçasını birleştirir.

Prolog, sever(yasin, hersey):-sever(esra, hersey) kuralını kullanarak, Yasin’in sevdiği nesneyi bulmak için önce kuralın ikinci kısmını, yani Esra’nın sevdiği nesneyi bulur. Bunun doğruluğu ispatlandıktan sonra Yasin’in sevdiği nesneyi belirler.

2.3. Sorgulamalar: (Querries)

Prolog’a bazı gerçekler tanıtıldıktan sonra, artık bu gerçeklerle ilgili sorular sormaya başlanabilir. Bunu Prolog Sistemini Sorgulama diyoruz. Veri olarak saklanan gerçekler ve gerçekler arasındaki ilişkiler bilindikten sonra, bu ilişkiler hakkında soru sorup cevap almak kolaydır.

Günlük konuşmalarda Esra Yasin’i seviyor mu? şeklindeki bir soruyu Prolog’da şöyle ifade edilir.

sever(esra, yasin).

Bunun cevabı program akışı içerisinde verdiğimiz gerçeklere bağlıdır. Yasin neyi sever? şeklindeki bir soruyu Prolog’a sormamız mümkündür. Bunu sever(yasin, Neyi) şeklinde kodlarsak, Prolog’dan şu cevabı alırız:

Neyi=esra

Neyi=kediler

2 Solutions

Çünkü önceden verilen sever(yasin, esra) ve sever(yasin, kediler) ilişkileri, bunu ispatlamaktadır.

Burada Yasin ve Esra’ın küçük harfle, Neyi kelimesinin ise büyük harfle başlamaktadır. Çünkü, yüklemdeki Yasin sabit bir nesnedir, yani değeri sabittir. Oysa Neyi bir değişkendir. Yani farklı gerçeklerle beraber, sorgudan alınacak cevaplar da farklı olacaktır. Bu yüzden değişkenler daima büyük harf veya bir ‘_’ ile başlar.

Bu durumda Neyi kelimesinin cevapları değişebilir. Prolog bir sorguya cevap ararken daima önceden verilen gerçeklerin ilkinden başlar ve hiçbirini ihmal etmeden en sondaki gerçeğe kadar ilerler.

Prolog’da, bir insana sorulabilecek başka soruları da sormak mümkündür. Fakat ‘Mehmet hangi kızı sever?’ şeklindeki bir soruya hiçbir cevap alınamaz. Çünkü yukarıdaki satırlar dikkate alındığında, bu konuyla ilgili bir bilginin mevcut olmadığı görülür. Yasin Esra’yı sevmektedir, fakat Esra’nın kız olduğuna dair bir bilgi mevcut olmadığından, Prologun bu gerçeklerden hareketle bir karara varması mümkün olamaz.

2.4. Gerçekler, Kurallar ve Sorgulamaların Bir Araya Yazılması

1. Aşağıdaki gerçekler ve kuralların var olduğunu kabul edilsin.

Büyük araba hızlıdır.

Büyük bir araba iyidir.

Küçük bir araba daha kullanışlıdır.

Kasım, eğer hızlı ise, büyük arabayı ister.

Yukarıdaki gerçeklerden anlaşılan şey, Kasım’ın hızlı ve büyük arabalardan hoşlandığıdır. Prolog da aynı sonuca varacaktır. Zaten hızlı arabalar hakkında bilgi verilmeseydi, hiçkimse Kasım’ın hızlı arabalardan hoşlandığı sonucuna varamazdı. Yapılabilecek tek şey, ne tür bir arabanın hızlı olacağını tahmin etmektir.

2.   Aşağıdaki örneğe bakarak, Prolog’un kuralları kullanarak sorgulara nasıl cevap bulduğu açıklanmıştır.

hoslanir(cengiz, masa_tenisi).

hoslanir(mehmet, yuzme).

hoslanir(yavuz, futbol).

hoslanir(levent, Spor):-hoslanir(yavuz, Spor).

Son satırdaki hoslanir(levent, Spor):-hoslanir(yavuz, Spor) bir kural olup, konuşma dilindeki karşılığı şudur: Levent, bir spor türünden eğer Yavuz da hoşlanıyorsa hoşlanır.

Bu kuralın baş tarafı hoslanir(levent, Spor) ve gövde kısmı hoslanir(yavuz, Spor) olur. Burada Levent’in yüzmeyi sevip sevmediği hakkında hiçbir bilgi yoktur. Bunu öğrenmek için hoslanir(levent,yuzme) şeklinde bir sorgu kullanmak yeterlidir. Cevap bulmak için Prolog hoslanir(levent, Spor):-hoslanir(yavuz, Spor) kuralını kullanır. Yukarıda geçen gerçeklerle bunlar arasındaki ilişkiler, aşağıdaki şekilde bir program haline getirilir

PREDICATES

nondeterm hoslanir(symbol,symbol)

CLAUSES

hoslanir(cengiz, masa_tenisi).

hoslanir(mehmet, yuzme).

hoslanir(yavuz, futbol).

hoslanir(levent, Spor):- hoslanir(yavuz, Spor).

GOAL hoslanir(levent, futbol).

Bu program Prolog’da derlenirse, ‘yes’ cevabını alınır. Çünkü hoslanir(yavuz, futbol) gerçeği Yavuz’un futboldan hoşlandığını göstermektedir. hoslanir(levent, Spor):-hoslanir(yavuz, Spor) kuralı ise Levent’in, Yavuz’un yaptığı spor türlerinden hoşlandığını göstermektedir. İlgili olgu Yavuz’un futboldan hoşlandığını gösterdiği için, Levent’in de futboldan hoşlandığını söylemek mümkündür. Bu yüzden GOAL hoslanir(levent, futbol) sorgusunun cevabı ‘yes’ olur.

Fakat hoslanir(levent, tenis) sorgusunun cevabı ‘no’ olacaktır. Çünkü:

1.   Bu sorgunun doğrulanabilmesi için gerçekler arasında öncelikle Yavuz’un tenisten hoşlandığını gösteren bir olgunun var olması gerekir.

2.   hoslanir(levent,Spor):-hoslanir(yavuz, Spor) kuralı, üstteki gerçekleri kullanarak bu konuda bir karara varamaz. Çünkü kuralın gövdesini doğrulayacak bir bilgi olmadığından, kural başarısız olur.

2.5. Değişkenler: Genel Cümleler

Prolog’da değişkenler kullanılarak genel gerçekler, kurallar yazılabilir ve genel sorular sorulabilir. Değişkenler tabii dilde de kullanılır. Tipik bir örnek vermek gerekirse:

Kasım, Ferit’in sevdiği şeyi sever.

Bu bölümün başında da belirtildiği gibi, Prolog’da değişkenler daima büyük harf veya bir ‘_’ ile başlar. sever(kasim, Sey):-sever(ferit, Sey) şeklinde ifade edilebilecek yukarıdaki cümlede, Sey değişkendir. kasim ve ferit kelimeleri sabit semboller oldukları için küçük harfle başlarlar. Bu sabitleri de ekrana büyük harfle başlayacak şekilde yazmak mümkündür. Bunun için sadece (“Kasim”, Sey) veya (“Ferit”, Sey) şeklinde yazmak yeterlidir.

2.6. Bölüm Özeti

1.   Bir Prolog programı iki tür ifadelerden oluşur: Gerçekler ve Kurallar.

·        Gerçekler, programcının doğruluğundan emin olduğu bilgiyi ilişkiler veya özellikler olarak anlattığı satırlardır.

·        Kurallar, bağımlı ilişkilerdir. Prolog bu kuralları kullanarak bir bilgiden hareketle bir konuda karar verir. Bir kural, verilen şartlar yerine geliyorsa başarılı olur, yani doğru olur.

·        Prolog’da bütün kuralların iki kısmı vardır: Baş ve Gövde kısmı. Bunlar birbirinden :- sembolleri ile ayrılırlar.

·        Baş kısmı verilen gerçekler doğrulanıyorsa doğrudur. Bu kısım aynı zamanda sonuç veya bağımlı ilişki olarak da bilinir.

·        Gövde kısmı ise doğru olması gereken şartları taşır. Böylece Prolog, programın baş kısmının doğru olduğunu ispatlayabilir.

2.   Gerçekler ve kurallar birbirinin aynısıdır. Gerçeklerin kurallardan tek farkı, açıklayıcı bilgi taşıyan gövdelerinin olmamasıdır.

3.   Prolog’a bir dizi gerçek veya kural tanıttıktan sonra, bu gerçekler veya kurallar hakkında soru sormak mümkündür. Buna Prolog Sistemini Sorgulama denir. Prolog, sorgulama esnasında, verilen gerçekler listesinin başından sonuna kadar tarama yapar ve sorguya uyan cevapları bulmaya çalışır.

4.   Prolog’daki Karar Motoru bir kuralın baş ve gövde kısmını incelerken, bilinen gerçek ve kurallara başvurur. Şartların yerine gelip gelmediğini kontrol eder. Bir kuraldaki bütün şartlar doğrulandıktan sonra, bağımlı olan kısım, yani kuralın baş kısmının doğru olduğuna karar verir. Bütün şartlar, bilinen gerçeklere göre karşılanamazsa, sorguya olumlu cevap verilemez.

Örnekler:

Prolog gerçeklerinin konuşma diline çevrilmesi, aşağıda verilmiştir.

1.   yapmaktan_hoslanir(oya, resim) = Oya, resim yapmaktan hoşlanır.

2.   cocuk(arif).= Arif, bir çocuktur.

3.   bulunur(“Çankaya Köşkü”, “Ankara”). = Çankaya Köşkü Ankara’dadır.

4.   adres(abuzer, zonturlu, “ Fatih Cad. 6. Sokak.”, “Dışkapı”, “ANKARA”, 06412).= Abuzer Zonturlu’nun adresi Fatih Cad. 6. Sokak Dışkapı, ANKARA, 06412’dir.

Şimdi tam tersini yapalım, konuşma dilinden Prolog diline çevrilme ise, aşağıdaki gibi yapılır.

1.   Vedat iyi kebap yapar = yapar(vedat, iyi_kebap).

2.   Keban Barajı Elazığ’dadır = bulunur(“Keban Barajı”, “Elazığ”).

3.   Kasım Kaya’nın telefon numarası 314 41 17’dir. telefon_no(“Kasım KAYA”, “314 41 17”).

4.   Hüseyin Meryem’in babasıdır. = baba(huseyin, meryem).

2.7. Konuşma Dilindeki Cümlelerin Prolog Programlarına Aktarılması

Bu bölümün ilk kısmında gerçekler, kurallar, ilişkiler, genel cümleler ve sorgulamalar konusunu incelenmiştir. Aynı kelimeler üzerinde çalışmakla beraber, Prolog’la daha fazla ilgili kelimeler üzerinde, yani cümlecikler, yüklemler, değişkenler ve hedefler üzerinde durulacaktır.

2.8. Cümleler (Gerçekler ve Kurallar)

Prolog dilini oluşturan iki türlü ifade vardır. Bu ifadeler gerçekler veya kurallardan ibarettir. Prolog dilinin kalbini oluşturan bu ifadelere clause denilmektedir.

Bir gerçek, bir nesnenin veya nesneler arasındaki ilişkinin bir özelliğinin sadece tek bir yönünü temsil eder. Bir gerçeğin Prolog tarafından tamamen doğru kabul edildiğini, bir sorgulamaya cevap ararken bu gerçeklerden yola çıkıldığını ve bu gerçeklerin doğruluğunun kontrol edilmediği unutulmamalıdır.

Günlük hayatımızda da doğruluğu bilinen gerçeklerden yola çıkarak bir şeyin doğru olup olmadığı araştırlır. İşte, mevcut gerçeklerden hareket ederek neyin doğru olabileceğini gösteren yapıya Prolog’da Kural denir. Şimdi Prolog’daki Kural yapısına bir örnekle yakından bakalım. Örnek:

1.   Aşağıdaki cümlede, menü’de olan bir yemeğin Mehmet’e uygun olup olmadığı sorgulanmaktadır.

Mehmet ülser olduğu için sadece doktorunun izin verdiği yemekleri yer.

Menü ve yukarıdaki kurala bakarak, Mehmet’in hangi yemeği sipariş edebileceğine karar verilebilir. Bunu yapabilmek için, menüdeki yemeğin belirli şartları taşıyıp taşımadığına bakılmaladır.

a.   Menudeki_yemek bir sebze mi?

b.   Menudeki_yemek doktorun tavsiye ettiği listede var mı?

c.   Sonuç: Eğer a ve b şıklarının ikisinin de cevabı ‘Evet’ ise, bu durumda Mehmet menüdeki bu yemeği yiyebilir.

Prolog’da bu tür ilişkilerin bir kuralla ifade edilmesi zorunludur, çünkü verilecek karar tamamen gerçeklere bağlıdır. Yukarıdaki ifadeler; Prolog gerçekleri olarak şöyle yazılabilir:

mehmet_yiyebilir(Menudeki_yemek):-

sebze(Menudeki_yemek), doktor_tavsiyeli(Menudeki_yemek).

sebze(Menudeki_yemek) ifadesinden sonra ‘,’ konulmuştur. Çünkü virgül, iki amaç arasındaki bağlantıyı gösterir ve ‘and’ anlamındadır. mehmet_yiyebilir(Menudeki_yemek) ilişkisinin doğrulanabilmesi için, sebze(Menudeki_yemek), doktor_tavsiyeli(Menudeki_yemek) ilişkilerinin her ikisinin de doğru olması gerekir.

Örnek:

Ebeveyn ilişkisini anlatan bir Prolog gerçeği aşağıdaki gibi yazılır.

ebeveyn(omer, nejla) = Omer, Nejla’nın ebeveynidir.

Programın veritabanında babalık durumunu gösteren gerçeklerin zaten var olduğunu, yani baba(omer, nejla) gerçeğinin mevcut olduğu ve aynı zamanda annelik ilişkisini de gösteren anne(leyla, nejla) gerçeğinin de var olduğu kabul edilsin. Babalık veya annelik bağı hakkında yeterince bilgi olduğundan, ayrıca baba ve anne bilgilerini anlatmak vakit kaybına neden olur. Bunu yerine genel bir kural yazmak daha mantıklıdır. Yani,

ebeveyn(Sahis1, Sahis2):-baba(Sahis1, Sahis2).

ebeveyn(Sahis1, Sahis2):-baba(Sahis1, Sahis2).

Örnek:

Bir müşteri arabayı severse ve araba satılık ise bu arabayı satın alabilir.

Tabii dildeki bu ilişki, aşağıdaki kuralla Prolog’a aktarılabilir:

satin_alabilir(Musteri, Model):-

sahis(Musteri), araba(Model), hoslanir(Musteri, Model), satilik(Model).

Aynı kural, konuşma dilinde aşağıdaki şekilde ifade edilir.

Müşteri modeli satın alabilir :-

Müşteri bir şahıs ve

Model bir araba ve

Müşteri modelden hoşlanırsa ve

Model satılık ise.

Bu kuralın baş kısmı, gövde kısmındaki her dört şartın da doğrulanması halinde doğru olacaktır. Yukarıda yazılan gerçekler, aşağıdaki şekilde program haline getirilebilir.

PREDICATES

nondeterm satin_alabilir(symbol, symbol)

nondeterm sahis(symbol)

nondeterm araba(symbol)

hoslanir(symbol, symbol)

satilik(symbol)

CLAUSES

satin_alabilir(X,Y):-

sahis(X),

araba(Y),

hoslanir(X,Y),

satilik(Y).

sahis(ahmet).

sahis(paki).

sahis(cengiz).

sahis(levent).

araba(buick).

araba(bmw).

araba(passat).

araba(toyota).

hoslanir(paki,buick).

hoslanir(levent, toyota).

hoslanir(cengiz, passat).

hoslanir(ahmet, tenis).

satilik(pizza).

satilik(toyota).

satilik(buick).

satilik(passat).

Yukarıdaki programı yazdıktan sonra Levent ve Cengiz’in ne satın alabileceğini, kimin buick marka arabayı alabileceğini bulmak için aşağıdaki hedef cümleleri kullanılabilir:

satin_alabilir(Kim, Ne).

satin_alabilir(levent, Ne).

satin_alabilir(cengiz, Ne).

satin_alabilir(Kim, buick).

2.9. Olgular Arasındaki İlişkiler: Yüklemler (Predicates)

Bir ilişkinin sembolik ismine yüklem denir ve yükleme bağlı olan nesnelere argüman denir. Mesela sever(yasin, esra) gerçeğindeki sever ilişkisi yüklem, yasin ve esra ise bu yüklemin agrümanları olan nesnelerdir.

Argümanlı ve agrümansız yüklem örnekleri:

sahis(soyad, ad, cinsiyet). sahis yüklem; soyad, ad, cinsiyet ise bu yüklemin argümanlarıdır.

basla = argümanı olmayan yüklem

dogum_gunu(isim, soyisim, tarih). Dogum_gunu yüklem, isim, soyisim ve tarih nesneleri ise argümanlarıdır. Sınırlı olmakla beraber, bir yüklem argümansız olarak da kullanılabilir.

2.10. Değişkenler (Genel Cümleler)

Basit bir sorgulamada, sever(Kim, tenis) kuralını kullanarak kimin tenis oynamaktan hoşlandığı öğrenilebilir. Bu sorguda Kim, değişken olarak kullanılmıştır. Visual Prolog’da değişken isimlerinin daima büyük harfle veya ‘_’ ile başladığı, daha önceden söylenmişti. İlk karakteri büyük bir harf veya ‘_’ olmak şartıyla, değişkenler istenilen kadar rakam, büyük veya küçük harf alabilirler. Konu ile ilgili birkaç örnek, aşağıda verilmiştir.

Geçerli Değişkenler                                     Geçersiz Değişkenler

Prolog_ile_yazdigim_ilk_program                1.deneme

_14_10_1978_tarihinde_doganlar                14.program

_1_nolu_ogrenci                                            “prolog”

Değişken ismi seçimine dikkat etmek, programın başkaları tarafından rahat bir şekilde okunması ve anlaşılması bakımından önemlidir. sever(Kim, tenis) kuralı sever(X, tenis) kuralına tercih edilir. Çünkü Sahis X’e göre daha fazla anlamlıdır.

2.10.1. Prolog’da Değişkenlerin Değer Alması

Diğer programlama dillerinde, değişkenlerin değer almalarına imkan tanıyan atama ifadeleri Prolog’da yoktur. Prolog’u diğer programlama dillerinden ayıran en önemli özelliklerden biri de budur. Prologdaki değişkenler almaları gereken değerleri atamayla değil, gerçekler veya kurallardaki sabitlere eşleştirilirken alırlar.

Bir değişken, değer almadığı müddetçe serbest değişken olarak kalır. Fakat herhangi değer aldığı andan itibaren sınırlı hale gelir. Bu sınırlılık bir sorguya cevap almak için gerekli olan süre kadar sınırlı kalır. Bu işlem bittikten sonra değişken yeniden sınırlı hale gelir, program başa döner ve alternatif çözümler arar. Dolayısıyla bir değişkene bir değer vererek bilgi depolanamaz. Değişkenler bilgi depolamak için değil, kalıp-eşleştirme ve işlemenin bir parçası olarak kullanılır.

PREDICATES

nondeterm sever(symbol, symbol)

CLAUSES

sever(oktay, okuma).

sever(yavuz, bilgisayar).

sever(orhan, tavla).

sever(vedat, uyuma).

sever(ismail, yuzme).

sever(ismail, okuma).

Hem okuma hem de yüzmeden kimin hoşlandığı sorusuna cevap aramak için şu sorguyu kullanılır.

GOAL sever(Sahis, okuma), sever(Sahis, yuzme).

Prolog bu kuralı çözmek ve önce sever(Sahis, okuma) kısmının doğru olup olmadığını bulmak için bütün gerçekleri baştan sonra kadar inceler. Çözüm bulunmadan önce Sahis değişkeninin değeri yoktur, yani serbesttir. Öte yandan okuma kısmı bilinmektedir. İlk sever(oktay, okuma) gerçeğindeki okuma kısmı sorguya uyduğu için Sahis ‘oktay’ değerini alır. Prolog aynı zamanda aşağıya doğru nereye kadar tarama yaptığını göstermek için kuralın başıyla eşleşen ilk noktaya bir ‘pointer’ koymaktadır.

Sorgunun ilk kısmı doğrulandıktan sonra ikinci kısmının da doğrulanması gerekir. Yani yüzmeden hoşlanan kişinin de bulunması gerekir. Sahis değişkeni ‘oktay’ değeri aldığı için artık sever(oktay, yuzme) gerçeğinin doğru olup olmadığı araştırılır. Gerçekler incelenirse, ‘oktay’ isimli şahsın yüzmeden hoşlanmadığı görülür. Bu durumda Prolog Sahis değişkenine atadığı ‘oktay’ değerini etkisiz hale getirir ve Sahis yeniden serbest hale gelir. Kuralın ilk kısmını doğrulayan gerçeği bulmak için Prolog bu kez kuralların başından değil, gerçekler listesine daha önce yerleştirmiş olduğu pointer’den aşağıya kadar doğru taramaya başlar. İlk gerçek gereken şartları sağlayamadığı için artık dikkate alınmaz. Bu işleme Geriye İz Sürme denir.

Yapılan taramada okumadan hoşlanan kişinin ismail olduğu görülünce Sahis değişkeni bu kez ‘ismail’ değerini alır. Kuralın ikinci kısmının doğrulanması için tarama yapılırsa, yüzme için gereken şartın yine ‘ismail’ ile sağlandığı görülür. Dolayısıyla Prolog’un vereceği cevap şu olur:

Sahis=ismail

1 Solution

2.11. Anonim Değişkenler

Anonim değişkenler, programların gereksiz bilgi ve satırlarla karmaşık hale gelmelerini engeller. Böylece bir sorgulamadan beklenilen bilgileri alabilir ve ihtiyaç olmayan değerler iptal edilmiş olur. Prolog’da anonim değişkenler ‘_’ ile gösterilir.

Aşağıdaki örnekte anonim değişkenin kullanımı verilmiştir:

PREDICATES

erkek(symbol)

bayan(symbol)

nondeterm ebeveyn(symbol, symbol)

CLAUSES

erkek(selahattin).

erkek(cihat).

bayan(sacide).

bayan(sezen).

ebeveyn(selehattin, cihat).

ebeveyn(sacide, cihat).

ebeveyn(selehattin, sezen).

GOAL ebeveyn(Ebeveyn,_).

Diğer değişkenlerin yerine kullanılabilen anonim değişkenlerin, normal değişkenlerden tek farkları şudur: anonim değişkenler hiçbir zaman bir değere eşitlenemezler.

Yukarıdaki örnek yazdıktan sonra GOAL ebeveyn(Ebeveyn,_) sorgusu çalıştırılarak, ebeveyn olan kişilerin isimleri öğrenilebilir. Çocukların isimleri istenmediği için isimlerinin yerine anonim değişken kullanılmıştır.

Programın sonucunda şu sonuç görüntülenir:

Ebeveyn=selehattin                     /*Cihat’ın ebeveyni */

Ebeveyn=sacide                          /* Cihat’ın ebeveyni*/

Ebeveyn=selehattin                     /* Sezen’in ebeveyni*/

2 solutions

Tanımlanan değişken anonim olduğu için, alınacak cevabın ikinci argümanla bağlantısı olmayacaktır. Anonim değişkenler, gerçeklerin tanımlanmasında da kullanılabilir.

vardir(_,televizyon).

yemek_yer(_).

İfadeleri konuşma dilinde “Herkesin televizyonu var” ve “Herkes yemek yer” olarak çevrilebilir.

2.12. Hedefler (Sorgular)

Şimdiye kadar Prolog’a soru sormak anlamında kullanılan sorgulama kelimesinin yerine bu andan itibaren Hedef(Goal) kelimesi kullanılacaktır. Sorgulamaları hedef olarak tanımlamak daha anlamlıdır, çünkü Prolog’a bir sorgu yöneltmekle, ona yerine getirilmesi gereken bir hedef verilmiş olur.

Hedefler sever(ismail, yuzme) gibi basit olabileceği gibi sever(Sahis, okuma), sever(Sahis, yuzme) gibi daha karmaşık da olabilir. Birden fazla parçadan oluşan hedefe Birleşik Hedef, her bir parçaya da alt hedef denir.

2.12.1. Birleşik Hedefler: Bağlaçlar ve Ayraçlar

Birleşik bir hedefin çözümünü bulmak için her iki alt hedefin doğru olması gerekir. Bu durumda, iki alt hedef arasında (ve) anlamına gelen ‘,’ kullanılır. Fakat istenilen durumlarda alt hedeflerden sadece birinin doğru olması şartı da aranabilir. Bu durumda alt hedefler arasında (veya) anlamına gelen ‘;’ kullanılması gerekir. Bu duruma Ayırma işlemi denilmektedir.

Şimdi bu durumu gösteren bir örnek inceleyelim:

PREDICATES

nondeterm araba(symbol,long,integer,symbol,long)

nondeterm kamyon(symbol,long,integer,symbol,long)

nondeterm arac(symbol,long,integer,symbol,long)

CLAUSES

araba(chrysler,130000,3,kirmizi,12000).

araba(ford,90000,4,gri,25000).

araba(datsun,8000,1,kirmizi,30000).

kamyon(ford,80000,6,mavi,8000).

kamyon(datsun,50000,5,sari,20000).

kamyon(toyota,25000,2,siyah,25000).

arac(Marka,Kilometresi,Yas,Renk,Fiyat):-

araba(Marka,Kilometresi,Yas,Renk,Fiyat);

kamyon(Marka,Kilometresi,Yas,Renk,Fiyat).

GOAL araba(Marka, Kilometresi, Kullanim_Suresi, Renk, 25000).

Bu örnekteki hedef, cümleciklerde tarif edilen 25000 dolarlık arabayı bulur. Benzer şekilde; fiyatı 25.000 dolardan daha az olan bir araba var mı? şeklindeki bir soruya cevap bulmak da mümkündür. Bunun için araba(Marka, Kilometresi, Kullanim_Suresi, Renk, Fiyat), Fiyat< 25000 şeklindeki bir sorguyla bu sorunun cevabını bulmak mümkündür. Bu kuralı sorgulandığında, alınacak cevap chrysler olacaktır.

Şimdi ‘fiyatı 25.000 dolardan az olan bir araba veya fiyatı 20.000 dolardan daha az olan bir kamyon var mıdır?’ şeklindeki bir soruya uygun bir hedef yazalım:

araba(Marka, Kilometresi, Kullanim_Suresi, Renk, Fiyat), Fiyat< 25000; kamyon (Marka, Kilometresi, Kullanim_Suresi, Renk, Fiyat), Fiyat< 20000.

Prolog ilk önce fiyatı 25.000 dolardan daha az olan bir araba olup olmadığını araştırır. Sonuç doğru olsun veya olmasın, ikinci alt hedef de araştırılır. Her ikisinden birinin doğru olması durumunda alınacak cevap olumlu olacaktır. Hedefin doğrulanması için birden fazla alt hedefin aynı anda doğru olması gerekmez. Bu tür hedeflere ayrıştırma denilmektedir ve bunun için alt hedefler arasında ‘;’ ayracı kullanılmaktadır.

2.13. Açıklama Satırları

Program yazarken program satırları arasına açıklamalar yazmak, başkalarının da programı okuyup anlamasına imkan tanır. Program içerisine yazılan bu yorum satırları derleyici tarafından dikkate alınmaz. Prolog’da yorum satırları bir kaç satırdan oluşacaksa ‘/*’ ile başlamalı ve ‘*/’ ile bitmelidir. Eğer tek bir satır yorum yazılacaksa ‘%’ işareti kullanılabilir.

/* Program yazarken kullanılan değişkenler, yüklem ve kurallar*/

/*hakkında bilgi vermek için bu tür yorum satırları yazılabilir*/

%Tek satırlık yoruma bir örnek.

/* İç içe /* yorum */ satırı yazmak da mümkündür*/

2.14. Eşleştirme

Prolog’da eşleştirme yapılırken eşlenik yapılar birbiriyle eşleşebilir. ebeveyn(selehattin, X), ebeveyn(sacide, cihat) kuralındaki X değişkeni ‘cihat’ değerini alır ve serbest olan bu değişken artık bağlı hale gelir. Bağlı hale gelen başka bir değişkene atanırsa, diğer değişken de aynı değeri alır.

2.15. Bölüm özeti

1.   Prolog’da bir program gerçekler ve kurallardan oluşan cümleciklerden oluşur.

·      Gerçekler, doğru oldukları kabul edilen ilişkiler ve özelliklerdir.

·      Kurallar bağımlı ilişkiler olup, gerçekler ve ilişkileri kullanarak bilgi elde etmeye yararlar.

2. Gerçeklerin genel yazılış biçimi şöyledir:

ozellik(nesne1, nesne2,….. nesneN)

veya

ilişki(nesne1, nesne2,….. nesneN)

Burada özellik nesnelerin herhangi bir özelliği, ilişki ise nesneler arasındaki herhangi bir ilişkidir. Özellik ve ilişki kelimelerinin her ikisi de Prolog’da aynı anlamda kullanılır.

3.   Bir programda verilen bir ilişki bir veya daha fazla nesne arasındaki ilişkiden ibarettir. sevmek(ahmet, futbol) gerçeğindeki ‘sevmek’ bir ilişkiyi, ahmet ve futbol ise bu ilişkinin nesnelerini temsil eder. solak(hasan) gerçeğinde ‘solak’ bir özelik, hasan ise bir nesnedir.

4.   Kuralların genel yazılma şekli:

Baş:-Gövde

olup, daha açık hali aşağıdaki gibidir.

ilişki(nesne, nesne, ….., nesne) :-

ilişki(nesne, nesne, …, nesne),

 .

 .

ilişki(nesne, nesne, …., nesne).

5.   İlişki ve nesne isimlerinin yazılması bazı kurallara bağlıdır. Nesne ve ilişki isimleri daima küçük harfle başlar. Bunu takiben istenilen sayıda büyük-küçük harf, rakam, ‘_’ kullanılabilir.

6.   Değişken isimleri daima büyük bir harf veya ‘_’ ile başlar. Bunu takiben istenildiği kadar küçük_büyük harf, rakam vs. kullanılabilir. Değişkenler bir değer almadan önce serbest, değer aldıktan sonra ise bağlı hale gelirler. Bir değişkene değer atayıp bilgi depolamak mümkün değildir. Çünkü bir değişken sadece bir cümlecikte bağımlıdır.

7.   Bir sorgudan sadece belirli bir bilgi alınmak isteniyorsa, anonim değişken (_) kullanılabilir. Anonim değişkene hiçbir zaman değer atanması yapılamaz.

8.   Prolog’a programda verilen gerçeklere göre bir soru sormak Prolog Sistemini Sorgulama olarak adlandırılır ve bu sorguya Hedef denir.

Bileşik bir hedef iki veya daha fazla hedeften oluşur. Bu parçaların her birine alt hedef adı verilir. Bileşik hedefler Bağlaç veya Ayraç şeklinde olabilir.

10. Eşleştirme birbirine denk yapılar arasında gerçekleştirilir. Serbest bir değişken bir sabite veya önceden değer alıp bağımlı hale gelmiş başka bir değişkene atanabilir. Serbest olan iki değişken birbirine atanırsa, birinin alacağı değer otomatik olarak diğerine atanmış olur.


3. VISUAL PROLOG PROGRAMLARININ TEMEL BÖLÜMLERİ

Bir VIP Programı genelde şu dört bölümden oluşur: Clauses (Gerçekler ve Kurallar), Predicates (Yüklemler), Domains (Değişken Tipleri) ve Goals(Hedefler).

3.1. Clauses(Olgular veya Kurallar)

Bu bölüm bir programın kalbi durumundadır. Çünkü programda tanımlı hedefler doğrulanmaya çalışılırken, doğruluğu daha önceden bilinen gerçeklerden yola çıkılır. Gerçek ve gerçekler arasındaki ilişkileri tanımlayan kuralların tanımlandığı yer bu bölümdür. Bir yüklem için tanımlanması gereken bütün clauselar kümesine Procedure denir.

3.2. Predicates (Yüklemler)

Yüklemlerin ve yüklemlerdeki argümanların tiplerinin tanımlandığı yer bu bölümdür. Visual Prolog’da mevcut olan hazır yüklemlerin tanımlanması gerekmez.

3.3. Domains (Değişken Tipleri)

Burada, Visual Prolog’da olmayan tiplerin tanımlanması yapılır.

3.4. Goal (Hedef)

Programdaki sorgular buraya yazılır.

3.5. Yüklem Tanımı

Bir yüklemin genel yazılış biçimi şöyledir:

yuklem_adi(argüman_tip1, argüman_tip2, argüman_tip3,…., argüman_tipN)

Yüklemlerin bitiş parantezinin clauses bölümündeki gibi ‘.’ ile sonlanmadığına dikkat edilmelidir. Yüklem isimleri en fazla 250 karakterten oluşabilir ve herhangi bir harfle başlayabilir. Yüklemler için isim seçilirken küçük veya büyük harfle başlamak önemli değildir. Fakat küçük bir harfle başlayan bir isim seçilmesi önerilir. Çünkü Prolog derleyicilerin çoğu ancak küçük harfle başlayan yüklem isimlerini kabul etmektedir. Kullanılabilecek karakterler şunlardır:

Büyük harfler: A, B, ………., Z

Küçük harfler: a, b, …………, z.

Rakamlar: 0, 1, ………………, 9

Alt tire: _.

Geçerli Yüklem İsimleri                                    Geçersiz Yüklem İsimleri

Olgu                                                                  [olgu]

Oynar                                                                *gider*

sahip_olunan_servet                                         Sahiptir/araba

tahakkuk_fisi                                                    bu-ayin-bordrosu

10_kisilik_sinif                                                 <10-kisiden_biri

 

Örnekler:

domains

isim=symbol

numara=integer

predicates

ilk_yuklem(isim, numara)

domains

sahis, eylem=symbol

araba, marka, renk=symbol

kilometresi, kullanim_yili, fiyat=integer

predicates

sever(sahis, eylem)

ebeveyn(sahis, sahis)

satin_alabilir(sahis, araba)

araba(marka, kilometresi, kullanim_suresi, renk, fiyat)

yesil(symbol)

derece(symbol, integer)

Yukarıdaki program parçasında yüklem ve argümanların anlamları aşağıda verilmiştir.

·        sever yüklemi iki argüman alır: sahis ve eylem. Bu argümanların her ikisi de değer olarak symbol, yani alfabetik karakterler alabilir.

·        ebeveyn yükleminin iki argümanı da sahis olup, domainde tanımladığı şekliyle symbol tipindedir.

·        satin_alabilir yüklemi tipi symbol olan sahis ve araba argümanlarını almıştır.

·        araba yüklemi 5 adet argüman almıştır. İlk ikisinin tipi symbol, son üçünün ise integer’dır (tamsayı).

·        yesil yüklemi, tipi symbol olan tek bir argüman almıştır. Symbol tipi zaten Visal Prolog’un standart tipleri arasında yer aldığından, ayrıca tanımlamaya gerek yoktur.

·        derece yükleminin argümanları da standart domain’de yer almaktadır.

3.6. Domains (Tip tanımları) Bölümü

Domain kısmında argümanların tipleri tanımlanır. Bir argüman alfabetik, nümerik veya her ikisinden oluşan karakterleri değer olarak alabilir. Domain kısmı, birbirinin aynısı gibi görünebilecek verilere farklı isimler vermemize imkan tanır. VIP programlarında ilişki veya gerçeklerde tanımlanmış olan nesneler (yüklemdeki argümanlar) domainlere aittir. Bu tipler standart olarak tanımlı olabileceği gibi, kullanıcı tarafından sonradan da tanımlanabilir.

Domain kısmı son derece faydalı iki görev icra eder. Birincisi, yüklemlerde tanımlanan argümanların tipleri VIP’de standart olarak tanımlamış olan symbol, tamsayı vs. domainleri olsalar bile, argümanlara farklı anlamlı isimler vermemize imkan tanır. İkincisi, standart domainler tarafından tanımlanmamış veri yapılarını tanımlanmasına imkan sağlar.

Ayrıca, yüklemdeki argümanların net olarak anlatılabilmesi için farklı domainler olarak tanımlanması da faydalıdır.

Örnekler:

1.   Aşağıdaki tabii dil cümlesinin VIP’de karşılığını yazıp, özel domain tanımı aşağıdaki şekilde yapılır.

Hasan, 28 yaşında bir erkektir.

Eğer özel olarak domain tanımlanmazsa, yani VIP’deki standart tipler kullanılırsa yukarıdaki cümle şöyle yazılabilir:

sahis(symbol, symbol, integer)

Bu yüklem ve argümanlar doğru biçimde tanımlandığı için çalışır. Fakat sahis yüklemi içinde tanımlanan üç argümanın neye işaret ettiğini hatırlamak zor olabilir.

Bunun yerine:

domains

isim, cinsiyet        = symbol

yas                                   = integer

predicates

sahis(isim, cinsiyet, yas)

şeklinde üç ayrı domain tanımlanırsa sahis argümanındaki isim, cinsiyet ve yas argümanlarının anlamı her zaman için barizdir. Bu tanımlamanın bir faydası da argüman tipleri arasında olabilecek tip eşleştirme hatalarını önlemektir.

Özel domainler, argümanların anlamını çok daha iyi ifade ettikleri halde, bütün argümanlar için özel domain kullanmak gerekmez. Bir argüman için belli bir tip tanımlanması yapıldıktan sonra, bu argüman, tipi aynı olan bir başka argümanla hiçbir şekilde karıştırılmaz. Örneğin isim ve cinsiyet argümanlarının her ikisinin de tipi symbol olmasına rağmen birbiriyle karıştırılmazlar. Fakat kullanıcının tanımladığı argümanların hepsi önceden tanımlanmış argümanlarla karıştırılabilir.

Aşağıdaki örnek, çalıştırıldığı zaman bir tip hatası verir.

DOMAINS

carpma, toplam = integer

PREDICATES

toplama_yap(toplam, toplam, toplam)

carpma_yap(carpma, carpma, carpma)

CLAUSES

toplama_yap(X, Y, Toplam):-

Toplam=X+Y.

carpma_yap(X, Y, Carpma):-

Carpma=X*Y.

GOAL toplama_yap(32, 54, Toplam).

Buradaki GOAL toplama_yap(32, 54, Toplam) doğru çalışır ve

Toplam=86

1 Solution

cevabı alınır. Carpma_yap fonksiyonu için 35 ve 25 değerlerleri kullanılırsa,

Carpma=875

1 Solution

sonucu alnır.

31 ve 17 sayılarının çarpımını bulup, elde edilen sayıyı kendisiyle toplayıp Cevap argümanının değeri aşağıdaki şekilde bulunur.

carpma_yap(31, 17, Toplam), toplama_yap(Toplam, Toplam, Cevap) şeklinde bir hedef yazılabilir. Bu hedefe göre, bulunacak sonucun

Toplam=527 (31*17), Cevap=1054 (527+527)

olması gerekirken, VIP derleyici bir hata mesajı verir. Çünkü carpma_yap fonksiyonundaki Toplam argümanı 527 değerini aldıktan sonra bu değeri ikinci yüklem olan toplama_yap’taki ilk iki argümana taşımaya çalışır. Her iki argüman da tamsayı tipinde olmasına rağmen farklı isimlerde olduklarından, birbirleriyle eşleştirilemezler ve neticede hata mesajı görüntülenir. Bu yüzden bir cümledeki fonksiyonda tanımlanan değişken birden fazla fonksiyonda kullanılacaksa, her fonksiyonda aynı şekilde tanımlanmalıdır.

Örnek:

DOMAINS

marka, renk = symbol

yas=byte

fiyat, yol=ulong

PREDICATES

nondeterm araba(marka, yol, yas, renk, fiyat)

CLAUSES

araba(chrysler,130000,3,kirmizi,12000).

araba(ford,90000,4,gri,25000).

araba(datsun,8000,1,siyah,30000).

GOAL araba(renault, 13, 40000, kirmizi,12000).

GOAL araba(ford, 90000, gri, 4, 25000).

GOAL araba(1, kirmizi, 30000, 80000, datsun).

Burada araba yükleminin 5 argümanı mevcuttur. Yas argümanı byte tipinde olduğu için alabileceği değer 8 bitlik ve 0-255 arasında değişen pozitif bir sayıdır. Aynı şekilde yol ve fiyat tipleri ulong (uzun tamsayı) olup 32-bit pozitif tamsayı değerleri alır. Son olarak marka ve renk tipleri symbol tipindedir. Yukarıdaki sorguları tek tek deneyince her birinin ayrı bir tip hatasına neden olduğu görülecektir. GOAL araba(renault, 13, 40000, kirmizi, 12000) sorgusunda byte tipinde olması gereken yas argümanı 40000 değerini almıştır. Bunun 0-255 arasında olması gerekir. İkinci sorguda yas ve renk argümanlarının değerleri yer değiştirmiştir. Bu nedenle yine hataya neden olur.

3.7. Goal Bölümü

Goal bölümünün bir kuralın yapısından sadece iki farkı vardır.

1.   Goal kelimesinden sonra ‘if’ anlamındaki ‘:-‘ operatörü kullanılamaz.

2.   Program çalışırken VIP ilk önce GOAL satırını çalıştırır.

3.8. Deklarasyon ve Kurallara Ayrıntılı Bakış

Bir yüklemdeki argümanların tiplerini tanımlarken, VIP’de hazır bulunan standart tipler kullanılabilir. Bu tiplerin domains kısmında, ayrıca tanımlanması gerekmez. Aşağıdaki tabloda hazır olarak bulunan tipler verilmiştir (Tablo 1).

 

Tablo 3.1: Visual Prolog’da Tipler ve Alabilecekleri değerler.

 

Tip

Kullanıldığı Yer

 

Değer Aralığı

short

Bütün Platformlar

16 Bit

-32768….+32767

Ushort

Bütün Platformlar

16 Bit

0…65535

Long

Bütün platformlar

32 bit

-2147483648………+2147483647

Ulong

Bütün platformlar

32 bit

0…4294967295

İnteger (Bilgisayar ve Mimariye bağlı olarak – veya + değer alabilir)

16 Bit Platformlar

32 Bit platformlar

16 Bit

32 Bit

-32768….+32767

-2147483648……..+2147483647

Unsigned (Bilgisayar ve mimariye bağlı olarak -/+ değer alabilir)

16 Bit Platformlar

32 Bit platformlar

16 Bit

32 Bit

0…65535

0…4294967295

byte

Bütün platformlar

8 bit

0-255

Word

Bütün platformlar

16 bit

0…65535

Dword

Bütün platformlar

32 bit

0…4294967295

Her değişken tipi verilen aralıkta bulunan bir değeri alabilir. Integer ve unsigned tipleri, değişkenlerin tanımlandığı bilgisayar veya sistemlere göre değişen aralıktaki değerleri alırlar.

Domain tanımı yapılırken signed veya unsigned kelimeleri byte, word ve dword domainleri ile birlikte kullanılabilirler.

Domains

i8 = signed byte

tanımı normalde unsigned olan ve bu yüzden 0-255 aralığından değer alan byte yerine -128…+127 değerleri arasında değer alan bir tip haline gelir.

3.8.1. Char

İşaretsiz bir byte olarak kullanılır. Örnek: ‘A’, ‘b’…

3.8.2. Real

+/- DDDD.DDDD şeklinde olan 8 bitlik bir değişken. (1*10-307-1*10+308)

3.8.3. String

255 karakter uzunluğunda olabilen bu tipin iki formatı vardır.

a)   İlki küçük harf olmak üzere harf, sayı veya altçizgiden oluşur.

b)  Çift tırnak arasına alınmış karakterlerden oluşur. Örnek

Örnekler: Adı_soyadı, “Müşterinin Adı”, “Fox Ltd.”

3.8.4. Symbol

Formatı string’ler ile aynıdır.

Symbol ve string değişkenler birbirinin aynısı olmakla beraber, VIP bunları farklı şekillerde depolar. Symbol tipleri bir tabloda saklanır. Adresleri ise nesneleri temsil edecek şekilde saklanır. Böylece eşleştirme işleminde hızlı kullanılırlar. Fakat karşılaştırmalarda String tipler karakter bazında eşleştirilir.

3.9. Yüklemlerdeki Argümanların Yazılması

Predicates bölümündeki bir argümanın tipini tanımlamaya, argüman tipi tanımlama denilmektedir.

Hasan, 28 yaşında olan bir erkektir = sahis(hasan, erkek, 28).

Sahis bu argümanlarla birlikte kullanan bir yüklem olarak tanımlamak için aşağıdaki satırın predicates bölümünde yazılması gerekir.

sahis(symbol, symbol, unsigned)

Görüldüğü gibi her üç argüman da standart tipte tanımlanmıştır. Yani, program içerisinde her ne zaman sahis yüklemi geçerse, bu yüklemi sadece 3 argümanla birlikte kullanılabilir. Bunların ilk ikisi symbol, üçüncüsü ise unsigned tipinde bir integer olmalıdır.

Alfabedeki bir harfin yerini belirleyen alfabedeki_yer(Harf, Yer) şeklinde bir ilişkiyi incelendiğinde, Harf ve Yer argümanlarının her ikisi de değişken olarak tanımlandığı görülür. Böylece Harf=a ise Yer=1, Harf=b ise Yer=2 vs. şeklinde devam eder. Bu durum kısaca şöyle ifade edilebilir.

alfabedeki_yer(Bir_harf, N).

Bunun için yazılması gereken olgular:

alfabedeki_yer(‘a’, 1).

alfabedeki_yer(‘b’, 2).

alfabedeki_yer(‘c’, 3).

………..

alfabedeki_yer(‘z’, 29.)

şeklinde olmalıdır.

PREDICATES

alfabedeki_yer(char, integer)

CLAUSES

alfabedeki_yer(‘a’, 1).

alfabedeki_yer(‘b’, 2).

alfabedeki_yer(‘c’, 3).

GOAL alfabedeki_yer(‘c’, Nerede).

Program çalıştırıldığında ‘c’ harfinin yerini veren Nerede değişkeni 3 değerini alır.

Örnek:

DOMAINS

adi_soyadi, tel_no = symbol

PREDICATES

nondeterm telefon_numarasi(adi_soyadi, tel_no)

CLAUSES

telefon_numarasi(“Orhan AYDIN”, “255 45 47”).

telefon_numarasi(“Arif GÜREL”, “3134578”).

telefon_numarasi(“Husamettin BULUT”, “3145869”).

telefon_numarasi(“Kasim YENIGÜN”, “3174152”).

Bu program, aşağıdaki sorgularla veya yenileri ilave edilerek çalıştırılabilir.

GOAL telefon_numarasi(Kimin_Telefonu, “3145869”).

GOAL telefon_numarasi(“Orhan AYDIN”, Telefon_Numarasi).

GOAL telefon_numarasi(Telefon_Sahibinin_Adi, Telefon_Numarasi).

Örnek: Ekrandan girilen bir karakterin harf olup olmadığını kontrol eden bir program yazınız. (Not: char tipi sadece bir tek karakteri tanımlar)

REDICATES

nondeterm aranan_harf(char)

CLAUSES

aranan_harf(Harf):-

‘a’<=Harf,

Harf<=’z’.

aranan_harf(Harf):-

‘A’<=Harf,

Harf<=’Z’.

GOAL

aranan_harf(‘x’).

aranan_harf(‘2’).

aranan_harf(“Merhaba”).

aranan_harf(‘a’).

aranan_harf(x).

Yukarıdaki program, verilen bir karakterin alfabenin bir harfi olup olmadığını test etmektedir. Yazılan sorguları kullanarak elde edilen sonuçları inceleyiniz. Bazı şıklarda neden hata verdiğini bulmaya çalışınız.

Predicate bölümünde aynı isimde birden fazla yüklem tanımlanabilir. Fakat bunların argümanlarının farklı sayıda olması gerekir. Predicates ve Clauses bölümlerinde aynı isimde olanların birlikte gruplanmaları gerekir. Bu yüklemler, tamamen farklıymış gibi işlem görürler.

Örnek:

DOMAINS

sahis=symbol

PREDICATES

baba(sahis) %Buradaki şahıs bir babadır.

baba(sahis, sahis) %Buradaki birinci kişi ikinci kişinin babasıdır.

CLAUSES

baba(Insan):-,

baba(Insan, _).

baba(ahmet, mehmet).

baba(omer, yavuz).

3.10. Kuralların Yazım Biçimi

VIP’de kurallar, Baş ve Gövde olmak üzere iki kısımdan meydana gelir.

Genel Biçim:

Baş:- <alt hedef1>, <alt hedef2>,……, <alt hedefN>.

Alt hedefler biribirinden ‘,’ ile ayrılır ve sonuncusu nokta ile biter. Alt hedeflerin her biri ayrı bir yüklem çağırır. Alt hedefin doğru olup olmadığı kontrol edilir. Sonuç ne olursa olsun, bu işlem bütün alt hedeflere uygulanır. Alt hedeflerin tamamının olumlu netice vermesiyle beraber o kuralın doğruluğu ispatlanmış olur. Sadece bir alt hedef bile yanlış olursa, bütün kural yanlış olur.

3.11. Prolog ve Diğer Dillerdeki ‘if’ Komutunun Karşılaştırılması

VIP’de baş ve gövde kısmını ayıran ‘:-‘ sembolü if anlamına gelir. Örneğin Pascal’daki if komutu, öncelikle if komutundan sonra gelen ifadenin doğru olup olmadığını kontrol eder. Eğer ifade doğrulanırsa, komut then ifadesinden sonraya geçer geçer.

Yani if x>10 then writeln(“Bu işlem tamam”);

satırında öncelikle x değişkeninin 10’dan büyük olup olmadığı kontrol edilir. Eğer sonuç doğru ise ‘Bu işlem tamam’ satırı görüntülenir. Aksi takdirde program bir alt satırdan itibaren çalışmaya devam eder. Bu tip ifadeye if/then şartlı denir. VIP ise bunun tam tersi olan bir sistem uygular. Öncelikle gövdedeki alt hedeflerin doğru olup olmadığına bakılır. Tamamı olumlu sonuç verirse, kuralın gövde kısmının doğruluğu ispatlanmış olur. Bu ise VIP’da then/if şartının geçerli olduğunu gösterir.

3.12. Otomatik Tip Dönüştürmeler

VIP’de iki değişken karşılaştırıldığında her ikisinin de aynı tipte olması her zaman gerekmez. Değişkenler bazen başka tiplerdeki sabit değişkenlere de atanabilir. Çünkü VIP aşağıdaki tipler arasında otomatik olarak tip dönüştürmesini yapar.

· string ve symbol

· Bütün integral tipler ve reel değişkenler. Bir karakter sayısal bir değere dönüştürülürken, bu karakterin karşılığı, sayının ASCII tablosundaki karşılığı olur.

Örneğin string tipindeki bir agüman symbol tipi ile uyumludur. Benzer şekilde integer olarak tanımlı bir tip real, char, word etc. Tipleriyle uyumludur. Bu tür tip değişikliği şu kolaylıkları sağlar:

·      string tipiyle tanımlı bir yüklem symbol tipindeki bir argümanla çağrılabilir.

·      real tipiyle tanımlı bir yüklem integer tipindeki bir argümanla çağrılabilir.

·      char tipiyle tanımlı bir yüklem integer tipindeki bir argümanla çağrılabilir.

·      Alfabetik karakterler ASCII değerleri bilinmeden de rahatlıkla kullanılabilir.

Argümanlar, tanımlı olduklarının dışında bir tipe dönüşürken ne gibi kuralların etkili olduğu, sonuçta ortaya çıkan argümanının hangi tipte olacağı konusu ileride incelenecektir.

3.13. Bir Programın Diğer Bölümleri

Şimdiye kadar VIP’daki clauses, predicates, domains ve goals bölümleri incelenmiş ve bol miktarda örnek verilmiştir. Şimdi database, constants ve global bölümlerine kısa bir giriş yapılacaktır.

3.13.1. Database Bölümü

Bir VIP programının gerçekler ve kurallardan oluştuğu bilinmektedir. Program çalışırken bazen kullanılan gerçek ve kuralları değiştirmek, güncellemek, ilave yapmak veya çıkarmak gerekebilir. Böyle bir durumda gerçekler, dinamik bir dahili veritabanı oluşturur. Program çalışırken değiştirilebilecek gerçeklerin tanımlı olduğu bölüme database bölümü denilmektedir.

3.13.2. Constants Bölümü

Diğer dillerde olduğu gibi VIP’de de sabit değişkenler kullanılabilir. Bu değişkenler constants bölümünde tanımlanır. Her bir satıra sadece tek bir sabit yazılabilir.

constants

yuz=(10*(10-1)+10)

pi=3.14159265

maas_katsayisi=4

mavi=5

Program derlenmeden önce her sabit değişkenin karşısındaki string olduğu gibi atanır. Örnek:

A=yuz*34, bekle(A)

şeklindeki A değişkenine yuz sabiti yerine 100 değil, yuz sabit değişkeninde tanımlı şekliyle (10*(10-1)+10) değeri atanır.

Sembolik sabitlerin yazımında şu kurallar geçerlidir:

· Sabit bir değişken kendisini çağıramaz. Yani sayi= 2*sayi/2 yanlıştır.

· Büyük veya küçük harfle başlayan sabit değişkenler, farklı olarak işlem görmezler. Bu yüzden büyük harfle başlayan sabit bir değişken clause veya goal bölümünde küçük harfle başlatılmalıdır. Böylece büyük harfle başlamaları zorunlu olan normal değişkenlerle karışmazlar. Örnek:

constants

iki=2

goal A=iki, write(A).

·      Bir programda birden fazla constants bölümü olabilir. Fakat programda kullanılmadan önce bu değişkenlerin mutlaka tanımlanmış olmaları gerekir.

·      Tanımlanan sabitler tanımlanan noktadan başlayıp programın sonuna kadar aynı değerde kalırlar. Bir sabit değişken sadece bir kez tanımlanabilir.

3.13.3. Global Bölümü

VIP’de şimdiye kadar tanımladığımız domains, predicates ve clauses bölümleri tamamen lokal idi. Bunları global yapmak için programın en başında global domains, global predicates vs. bölümler oluşturulabilir. Bu konu daha sonra incelenecektir.

3.14. Derleyici Direktifleri

VIP, yazılan bir program parçasının derleme sırasında belirtilen şekilde işlem görmesi için bazı direktiflerin kullanılmasına imkan tanır. Bu seçenekler menüdeki Options/Compiler Directives başlığından ayarlanabilir.

3.14.1. Include Direktifi

Bu direktif daha önce yazılan bir program parçasının veya prosedürün her çağrıldığında aynı program içerisinde tekrar tekrar kullanılmasını sağlar. Bu durum basit bir örnek üzerinde açıklanmaktadır.

İçinde en sık kullanılan tip ve yüklemlerin bulunduğu TEST.PRO isminde bir programın olduğunu varsayalım. Hazırlanan başka bir programda bu program çağırılıp kullanılmak istendiğinde, kullanılan

include “test.pro”

bir derleyici direktifidir. Ana program derlendiği zaman VIP test.pro isimli programı derleyip ana programa ilave eder. Include direktifiyle tanımlanan bir programda da başka bir include satırı bulunabilir ve o da başka bir programı çağırabilir. Fakat bir programda bir dosya sadece bir kez include “dosyaismi.pro” şeklinde kullanılabilir.

3.15. Bölüm Özeti

1.   Bir VIP programının yapısı şu şekildedir:

domains

argüman1,…,argümanN=tip

predicates

yüklem_ismi(argüman1,…, argümanN)

clauses

kurallar ve gerçekler

GOAL

alt_hedef1, alt_hedef2, …….., alt_hedefN

2.   Domains bölümünde kullanılacak değişkenlerin tipleri tanımlanır. VIP’da kullanılabilecek bazı tipler: char, byte, short, ushort, word, integer vs.

3.   Yazılmış olan gerçek ve kuralları inceleyerek doğruluğunun sağlanması istenilen Goal (sorgu), programın içine yazılması gerekir. Bu dahili bir sorgudur. Harici olarak tanımlanacak olan bir sorgu program çalışırken açılan Dialog penceresine yazılır.

4.   Aynı isimde fakat farklı sayıda argüman taşıyan yüklemler tamamen farklı yüklemlermiş gibi işlem görür.

5.   Kurallar Baş:- alt_hedef1, alt_hedef2, ………, alt_hedefN genel şekliyle yazılır. Bir kuralın istenilen sonucu vermesi için alt hedeflerin tamamının doğrulanması gerekir.

6.   Prolog’daki if komutu diğer dillerdeki if komutundan farklıdır. Prolog’da then/if şeklinde tanımlı olan bu komut diğer dillerde if/then şeklinde tanımlıdır.


4. EŞLEŞTİRME VE GERİYE İZ SÜRME

VIP bir alt hedeften gelen bir çağrıyı clauses bölümünde tanımlı bir cümle ile karşılaştırmaya çalışırken belirli bir işlem kullanır. Bu işleme eşleştirme denir. Bir program çalışırken

Goal yazdi(X,Y).

sorgusunun kullanıldığını kabul edilsin. Bu sorgunun doğruluğunu araştırırken, clauses bölümdeki bütün yazdi(X,Y) cümlecikleri eşleştirme işlemi için test edilir. Goal yazdi(X,Y) ifadesindeki X ve Y argümanları, clauses bölümündeki yazdi(…) cümlecikleriden kontrol edilir. Bunun için bütün cümlecikler tek tek incelenir. Sorguyla eşleşen bir cümle bulunduğu zaman cümledeki değer serbest olan değişkene atanır ve böylece cümle ile goal eşleşmiş olur. Bu duruma ‘sorgunun cümle ile eşleşmesi’, bu işleme de eşleştirme denilir.

Örnek

DOMAINS

kitap_adi, yazar = symbol

sayfa_sayisi       = unsigned

PREDICATES

kitap(kitap_adi, sayfa_sayisi)

nondeterm yazdi(yazar, kitap_adi)

nondeterm roman(kitap_adi)

CLAUSES

yazdi(eco, “Gülün Adı”).

yazdi(tolstoy, “İnsan Ne İle Yaşar”).

kitap(“İnsan Ne İle Yaşar “, 245).

kitap(“Gülün Adı”, 760).

roman(Kitap_adi):- yazdi(_, Kitap_adi), kitap(Kitap_adi, Sayfa_sayisi), Sayfa_sayisi> 400.

GOAL yazdi(Yazar, Kitap_adi).

Sorgudaki Yazar ve Kitap_adi değişkenleri serbest değişkenler olduklarından herhangi bir argümana eşitlenebilirler. Dolayısıyla sorgu clauses bölümündeki ilk yazdi cümlesi ile eşleşir. Yani yazdi(Yazar, Kitap_adi) cümleciği yazdi(eco, “Gülün Adı”) olur. Burada Yazar=eco, Kitap_adi=Gülün Adı değerini alır. Aynı işlem bütün alternatif çözümler için tekrar edileceğinden, Yazar ve Kitap_adi değişkenleri sırasıyla tolstoy ve İnsan Ne İle Yaşar değerlerini de alır. Yani sonuçta 2 çözüm bulunur.

GOAL roman(Roman_adi) çağrısının nasıl çalıştığı incelenecektir. Bir çağrının bir olgu veya kuralın baş kısmıyla eşleşip eşleşmediği kontrol edilir. Yani kuralın baş kısmı olan roman(Kitap_adi) kısmıyla eşleşir. Kullanılan olgudaki argümanlar eşleştirilir. X argümanı bağlı olmadığı için herhangi bir argümanla eşleşebilir. Kuralın başı olan roman(Kitap_adi)’ında, Kitap_adi argümanı bağımsız bir değişkendir. Kuralın başıyla sorgu kısmı eşleştirilir. VIP, eşleştirme yapıldıktan sonra alt hedefleri sırasıyla doğrulamaya çalışır.

roman(Kitap_adi):-

yazdi(_, Kitap_adi),

kitap(Kitap_adi, Sayfa),

Sayfa>400.

GOAL roman(Roman_adi) kodunda ilk önce yazdi(_,Kitap_adi) kısmı sorgulanır. Buradaki ilk argüman anonimdir. Dolayısıyla ilk olgudaki eco ve Gülün Adı ‘_’ ve ‘Kitap_adi’ argümanlarıyla eşleşir. Bundan sonra kitap(Kitap_adi,Sayfa_sayisi) cümleciğindeki kitap olgusuna çağrı yapılır. İlk cümlecikteki ‘eco’ ve ‘Gülün Adı’ değerlerini alır. İlk alt hedef doğrulandığı için sonraki adım olarak kitap(Kitap_adi, Sayfa_sayisi) alt hedefine geçilir. Kitap_adi argümanı ‘Gülün Adı’ değerine bağlı hale geldiği için çağrı kitap(“Gülün Adı’, Sayfa_sayisi) şeklinde devam eder. Programın başından başlayan sorgu kitap(“Gülün Adı”, 760) cümleciğinde eşleştirme yapmaz. Çünkü ilk argüman ‘Gülün Adı’ olmuştu. İkinci cümlecik sorguyu doğrular ve Sayfa_sayisi 760 değerini alır. Sayfa_sayisi>400 alt hedef halini alır. 760 değeri 400’den büyük olduğu için alt hedef doğrulanır ve böylece bütün hedef doğrulanmış olur. Sonuçta şu mesaj görüntülenir:

Roman_adi=Gülün Adı

1 Solution

4.1. Geriye İz Sürme

Gerçek problemlere çözüm ararken, verilen karar doğrultusunda mantıklı olan bir yol takip eder, yolun sonuca ulaşmaması durumunda alternatif bir yol aranır. Mesela bir labirent oyununda çıkış yolunu ararken sola veya sağa doğru gidilir. Çıkmaz sokağa gelindiğinde geriye döner, başka bir yolu takip eder. Bu yönteme göre devam edilirse, sonunda çıkış noktası bulunur.

VP, geriye iz sürme denilen bu sistemi kullanır. Bir sorgunun doğru olup olmadığı araştırılırken alt hedeflerin herbirinin ayrı ayrı doğrulanmaya çalışılır. VP, doğrulama işlemini yürütürken sorgulanması gereken durumların başlangıç noktasına bir işaret koyar. Sonra bu yolların ilkini dener. Eğer olumlu sonuç alınırsa işleme oradan itibaren devam eder. Sonucun olumsuz çıkması durumunda, işaret konulan yere döner ve ikinci yolu, yani bir sonraki alt hedefi dener. İşte bu ileriye gidiş ve gerektiğinde yine geriye dönüş işlemine Geriye İz Sürme denir.

Örnek

PREDICATES

nondeterm yemeyi_sever(symbol, symbol)

nondeterm yemek(symbol)

yemegin_tadi(symbol, symbol)

CLAUSES

yemeyi_sever(besir,X):-

yemek(X),

yemegin_tadi(X, iyi).

yemegin_tadi(kebap, iyi).

yemegin_tadi(kapuska, kotu).

yemek(kapuska).

yemek(kebap).

GOAL yemeyi_sever(besir, Besirin_Sevdigi_Yemek).

Programda iki olgu kümesi, bir de kural bulunmaktadır. Kural, Bülent’in, tadı güzel olan yemeklerden hoşlandığını söylemektedir. Sorgunun doğrulanması için VP ilk satırdan başlayarak tarama yapar. Hedefe uyan ilk satır yemeyi_sever(bulent, X) kuralının başı olduğu için Besirin_Sevdigi_Yemek argümanı X ile eşleşir. Bu durumda kuralın geri kalan kısmının doğrulanmasına çalışılır. Buradaki ilk alt hedef yemek(X) cümleciğidir. VP alt hedefi doğrulamak için yine programın en başına gider. VP eşleşen bir olgu ararken yemek(kapuska) cümleciğine ulaşır ve burada X değişkeni ‘kapuska’ değerini alır. VIP, buraya geri dönüş işaretini koyar ve alternatif bir çözüm ararken hareket edilecek ilk noktanın başlangıcı belirtilmiş olur.

Bir sonraki hedef, yemegin_tadi(X, iyi) alt hedefi olur. X ‘kapuska’ değerini aldığına göre bu cümle yemegin_tadi(lahana, iyi) şekline dönüşür. Bunun doğrulanması sırasında argümanlar başka bir olguyla eşleşmediği için bu alt hedef olumsuz olur. Dolayısıyla sorgunun bu doğrulanması başarısız olur. İşte bu noktada VP geri dönüş işaretini koyduğu en son noktaya, yani yemek(kapuska) cümleciğine gider. Geri dönüş noktasına gelindiğinde, bu noktadan sonra değer almış olan bütün değişkenler yeniden serbest hale gelirler.

Bu noktadan sonra ilk eşleşme yemek(kebap) olgusu ile olur ve X değişkeni kebap değerini alır. Daha sonraki alt hedef yemegin_tadi(kebap, iyi) olduğundan, programın başından itibaren yapılacak bir taramadan olumlu sonuç alınır. Çünkü yemegin_tadi(kebap, iyi) olgusu önceden tanımlanmıştı. Sonuçta görüntülenecek mesaj şu olur:

Besirin_sevdigi_yemek=kebap

1 Solution

Geriye İz Sürme yöntemiyle sadece tek çözüm değil, mümkün olan bütün çözümler elde edilir.

DOMAINS

aday=symbol

adayin_yasi=integer

PREDICATES

nondeterm oyuncu(aday, adayin_yasi)

CLAUSES

oyuncu(ahmet, 10).

oyuncu(mehmet, 12).

oyuncu(ali, 10).

oyuncu(huseyin, 10).

GOAL oyuncu(Birinci_oyuncu, 10), oyuncu(Ikinci_oyuncu, 10),

Birinci_oyuncu<>Ikinci_oyuncu.

VP’den yaşları 10 olan çocuklar arasında düzenlenecek bir masa tenisi turnuvası için muhtemel ikili rakip listesi istensin. Eşleştirme sırasında yaşları 10 olan, fakat kendileriyle eşleşmeyecek ikili gruplar istensin. Geriye İz Sürme yönteminin nasıl çalıştığını görmek için VP’nin takip edeceği prosedürü adım adım yazarsak:

1.   VP ilk önce sorgunun oyuncu(Birinci_oyuncu, 10) alt hedefini doğrulamaya çalışır. Bu hedef oyuncu(ahmet, 10) cümleciğiyle sağlanmış olur. VP hemen ikinci alt hedefi doğrulamaya çalışır. (Bu sırada programın en başına dönüş yapılır) oyuncu(İkinci_oyuncu, 10) alt hedefini sağlamaya çalışırken yine 10 yaş şartını birinci cümlecik sağlar. Dolayısıyla İkinci_oyuncu argümanı da ‘ahmet’ değerini alır. Her iki alt hedef sağlandıktan sonra şimdi üçüncü alt hedef sağlanmaya çalışılır. Yani Birinci_oyuncu<>İkinci_oyuncu (Birinci ve ikinci oyuncu aynı kişi olmayacak)

2.   Oyuncuların her ikisi de ahmet olarak eşleştiği için bu hedef sağlanamaz, dolayısıyla sorgu başarısız olur. VP’nin Geriye İz Sürme mekanizması yeniden bir önceki alt hedefi, yani ikinci alt hedefi sağlamaya yönelir. Bu kez ikinci_oyuncu argümanı ali değerini alır.

3.   Üçüncü alt hedef sağlanmış olur. Çünkü ahmet ve ali, yaşları 10 olan farklı kişilerdir. Bütün alt hedefler sağlandığından sorgunun tamamı başarılmış olur. Sonuçta oluşan ilk ikili

Birinci_oyuncu= ahmet, İkinci_oyuncu=ali

olarak bulunmuş olur.

4.   VP’nin sadece bir çözüm değil, mümkün olan bütün çözümleri bulur. Bu yüzden 3. alt hedef sağlandıktan sonra başka çözüm olup olmadığını bulmak için bütün alternatifler tükeninceye kadar ikinci alt hedefi sorgulanır. Bu kez ikinci_oyuncu olarak Hüseyin seçilir. Ahmet ve Hüseyin 3. şartı da sağladığı için ikinci grup ahmet ve hüseyin’den oluşur.

5.   Peki başka çözüm var mı? VP bunu bulmak için yine ikinci alt hedefe dönüş yapar. Görüldüğü gibi son oyuncu olan Hüseyin ile bu şanş tükenmiştir. İşte bu noktada Geriye İz Sürme yine ilk alt hedefe döner. İkinci eşleşme oyuncu(ali, 10) cümlesinde olur. İkinci oyuncu Hüseyin ile eşleşir. En son alt hedef de sağlandığı için bu kez ali=hüseyin ikilisi oluşturulur.

6.   Başka çözüm için VP 2. alt hedefe döner. VP ikinci kez hüseyin ismiyle eşleşme yapar. Fakat kişi aynı olduğundan sonuç alınamaz. Geriye İz Sürme yöntemiyle bütün seçeneklerin sırasıyla denenmesi sonucunda şu tablo ortaya çıkar.

Birinci_oyuncu=ahmet, İkinci_oyuncu=ali

Birinci_oyuncu=ahmet, İkinci_oyuncu=hüseyin

Birinci_oyuncu=ali, İkinci_oyuncu=ahmet

Birinci_oyuncu=ali, İkinci_oyuncu=hüseyin

Birinci_oyuncu=hüseyin, İkinci_oyuncu=ahmet

Birinci_oyuncu=hüseyin, İkinci_oyuncu=ali

6 Solutions

Bulunan sonuçların bazıları, isimlerin sadece yer değiştirilmesinden oluşmuş aynı ikili gruplardır. Bunu engellemek mümkündür.

(Not: Aynı program ile yaşları 10 ve 12 olan ikili grupları bulunuz)

4.2. Geriye İz Sürme Mekanizmasının Ayrıntıları

Aşağıdaki programa bakarak Geriye İz Sürme işlemenin nasıl işlediğini anlamaya çalışalım.

DOMAINS

isim, sey= symbol

PREDICATES

sever(isim, sey)

okur(isim)

merakli(isim)

CLAUSES

sever(ahmet, limonata):-!.

sever(murat, yuzme):-!.

sever(murat, kitap):-!.

sever(murat, basketbol):-!.

sever(Z,kitap):-

okur(Z), merakli(Z).

okur(ahmet).

merakli(ahmet).

GOAL sever(X, limonata), sever(X, kitap).

VP hedefi değerlendirirken, doğrulanan ve doğrulanamayan alt hedefleri belirler. Yukarıdaki programa aşağıdaki hedefi göz önüne alarak bakalım. Hedef aşağıdaki gibi bir ağaç dalı şeklinde gösterilebilir. Doğrulanan alt hedefi altı çizili halde, bununla eşleşen cümleciği de bunun hemen altına yazalım.

sever(X,limonata)

Sever(X,kitap)

4.2.1. Geriye İz Sürmenin 4 Temel Prensibi

Yukarıdaki örnekte, hedefin gerçekleştirilmesi için doğrulanması gereken iki alt hedef vardır. Bunun için VP dört temel prensibe göre çalışır:

1.   Bütün alt hedefler, ilkinden başlanmak üzere, birer birer doğrulanmalıdır. Bir cümleciğin doğrulanması için hangi alt hedefin kullanılacağına ikinci kurala göre karar verilir.

2.   Yüklem cümlecikleri (fonksiyonlar) programdaki sırasıyla, yukarıdan aşağıya göre test edilirler. Buna göre yukarıdaki program çalışırken ‘sever’ yüklemini sağlayan sever(ahmet, limonata) cümleciğiyle doğrulanır. Dolayısıyla sever(X, limonata) alt hedefindeki X argümanı ‘ahmet’ değerini alır. Daha sonra ikinci alt hedef doğrulanmaya çalışılır. Burada bağlı hale gelen X=ahmet argümanı kullanılır. Fakat sever(ahmet, limonata) alt hedefi sever(ahmet, kitap) alt hedefine eşitlenemez, çünkü limonata ve kitap aynı değildir. Bütün cümleciklerin sırayla deneneceği için bir sonraki cümlecik sever(murat, kitap) olacaktır. Fakat X daha önce ‘ahmet’ değerini aldığı için bu şık da başarısız olur. Bu yüzden bir sonraki sever cümleciğinin sağlanması gerekir.

sever(Z,kitap):-okur(Z), merakli(Z).

Z argümanı bir değişkendir ve X değişkeni ile eşleşebilir. Zaten ‘kitap’ argümanları da eşleşir. Dolayısıyla hedef, kuralın baş kısmıyla eşleşmiş olur.

Bir alt hedef bir kuralın baş kısmıyla eşleştiği zaman, kuralın gövde kısmının doğrulanması sağlanmalıdır. Böylece kuralın gövdesi doğrulanması gereken bir alt hedefler kümesi oluşturur.

Şimdi yeniden örneğe dönelim.

sever(X,limonata)                      sever(X,kitap)

okur(Z)                                                        merakli(Z)

okur(Z) ve merakli(Z) alt hedeflerinin doğrulanması gerekir. Burada Z değişkeninin ‘ahmet’ değerini aldığı söylenmişti. Şimdi ise her iki alt hedefi de sağlayan sorgulama başlayacaktır. Sonuçta elde edilecek ağaç:

sever(X,wine)                              sever(X,kitap)

sever(ahmet,wine)                     sever(Z,kitap)

                                       okur(Z)                 merakli(Z)

okur(ahmet)                merakli(ahmet)

4.   Hedef ağacının her bir dalını sağlayan bir gerçek bulunduğu zaman hedef sağlanmış olur.

Sonuçta

X=ahmet

1 Solution

cevabı görüntülenir. Harici bir hedef doğrulandıktan sonra VP’nin, eğer varsa, bütün alternatifleri bulmak için çalışacağı söylenmişti. Bir alt hedef başarısız olursa, VP yeniden bir önceki alt hedefe döner. Bu alt hedefi, biraz önce başarısız hale gelen alt hedefi de doğrulayacak bir cümlecik ile doğrulamaya çalışır.

VP bir alt hedefi sağlamak için sorgulamaya yüklemi tanımlayan ilk cümlecikten başlar. Bu sırada aşağıdaki durumlardan biri meydana gelebilir:

1.   İlk cümlecik verilen yüklemle eşleşir. Bu durumda;

a.   Alt hedefi doğrulama ihtimali olan başka bir cümlecik varsa, Geriye İz Sürme işleminde kullanılmak üzere bu cümleciğin yanına bir işaret konur.

b.   Alt hedefteki bütün serbest değişkenler cümlecikteki değerleri alır ve bağlı hale gelirler.

c.   Eğer eşleşen cümlecik bir kuralın baş tarafı ise, hemen kuralın gövde kısmı değerlendirilir. Bu durumda gövdedeki bütün alt hedeflerin doğrulanması gerekir.

2.   Eşleşen herhangi bir cümlecik bulunmaz ve sorgu başarısız hale gelir. VP bir önceki alt hedefi doğrulamak için geriye iz sürer. En son geriye dönüş noktasına geldiğinde, VP geriye dönüş noktasından sonra değer almış bütün değişkenleri serbest hale getirir. Daha sonra alt hedefi yeniden doğrulamaya çalışır.

Tarama, programın başından başlar. Geriye İz Sürme işlemi, daha önce yerleştirilen geriye dönüş noktasından itibaren başlar. Sorgu burada da başarısız olursa, geriye iz sürme işlemi tekrar edilir. Bütün alt hedef ve cümlecikler için geriye dönüş işlemi tamamlandığında sonuç elde edilemezse, hedef başarısız olur.

Geriye dönüş işlemi için başka bir örnek.

Örnek:

PREDICATES

nondeterm tur(symbol, symbol)

nondeterm canli(symbol, symbol)

yasar(symbol, symbol)

nondeterm yuzebilir(symbol)

CLAUSES

tur(tirnakli, hayvan).

tur(balik, hayvan)

canli(zebra, tirnakli).

canli(alabalik, balik).

canli(kopekbaligi, balik).

yasar(zebra, karada).

yasar(kurbaga, karada).

yasar(kurbaga, suda).

yasar(kopekbaligi, suda).

yuzebilir(Y):-

tur(X, hayvan),

canli(Y,X),

yasar(Y, suda).

GOAL yuzebilir(Ne), write(“Bir “,Ne,” yüzebilir\n”).

Program yazılıp çalıştırıldığında ilk olarak GOAL bölümü sağlanmaya çalışılır. Şimdi yapılacak işlemleri adım adım yazalım:

1.   yuzebilir yüklemi, ‘Ne’ serbest değişkeni ile çağrılır. Eşleşme olup olmadığını bulmak için program tarandığında ‘Ne’ argümanı ‘Y’ değerini alır.

2.   Hemen sonra hedefin gövde kısmına geçersek tur(X,hayvan) alt hedefinin doğrulanması gerekir. Programın başından itibaren yapılacak bir taramada tur(tirnakli, hayvan) cümleciği bu alt hedefi sağlar. Böylece X=tirnakli değerini alır.

3.   Burada tur(X,hayvan) alt hedefini sağlayabilecek birden fazla alternatif olduğu için, tur(tirnakli,hayvan) cümleciğinin yanına Geriye İz Sürme işareti konur.

4.   X değişkeni ‘tirnakli’ değerini alınca birinci alt hedef doğrulanmış olur. Bu kez ikinci alt hedef yani canli(Y, X) doğrulanmaya çalışılır. Bu hedef ise canli(Y, tirnakli) olarak sağlanır. canli(zebra, tirnakli) cümleciği ikinci alt hedefi sağlar ve Y değişkeni ‘zebra’ değerini alır ve bu hedefi sağlayan başka cümlecikler de mevcut olduğundan, VP bu cümleciğin yanına da bir Geriye İz Sürme işareti koyar.

5.   Şimdi X=tirnakli ve Y=zebra olacak şekilde en son alt hedefin doğrulanması gerekir. yasar(Y, suda) alt hedefinin sağlanması için yasar cümleciklerinin biriyle eşleşmesi gerekir. Fakat cümlecikler arasından bunu sağlayan bir gerçek olmadığı için hedef başarısız olur.

6.   VP bu noktada geriye dönüş işareti koyduğu en son noktaya, yani ikinci alt hedef ve canli(zebra, tirnakli) cümleciğine döner.

7.   Geriye dönüş noktasına geldiğinde, bu noktadan sonra değer almış bütün değişkenler serbest hale gelir. Daha sonra canli(Y, tirnakli) alt hedefine yeni bir çözüm arar.

8.   VP daha önce işaret koyup durduğu satırdan başlamak üzere, geriye kalan cümlecikler arasında tarama yaparak şimdiki alt hedefe uyacak bir çözüm arar. Programımızda alt hedefi doğrulayacak başka bir seçenek bulunmadığından, yapılan çağrı başarısız olur ve VP yeniden bir önceki alt hedefe döner.

9.   Bu kez tur(tirnakli, hayvan) hedefini doğrulamaya çalışır. Çünkü geriye dönüş işareti buraya konulmuştu.

10. Bütün değişkenler serbest hale getirilir ve yeniden tur(X, hayvan) alt hedefine çözüm arar. Geriye dönüş noktasından sonraki tur(balik, hayvan) cümleciği bu hedefi doğrular ve X=balik değerini alır. VP bu kez geriye dönüş noktasını bu cümleciğin yanına yerleştirir.

11. VP şimdi kuraldaki ikinci alt hedefi doğrulamak üzere aşağıya doğru hareket eder. Bu tarama yeni bir tarama olduğu için tarama yine cümleciklerin başından, yani canli(Y, tirnakli) cümleciğinden başlar.

12.  canli(alabalik, balik) cümleciği alt hedefi doğrular ve Y=alabalik değerini alır.

13. Y şimdi ‘alabalik’ değerini aldığı için, yasar(alabalik, suda) alt hedefi çağrılır. Bu da yeni bir çağrı olduğu için program yine baştan başlar.

14. Cümleciklerde görüldüğü gibi, yasar yüklemleri arasında yasar(alabalik, suda) alt hedefini doğrulayacak bir seçenek yoktur. Bu yüzden çağrı başarısız olur ve bir önceki alt hedefe yeniden dönüş yapılır.

15. canli(alabalik, balik) geriye dönüş noktasına gidilir.

16. Bu noktadan sonra değer alın bütün değişkenler yeniden serbest hale geldikten sonra canli(Y, balik) çağrısına cevap aranır.

17. Bu kez Y=kopekbaligi değeri alt hedefi sağlar.

18. VP üçüncü alt hedefi yeniden doğrulamaya çalışır. Y ‘kopekbaligi’ değerini aldığı için yasar(kopekbaligi, suda) alt hedefinin doğrulanması gerekir. Bu yeni çağrı doğrulanır, çünkü son cümlecik eşleşmektedir.

19. Alt hedeflerin doğrulanmasından sonra kuralın baş kısmı da sağlanmış olur. VP, Y değişkeninin aldığı ‘kopekbaligi’ değerini yuzebilir(Ne) kuralındaki Ne değişkenine atar ve böylece Goal bölümündeki write(“Bir “,Ne,” yüzebilir\n”) alt hedefi de çağrılır. Sonuç:

Bir köpekbalığı yüzebilir

Ne=kopekbaligi

1 Solution

4.3. Tarama İşleminin Kontrol Edilmesi

VP’de var olan geriye iz sürme mekanizması bazen gereğinden fazla tarama yapabilir. Bu ise verimi düşürür. Bazen verilen bir problem için sadece bir çözüm bulmak istenebilir. Bazen de, bir çözüm bulunsa bile –varsa- başka alternatif çözümleri de bulmak istenebilir. İşte bu gibi durumlarda geriye dönüş işleminin kontrol edilmesi gerekir.

Geriye İz Sürme işlemini kontrol edebilmek için VP’nin iki özelliğinden faydalanılabilir. Bunlar,: VP’yi geriye iz sürme işlemi yapmaya zorlayan fail yüklemi ve geriye dönüş mekanizmasını engelleyen cut ‘!’ özelliğidir.

4.4. fail Yükleminin Kullanılması

Alt hedeflerden birinin sağlanamaması durumunda geriye dönüş işlemi yapılır. Bazı durumlarda alternatif çözümleri bulabilmek için bu işlemin yapılması gereklidir. VP’nin fail yüklemi, bir sorgunun başarısız olmasına ve böylece geriye dönüş işleminin yapılmasına imkan tanır.

DOMAINS

isim=symbol

PREDICATES

nondeterm baba(isim, isim)

herkesi_bul

CLAUSES

baba(“Ömer “, yavuz).

baba(ahmet, kasim).

Baba(huseyin, veli).

Baba(murat, yusuf).

herkesi_bul:-

baba(X,Y), write(X, Y,” Babası\n”),

fail.

herkesi_bul.

GOAL herkesi_bul.

Programdaki dahili hedef doğrulandıktan sonra VP’nin geriye iz sürmesine gerek yoktur.  Bundan dolayı baba ilişkisine yapılan ilk çağrı başarılı olur ve sadece bir tek çözüm sağlanmış olur. Fakat yüklem bölümündeki herkesi_bul yüklemi fail özelliğini kullanarak Prologu geriye iz sürme mekanizmasını kullanmaya zorlar ve mümkün olan bütün çözümlerin bulunmasını sağlar. Herkes yükleminin amacı, görüntülenen cevapların daha net olmasıdır.

Herkes yüklemi VP’yi zorlayarak, baba(X,Y) kuralının sağlanması için geriye dönüş işleminin çalıştırılmasını sağlar. Daima olumsuz cevap vereceği için fail kuralının doğrulanması mümkün değildir. Bu yüzden VP daima bir üstteki alt hedefe geriye dönüş yapar. Geriye dönüş olduğunda VP, birden fazla çözüm verebilecek en son hedefe döner. Bu tür bir çağrı belirsiz (non-deterministic) olarak tanımlanır. Belirsiz bir çağrı, belirli olan ve sadece bir tek çözüm sunabilen bir çağrının tam tersidir.

‘write’ yükleminin doğruluğu yeniden sağlanamaz, çünkü yeni çözümler sunmaz. Haliyle VP kuraldaki ilk alt hedefe geriye dönüş yapar.

‘fail’ yüklemini takiben başka alt hedeflerin yazılması hiçbir işe yaramaz. Çünkü ‘fail’ yükleminin kendisi daima başarısız olacağından, ‘fail’ yüklemini takip eden bir alt hedefin sorgulaması mümkün değildir.

4.5. Geriye İz Sürmeyi Engelleme

VP’de ünlem işareti ile gösterilen (!) cut yükleminden itibaren geriye dönüş mümkün değildir. Cut yüklemi, bir kuralın içinde herhangi bir alt hedefmiş gibi yazılır. Program çalışırken cut alt hedefi daima doğrulanır ve işlem bir alt hedefe geçer. Bu hedeften önceki alt hedeflere ve cut komutunu içeren alt hedefin kendisine geriye dönüş artık mümkün değildir.

Cut komutu iki amaç için kullanılır:

1.     Alternatif çözümün mümkün olmadığına önceden karar verilirse, vakit ve bellek kaybını önlemek için bu komut kullanılabilir. Böylece program daha hızlı çalışır. Buna ‘green cut (Olumlu Cut)’ denir.

2.     Programın kendi mantığı cut yüklemini gerektiriyorsa, alternatif alt hedeflerin incelenmesini önlemek için de cut kullanılır. Buna ise ‘red cut (Olumsuz Işık)’ adı verilmektedir.

4.5.1. Cut Komutunun Kullanımı

Bu bölümde cut komutunun kullanımı ile ilgili örnekler üzerinde çalışalım. r1, r2, r3 kuralları r yüklemini, a, b, c ise alt hedefleri gösterir.

Bir kural içindeki bir alt hedefe geri dönüşü engellemek için

R1:- a, b, !, c. yazılabilir.

Yukarıdaki kuralın anlamı şudur: Kural içerisindeki a ve b alt hedeflerini doğrulayan bir çözüm bulunduğunda programı durdur. Bu yüzden cut komutunu geçip c alt hedefine geçmek mümkün değildir. Dolayısıyla a ve b için alternatif çözümler mümkün olsa da, sadece bulunan ilk çözümle yetinilir. Cut komutu r1 yüklemini tanımlayan başka bir cümlecik içine gitmeyi de engeller.

Örnek

PREDICATES

araba_satin_al(symbol,symbol)

nondeterm araba(symbol,symbol,integer)

renkler(symbol,symbol)

CLAUSES

araba_satin_al(Model,Renk):-

araba(Model,Renk,Fiyat),

renkler(Renk,cazip),!,

Fiyat > 20000.

araba(murat,yesil,25000).

araba(mersedes,siyah,24000).

araba(bmw,kirmizi,28000).

araba(renault,kirmizi,24000).

araba(toyota, sari, 30000).

renkler(kirmizi,cazip).

renkler(siyah,orta).

renkler(yesil,berbat).

renkler(sari, cazip).

GOAL araba_satin_al(bmw, Hangi_renk).

Bu örneğin verilmesinin amacı, rengi cazip, fiyatı da uygun olan bir BMW almaktır. Veri tabanında BMW için zaten bir satır vardır. Prolog’un yapması gereken tek şey, fiyatının verilen şarta uyup uymadığını kontrol etmektir. Goal içerisindeki ! komutu, BMW için fiyat uygun değilse, başka bir araba aranmasını engeller. Programı çalıştırıldığında

Hangi_renk=kirmizi

1 Solution

yanıtı alınır.

4.5.2. Geriye İz Sürmeyi Engelleme

Cut komutu, bir yüklem için doğru olan bir cümlenin seçildiğini belirtmek için de kullanılabilir.

r(1):-!, a, b, c

r(1):-!, d

r(1):-!, c

r(_):- write (“Cümlelerin tamamı buraya yazılır”).

Cut komutu r yüklemini deterministic (belirli) yapar. Dolayısıyla r yüklemi bir tamsayı argümanı ile çağrılır. Yapılan çağrının r(1) olduğunu kabul edelim. Prolog yapılan çağrıya uygun bir eşleşme ararken, r’yi tanımlayan bir cümlecik bulur. Birden fazla çözüm mümkün olduğundan, Prolog ilk cümleciğe geri dönüş noktası işareti koyarak aşağıda doğru işleme devam eder ve geri kalan satırlara geçer. Olacak ilk şey, cut komutu geçmektir. Böyle yapmak artık başka bir r cümleciğine geri dönüşü ortadan kaldırır ve geri dönüş noktası ortadan kalktığı için, programın çalışma hızı oldukça artar.

Bu tür yapının diğer dillerde yazılan ‘Case’ yapılarına benzediği görülür. Deneme şartı, kuralın baş tarafında yazılır. Yukarıdaki satırları daha anlaşılır yapmak için şöyle yazalım:

r(x):- X=1, !, a, b, c.

r(x):- X=2, !, d.

r(x):- X=3, !,c.

r(_):-write (“Cümlelerin tamamı buraya yazılır”).

Örnek:

PREDICATES

arkadas(symbol,symbol)

kiz(symbol)

sever(symbol,symbol)

CLAUSES

arkadas(ahmet,fatma):- kiz(fatma), sever(ahmet,fatma),!.

arkadas(ahmet,mehmet):- sever(mehmet,futbol),!.

arkadas(ahmet,esra):- kiz(esra).

kiz(tuba).

kiz(fatma).

kiz(esra).

sever(mehmet,futbol).

sever(ahmet,esra).

GOAL arkadas(ahmet,Kimin_Arkadasi).

Program akışı içerisinde Cut komutu kullanılmazsa, yukarıdaki örnekten iki ayrı sonuç elde edilir. Yani Ahmet hem Mehmet’in hem de Esra’nın arkadaşıdır. Fakat arkadas iliskisini tanımlayan ilk cümledeki Cut komutu, bu cümlenin doğrulanıp Ahmet’in bir arkadaşının bulunması durumunda, artık ikinci bir arkadaş bulmanın gereksiz olduğunu vurgular. Bu yüzden yukarıdaki Goal için sadece Mehmet’in Ahmet’in arkadaşı olduğu cevabı görüntülenir.

4.6. Determinism ve Cut

Yukarıdaki örnekte ‘arkadas’ yüklemi Cut kullanılmadan tanımlanmış olsaydı, non-deterministic, yani geriye iz sürme işlemiyle birden fazla çözüm üretmesi mümkün bir yüklem olacaktı. Programların ihtiyaç duyacakları bellek miktarı artacağından, özellikle non-deterministic yüklemler ile çalışılırken dikkatli olmak gerekir. VIP non-deterministic yüklemleri dahili olarak kontrol etmekle beraber, güvenli bir program yazmak için check_determ derleyici direktifini kullanmak faydalıdır. Eğer check_determ programın hemen ilk satırına yerleştirilirse, programın çalıştırılması esnasında non-deterministic yüklemlere gelindiğinde bir uyarı mesajı görüntülenir. Böylece non-deterministic olan bir yüklemin gövde kısmında (body) uygun bir Cut komutu kullanarak yüklemi deterministic hale getirebiliriz.

4.7. Not Yüklemi

Genel Not Ortalaması 3.5 olan ve beklemeli olmayan Şeref Öğrencisini bulman program:

DOMAINS

isim= symbol

gno= real

PREDICATES

nondeterm seref_ogrencisi(isim)

nondeterm ogrenci(isim, gno)

beklemeli(isim)

CLAUSES

seref_ogrencisi(Isim):-ogrenci(Isim,Gno),Gno>=3.5, not(beklemeli(Isim)).

ogrenci (“Kasım Yenigün”, 3.5).

ogrenci(“Ferit DAĞDEVİREN”, 2.8).

ogrenci(“Orhan AYDIN”, 3.8).

beklemeli(“Kasım Yenigün”).

beklemeli(“Ferit DAĞDEVİREN”).

GOAL seref_ogrencisi(Seref_Ogrencisinin_Adi_Soyadi).

Not komutunu kullanırken dikkat edilmesi gereken tek bir kural vardır: Not komutu, sadece alt hedefin doğruluğunun ispatlanamaması durumunda işlem görür. Serbest değişkenli bir alt hedef Not içerisinden çağrıldığı zaman, Prolog, Free variables not allowed in ‘not’ or ‘retractall’ (Not veya retractall içerisinde serbest değişkenler kullanılamaz) hata mesajını verecektir. Prolog’un bir alt hedefteki serbest değişkenlere değer ataması için, bu alt hedefin başka cümlecikle eşleşmesi ve alt hedefin doğrulanması gerekir. Not içeren bir alt hedefteki bağımsız değişkenleri kullanmanın en doğru yolu anonim değişkenler (_) kullanmaktır.

Aşağıda bu konu ile ilgili yanlış ve doğru örnekler verilmiştir:

sever(ahmet, Herhangi_Biri):-                 /* ‘Herhangi_Biri çıktı argümanıdır’*/

sever(esra, Herhangi_Biri),

not(nefret_eder(ahmet, Herhangi_Biri).


 PROGRAM KONTROL DEYİMLERİ

 8.1.1. IF Yapısı

 Programın akışını IF değimi ile birlikte verilen koşula bağlı olarak belirlenen veya ELSE, ELSEIF veya END IF değimleri ile oluşturulan  işlem bloğuna geçmesini veya söz konusu program bloğunun işletilmeyip atlatılmasını sağlar.

 Yazılım :

 

                        IF Şart THEN

                                   Komutlar

                        ELSE

                                   Komutlar

                        END IF

 

Şartın gerçekleşmesi durumunda THEN değiminden sonraki satır işletilir. Gerçekleşmemesi durumunda ise ELSE değiminden sonraki satırlar işletilir.           

Tek satırda şart yazılırsa  END IF değimi kullanılmaz.

                       IF Şart Komutlar THEN Komutlar

            IF Şart Komutlar

 

Örnek 8.1  :   Girilen üç notun ortalamasını alıp, bu notların ortalamasına göre öğrencinin geçip veya kaldığını yazan programı yapınız?

 

Private Sub Form_Load()

 

Dim n1,n2,n3,ort

  n1=val(InputBox(“1.Sınav Notunu Giriniz:”, “Sınav”);

  n2=val(InputBox(“2.Sınav Notunu Giriniz:”, “Sınav”);

  n3=val(InputBox(“3.Sınav Notunu Giriniz:”, “Sınav”);

  ort=(n1+n2+n3)/3

             IF (ort<50) Then

     MsgBox(“Kaldınız” &ort)

 

 Else

 

    MsgBox(“Geçtiniz” &ort)

 END IF

End Sub

 

8.1.2. Select Case Yapısı   

İşlev bakımından IF değimine çok benzemektedir. Çok sayıda IF yapısı içi içe kullanıldığı zaman programın okunurluğu azalır ve programı izlemek zorlaşır. Bu gibi durumlarda Select Case yapısı kullanılır.

 Yazılım : 

            Select Case Kontrol Değişkeni

                        Case ifade 1

                                   ……

                        Case ifade 2

                                   …….

                        Case Else

                                   …….

            End Select

 Genel yazılımdan anlaşılacağı gibi bloğu başlatan Select Case değiminden sonra yapılacak karşılaştırmalarda kullanılacak bir kontrol değişkeni bulunmaktadır. Eğer kontrol değişkeninin içeriği “ifade1” olarak verilen değerle aynı ise, birinci ifadenin içeriğini araştıran Case değiminden bir sonraki Case değimine kadar olan program satırları işletilir ve program akışı End Select değiminden sonraki satıra geçer. 

Örnek 8.2. : Yukarıdaki örneği bu Select Case değimiyle yapalım.

 

Private Sub Form_Load()

 

Dim n1,n2,n3,ort

n1=val(InputBox(“1.Sınav Notunu Giriniz:”, “Sınav”);

n2=val(InputBox(“2.Sınav Notunu Giriniz:”, “Sınav”);

n3=val(InputBox(“3.Sınav Notunu Giriniz:”, “Sınav”);

ort=(n1+n2+n3)/3

     Select Case ort

Case  ort<50

 MsgBox(“Kaldınız” &ort)

 Case ort>50

                        MsgBox(“Geçtiniz” &ort)

           

   End Select

End Sub

 

Örnek 8.3 : 1-3 arasında girilen sayıyı bulan programı yapanız?

 

Private Sub Form_Load()

Dim sayi

sayi=val(InputBox(“1 ile 3 arasında bir sayı giriniz.”);

Select Case sayi

Case 1 

 MsgBox(“Girdiğiniz Sayı 1”)

            Case 2

                        MsgBox(“Girdiğiniz Sayı 2” )

            Case 3

                        MsgBox(“Girdiğiniz Sayı 3” )          

   End Select

End Sub

 

8.1.3. IIF Yapısı

 

Bir değişkenin değeri iki durumdan birine göre değer alırsa IF yapısı yerine IIF kullanılabilir. Bu yapı bize daha az satırla aynı işi yapabilmemizi sağlar.

 

 

 

Yazılım : 

            IFF (Şart; Doğru ise; yanlış ise)

 

Örnek 8.4 :   

Private Sub Form_Load()

Dim n1,n2,n3,ort,son

     n1=val(InputBox(“1.Sınav Notunu Giriniz:”, “Sınav”);

     n2=val(InputBox(“2.Sınav Notunu Giriniz:”, “Sınav”);

     n3=val(InputBox(“3.Sınav Notunu Giriniz:”, “Sınav”);

     ort=(n1+n2+n3)/3

            son=IIF (ort<50, “geçtiniz”, “Kaldınız”)

MsgBox son

End Sub

 

8.1.4. Choose Yapısı           

Bir değişkenin aldığı değer bir sayıya bağlı ise bu yapıyı kullanmak daha uygun olur.

 Yazılım:

Sonuç= Choose(sayı, değer1, değer2, değer3, değer4,……,değerN)

 Örnek 8.5:  gun=Choose(GunNo, “Pazar”, “Pazartesi”, “Salı”, “Çarşamba”,    “Perşembe”, “Cuma”, “Cumartesi”)

8.1.5. Switch Yapısı

           Birden fazla şartı aynı anda kontrol etmek için kullanılır.

  Yazılım :           

Sonuç=Switch(Şart1, Değer1, Şart2, Değer2,…….,ŞartN, DeğerN)

            8.2.1. For-Next Döngüsü 

For-Next döngüsü sayacın başlangıç değerinden başlayarak bitiş değerine kadar istenilen miktarda artırılarak blok içindeki konutları çalıştırır.

 

Yazlım:

 

            For Sayac=BaşlangıçDeğeri to BitişDeğeri [Step Artırım]

                        Komutlar

            Next

 

Not:  Artma değeri verilmezse artış miktarı 1 olarak alınır.  

Örnek 8.6 :  1’den 10’a kadar olan sayıları toplayan programı yapınız?

 

Private Sub Form_Load()

 

Dim sayi,i

      For i=1 to 10

          sayi=sayi+i

      Next

            MsgBox sayi

End Sub 

8.2.2.While-Wend ve Do While- Loop Döngüsü

Bir şart gerçekleştiği sürece çalışması gereken program bloklarında kullanılırlar. 

 

Yazılım:                While Şart

                        Komutlar

            Wend

 Do While Şart

            Komutlar

Loop

Yukarıdaki her iki komutta da  şart gerçekleştiği sürece döngüde kalınır.

 Örnek 8.7: Klavyeden girilen 10 öğrencinin notlarına göre sınıf ortalamasını hesaplayan programı yapınız.

Private Sub Form_Load ()

Dim not (10) As Integer

Dim t As Integer

 i=1

                Do While i < = 10

                  Not(i) = InputBox(Str(i) & ”. Öğrencinin Notu”)

              t = t + not(i)

            Loop

ort=t/10

MsgBox ort

End Sub

 8.2.3. Do Until – Loop Döngüsü

Bu döngü yapısı diğerlerinden farklı olarak şart gerçekleşene kadar

çalışması gereken program bloklarında kullanılır.

 Yazılım :

            Do Until Şart

                        Komutlar

Loop

 8.2.4. Do-Loop While ve Do Loop Until Döngüsü

Bu döngü yapılarının diğerlerinden tek farkı şart döngüye girerken değil de çıkarken kontrol edilir. Yani döngü içerisindeki komutlar en az bir kez çalışırlar.

Yazılım :

            Do

                        Komutlar

            Loop Until Şart

 Do

            Komutlar

Loop While Şart

 8.2.5.      Döngü Kontrol İfadeleri

 8.2.5.1. Exit Do

Bu komut Do-Loop ve While Wend döngülerinden birinde bazı şartların gerçekleşmesi durumunda döngüden çıkmak için kullanılır.

 8.2.5.2. Exit For       

            For-Next döngüsü tamamlanırken bazı şartlar gerçekleştiğinde döngüden çıkmaya yarar.

 8.2.5.3. Exit Sub ve Exit Function 

           Exit Sub ve Exit Function değimleri alt program sonuna ulaşmadan alt programdan çıkmaya yarar.

 8.2.5.4. End

            Programı sona erdirir.

    

PHP – 2

              

                  $ogrenciler[0][soyadi] = “Altun”;

                  $ogrenciler[0][sinav1] = “”;

                  $ogrenciler[0][sinav2] = “”;

                  $ogrenciler[0][not] = “”;

// Buraya Buraya başka kodlar girecek

                  print $ogrenciler[0][adi];

?>

Bir dizi değişkende kaç boyut olacaksa, o kadar içiçe array() ögesi oluşturabiliriz. Buna göre tek boyutlu bir dizi değişken sadece bir array() komutu ile ve sadece değerler verilerek oluşturulabilir. Diyelim ki yukarıdaki öğrenci listemiz sadece öğrencilerin isimlerinden oluşacak. Bu durumda $ogrenciler değişkenine ilişkin satırı şöyle yazabilirdik:

$ogrenciler = array (“Özbay”, “Muharrem”, “Hasan”, “Şahika”);

PHP, böyle tek boyutlu bir dizinin örneğin birinci elemanını, “$ogrenciler[0]” adıyla bilir. Böyle bir tek-boyutlu diziyi oluşturmak için PHP bize başka bir kolaylık da sağlar: array() komutunu kullanmadan,  doğruca dizinin ögelerine değer vermemiz mümkündür. Yukarıdaki programın sadece PHP bölümünü şöyle değiştirerek, dizi_degiskenler03.php adıyla kaydedin:

<?php

                  $ogrenciler[] = “Özbay”;

                  $ogrenciler[] = “Muharrem”;

                  $ogrenciler[] = “Hasan”;

                  $ogrenciler[] = “Şahika”;

// Buraya başka kodlar girecek

            print $ogrenciler[0];

?>

Böyle sırayla dizi değişken oluşturur veya oluşturulmuş bir dizi değişkene ek yaparken, değişkenin sıra numarasını yazmazsak, PHP bunları kendisi sıralar. Yukarıdaki kodun da Browser penceresine “Özbay” yazdırması gerekir. Mevcut tek-boyutlu bir dizi değişkene ek yaptığımızda, be yeni değerin dizinin en altına eklenmesini istiyorsak, sıra numarası yazmamıza gerek yoktur. Mevcut değerlerden birini değiştirmek istiyorsak, o değerin sıra numarasını yazmamız gerekir. Bunu denemek için yukarıdaki kodu şöyle değiştirilim ve dizi_degiskenler04.php adıyla kaydedelim:

<?php

                  $ogrenciler[] = “Özbay”;

                  $ogrenciler[] = “Muharrem”;

                  $ogrenciler[] = “Hasan”;

                  $ogrenciler[] = “Şahika”;

// Buraya başka kodlar girecek

                  $ogrenciler[0] = “Emre”;

                  $ogrenciler[15] = “Özbay”;

            print (“Dizideki 1’nci isim: $ogrenciler[0] <br>”);

            print (“Dizideki 2’nci isim: $ogrenciler[1] <br>”);

            print (“Dizideki 3’ünci isim: $ogrenciler[2] <br>”);

            print (“Dizideki 4’üncü isim: $ogrenciler[3] <br>”);

            print (“Dizideki 5’inci isim: $ogrenciler[4] <br>”);

            print (“Dizideki 6’ncı isim: $ogrenciler[5] <br>”);

            print (“…………..<br>”);

            print (“Dizideki 15’nci isim: $ogrenciler[15] <br>”);

           

?>

Bu programın Browser penceresine göndereceği sırada, birinci öğrenci ($ogrenci[0]) olarak bu kez Özbay değil Emre yazdığını göreceğiz.

<php00017.tif>

Bunun sebebi, diziyi oluşturan ilk grup deyimden sonra,

                  $ogrenciler[0] = “Emre”;

satırı ile birinci elemanın değerini değiştirmiş olduk. 15’nci elemana atama yapmakla, PHP’nin $ogrenciler dizisinde 6, 7, 8, 9,.. 14’e kadar boş elemanlar oluşturmasına sebep olduk.

Tek boyutlu dizileri de İlişkili Dizi olarak oluşturabilir yani değerlere endeks adı verebiliriz. Daha önce kaydettiğimiz dosyada şu değişikliği yapalım ve dizi_degiskenler05.php adıyla kaydedelim:

<?php

            $ogrenci[adi] = “Özbay”;

            $ogrenci[soyadi] = “Altun”;

            $ogrenci[sinav1] = “”;

            $ogrenci[sinav2] = “”;

            $ogrenci[not] = “”;

// Buraya başka kodlar girecek

            print $ogrenci[adi];

?>

PHP, $ogrenci adlı değişkenin beş ayrı değeri olduğunu ve bunların “adi,” “soyadi,” “sinav1″… olduğunu biliyor. Şimdi artık istediğimiz noktada bu değişkenin istediğimiz değerine, o değerin endeks adını yazarak, çağrıda bulunabiliriz; bu değeri yeniden verebiliriz.

Dizi değişkenleri kullanalım

Yukarıdaki paragrafta “..değişkenin istediğimiz değerine, o değerin endeks adını yazarak, çağrıda bulunabiliriz..” dediğimizi görmüş olmalısınız. Dizi veya tekil, değişkenleri oluşturmamızın sebebi, tuttukları değerleri programımızın gereği olan şekilde ve yerde kullanmaktır. Sadece bir değer tutan değişkenleri örneğin print() komutu ile sık sık kullandık. Yukarıda dizi değişken örneklerinde de bazı değişkenleri ve değerlerini çağırdık. Ancak dizi değişkenlerin değerlerinden yararlanabilmek için başka araçlar da vardır.

Herşeyden önce dizi değişkenlerin büyüklüğü, boyutu bizim için önem taşıyabilir. Özellikle bir veritabanı dosyasını okutarak oluşturacağımız dizi değişkenin kaç elemanı ve her bir elemanın kaç ögesi bulunduğunu bilmemiz gerekebilir.

Bir dizi değişkenin kaç elemanı bulunduğu, o değişkenin count() özelliği sorgulanarak öğrenilir. count(), dizideki eleman sayısını verir. Şimdi bunu bir örnekle görelim. Daha önce kaydettiğimiz dizi_degiskenler04.php dosyasını açın ve PHP bölümünde şu değişikliği yaparak dizi_degiskenler06.php adıyla kaydedin:

<?php

                  $ogrenciler[] = “Özbay”;

                  $ogrenciler[] = “Muharrem”;

                  $ogrenciler[] = “Hasan”;

                  $ogrenciler[] = “Şahika”;

// Buraya başka kodlar girecek

print (“\$ogrenciler adlı dizide “. count($ogrenciler) .” adet eleman var.”);

?>

Bu program Browser penceresine dizimizde 4 eleman bulunduğunu bildirecektir. Şimdi işleri biraz karmaşık hale getirelim! Yukarıdaki kodun, print() satırının yerine şu satırları ekleyerek, dizi_degiskenler06a.php adıyla kaydelim.

print (“\$ogrenciler adlı dizide “. count($ogrenciler) .” adet eleman var.”);

print (“<br><br>”);

for ($sayac=1 ;  $sayac <= count($ogrenciler) ; $sayac++ ) {

print (“\$ogrenciler dizisinin “. $sayac .”‘ncı elemanı: ” . $ogrenciler[$sayac] .”<br>”);

}

Bu programı çalıştırmadan önce, eklediğimiz satırları irdeleyelim. İlk print() komutunun Browser penceresine “yazdıracağı” metinde geçen ters bölü işaretini hatırlıyor olmalısınız. Bu, tek veya çift tırnak içine de almış bile olsak, PHP’nin, bir değişken adını gördüğü zaman onun yerine o değişkenin tuttuğu değeri yazması sebebiyle, $ işareti gibi PHP için özel anlamı olan işaretlerin anlamlandırılmasını önlemek için yaptığımız ve adına o karakteri kurtarma veya ESCaping dediğimiz işlemdir. Bu işlemle, PHP’nin anlamlı işaret değil de metin saymasını istediğimiz karakterlerin önüne ters bölü işareti koyarız: \” gibi. Buradaki örnekte, bu sayede PHP “$ogrenciler” kelimesini değişken adı olarak değil, düz metin olarak görüyor. Ki, aynı komutta aynı kelimeyi tekrar kullandığımızda bu kez değişken adı olarak kullanıyoruz ve bu değişkenin count() ögesinin değerini öğreniyoruz. $ogrenci değişkenin “Özbay,” “Muharrem,” “Hasan” ve “Şahika” değerleri bulunduğuna göre, bu değişkenin count()‘u 4 olacaktır. (“Ozbay” = 0, .. “Şahika” = 3 olmak üzere..) Bu print() komutu, Browser penceresine tahmin ettiğiniz gibi “$ogrenciler adlı dizide 4 adet eleman var.” yazdıracaktır. İkinci print() satırı ise ekrana ardarda iki yeni satır işareti gönderecektir.

Şimdi karışık noktaya geliyoruz! Burada bir for döngüsü başlıyor. Önce döngünün kaç kez tekrar edeceğini belirleyecek olan değişkeni tanımlıyoruz: $sayac. Sonra bu sayacın kaça kadar çıkacağını  belirliyoruz. Bu sayıyı, bize yine count() veriyor.  Ve tabiî for döngüsünün devam edebilmesi için gerekli son unsur olan, sayacın arttırılmasını sağlayan deyim var. Programımız bu döngünün içinde, yani dört kez, her seferinde dizinin bir elemanın adını Browser penceresine gönderiyor. Şimdi, hatırlayacaksınız, dizi değişkenlerin elemanlarının bir sıra sayısı vardı. Örneğin “Şahika” değeri, dizinin 3 numaralı, yani dördüncü elemanı; ve bu elemanın değerini ekrana göndermek için şu komutu vermemiz yeterli:

print ($ogrenciler[4]);

Programda ise buradaki endeks sayısını, $sayac değişkeninin o andaki değerinden alıyoruz. Döngünün her seferinde bu değer bir artacağı için bize $ogrenciler değişkeninin o anda hangi elemanının değeri çağırmak istiyorsak, o elemanın endeksini vermiş olacaktır. Ve sonuç olarak programımız, dizideki bütün değerleri Browser’a gönderecektir.

<php00018.tif>

Kimi zaman buradaki örnekte olduğu gibi, dizinin bütün elemanlarını bir for döngüsüyle değil, foreach döngüsüyle bulmak daha kolay olabilir. Kısaca belirtmek gerekirse, foreach döngüsü, bir dizi değişkenin bütün elemanları için, arzu ettiğiniz işi yapar. foreach döngüsünü yazarken komutun kaç kere icra edileceğini bir sayaçla tutmak gerekmez; çünkü döngü, ona adını verdiğiniz değişkenin içindeki bütün değerler bitinceye kadar devam edecektir. Yukarıdaki örnekteki bütün print() ve for satırlarını atarak yerine şunları yazıp ve dizi_degiskenler06b.php adıyla kaydelim.

foreach ($ogrenciler as $ogrenci) {

            print (“$ogrenci<br>”);

            }

foreach döngüsü, bir dizi değişkenin adını içinden değer çekilecek kaynak olarak ister; bunu “as” (olarak) kelimesi izler; sonra diziden alınacak her bir değeri geçici olarak tutacak değişkenin adı verilir. Buradaki print() komutumuz, bu geçici değişkenin tuttuğu değeri Browser’a gönöderecektir. Bu değer ise döngünün her adımında dizi değişkendeki bir değer yani öğrencilerin listesi olacaktır.

Dizi elemanlarının farklı özelliklerine ilişkin değerlere endeks adı verdiğimiz ilişkili dizilerde ise eleman değerlerini çağırmak foreach döngüsünün biraz farklı yazılmasını gerektirir. Perl’e aşina alanların bu dizi türüne “hash” dendiğini hatırlayacaklardır. PHP’de de Perl’ün hash türü değişkenlerinde olduğu gibi, endeks adlarına “anahtar” (key), bu endeksin belirlediği değere ise (evet, doğru tahmin ettiniz!) değer (value) denir. İlişkili dizilerden değer almak üzere foreach döngüsü yazılırken, değerin anahtarını ve değerin kendisini iki geçici değişkene yazmamız gerekir. Daha önce yazdığımız dizi_degiskenler05.php adlı dosyayı açarak mevcut tek satırlık print() kodunun yerine şunları yazın ve dizi_degiskenler07.php adıyla kaydedin:

foreach ($ogrenciler as $anahtar=>$deger) {

print (“$anahtar = $deger<br>”);

}

Bu kodu çalıştırmadan önce foreach döngüsü üzerinde kısaca duralım: döngü, $ogrenciler dizisini okumaya başladığında içinde, benzetme yerinde ise, iki sütun, ve bir çok satırlar bulacaktır. Bu sütunlardan birincisi, ikinci sütundaki verinin adıdır; foreach, birinci sütundaki veriyi alarak $anahtar adlı geçici değişkenin değeri olarak atayacak; sonra ikinci sütuna geçecek ve bunu alarak $deger adlı geçici değişkenin değeri yapacaktır. Döngü, daha sonra print() komutunu icra edecektir. print() ise ve geçici $anahtar değişkeninin değerini, ardından eşittir işaretini ve son olarak da geçici $deger değişkeninin değerini Browser’a gönderecektir. print() komutunun icrası bitince, foreach, kendisine verdiğimiz $ogrenciler değişkeninde anahtar-değer çiftini ele almadığı satır kalıp kalmadığına bakacak, ve elemanların tümü bitinceye kadar bu işlemi tekrar edecektir. Tabiî, sonuç anahtar ve değerlerin altalta sıralanması olacaktır.

<php00019.tif>

Bir de bu bölümün en başında ele aldığımız çok elemanlı ilişkili diziler vardı. Onların içindeki değerleri acaba nasıl alabilir ve kullanabiliriz? Tabiî yine bir döngü ile. Fakat bu kez, döngü-içinde-döngü kullanmak zorundayız. Böyle bir diziyi gözümüzde canlandırırsak, belki neden iki döngüye ihtiyaç olduğununu daha iyi görebiliriz. Gözümüzün önüne bir tablo getirelim: dizinin her bir elemanı (bizim öğrenimizde öğrenciler9 bir satırda yer almış olsun; sütunlar olarak da bu elemana ait değerler yer alıyor. Sütun başlığı ise, bu değerin endeksi olan anahtar! Şimdi bu bölümün başında yazdığımız dizi_degiskenler0i.php adlı dosyayı açalım tek satırlık print() komutunun yerine şu satırları yazarak dizi_degiskenler08.php adıyla kaydedelim:

foreach ( $ogrenciler as $ogrenci ) {

            foreach ( $ogrenci as $anahtar => $deger ) {

                  print (“$anahtar = $deger <br> “);

                  }

            print (“<br>”);

            }

Kısaca irdelersek, bu kodda foreach döngüsünün önce çok-boyutlu değişkenimizin bir satırını içindeki bütün anahtar+değer çeftleri ile ele alıp, tümünü $ogrenci adlı değişkene geçici olarak yerleştirdiğini görüyoruz. Bu foreach döngüsünün ilk işi yeni bir foreach döngüsü başlatmak oluyor. Yeni foreach ise sazı eline alır almaz, önce, kendisi çok ögeli bir değişken olan (çünkü içinde bir öğrenciye ait, tüm değişkenler ve onların endeks adları var) $ogrenci değişkeninin içindeki anahtar ve değer çiftlerini  tek-tek, $anahtar ve $deger değişkenlerine yerleştiriyor; sonra print() komutu ile, aralarına eşittir işareti koyarak bu değişkenlerin değerlerini Browser penceresine gönderiyor. Bu döngü biter bitmez, ilk foreach yaptıracağı işlere kaldığı yerden devam ediyor; ve ekrana bir yeni satır komutu gönderierek, başa dönüyor; bu kez çok boyutlu dizi değişkenin yeni bir elemana geçiyor. Taa ki, dizinin bütün elemanları ve elemanların bütün ögeleri bitinceye kadar.

<php00020.tif>

Bu noktada bir uyarı: Gerçek programda bir dizinin elemanlarına ilk ulaştığımızda, elemanın içinde değer bulunup bulunmadığını anlamak yerinde olur. Bunu is_array() fonksiyonu ile yapabiliriz. Bu fonksiyon, dizinin içinde değer varsa, True/Doğru, yoksa False/Yanlış karşılığını verecektir. Buradaki örnekte, ilk foreach satırından hemen sonra:

is_array( $ogrenci )

satırını koyarak, dizinin o anda okunan elemanın içinde değer bulunup bulunmadığını anlayabiliriz.

Dizi Değişkenlerin Düzenlenmesi

Dizi değişkenlerin daha verimli şekilde kullanılması için PHP bize bir takım araçlar sağlar. Bunlarla dizi değişkenleri birleştirebiliriz; içinden kesit alabiliriz, sıralayabiliriz veya bazı elemanlarını silebiliriz. Şimdi kısaca bu işlemleri ele alalım:

Dizileri birleştirme: array_merge()

İki veya daha fazla dizinin bütün elemanlarını birleştirerek, ortaya  yeni bir dizi çıkartır. Örnek:

$birinci_dizi = array ( “Özbay” , “Muharrem” , “Hasan” , “Şahika” );

$ikinci_dizi = array ( “Altun” , “Taç” , “Civelek” , “Tabak” );

$yeni_dizi = array_merge ( $birinci_dizi, $ikinci_dizi );

Bu kod ile oluşturulan $yeni_dizi isimli dizi değişkenin hangi elemanlara sahip olduğunu, şöyle bir kodla görebilirsiniz:

foreach ( $yeni_dizi as $yeni_eleman ) {

            print (” $yeni_eleman <br>”);

            }

İkinci dizinin bütün elemanları, birinci dizinin elemanlarının arkasına eklenmiş olmalı. array_merge() işlemi, çok-boyutlu ilişkili dizilere de uygulanabilir; PHP iki dizideki uyumlu-uyumsuz, yani birinde olan diğerinde olmayan bütün anahtar+değer çiftlerini yeni dizide de oluştur. (array_merge() işleminden sonra birleştirilen dizilerin değişmeden kaldığına dikkat edin.)

Dizilere değişken ekleme: array_push()

Bir diziye yeni değişkenler eklemek için, array_push() fonksiyonuna mevcut dizinin adını ve yeni değerleri yazarız. Örnek:

$birinci_dizi = array ( “Özbay” , “Muharrem” , “Hasan” , “Şahika” );

$yeni = array_push ($birinci_dizi, “Altun” , “Taç” , “Civelek” , “Tabak” );

Burada $yeni adlı değişken sadece $birinci_dizi adlı dizinin yeni eleman sayısını tutar. array_push(), kendisine adını verdiğimiz dizinin içeriğini değiştirir. Yukarıdaki örnekte içine yeni değerler yazılan dizinin elemanlarını görüntülemek için şöyle bir kod yazabiliriz:

print (“\$birinci_dizi adlı dizide $yeni_dizi adet değişken var<br>”);

foreach ( $birinci_dizi as $ogrenci ) {

            print (“$ogrenci <br> “);

            }

Dizinin ilk elemanını silme: array_shift()

Bir dizi-değişkenin ilk elemanını tümüyle silmek için array_shift() fonksiyonunu kullanırız. Bu fonksiyona sadece birinci elemanı silinecek dizinin adını vermek yeter. Örnek:

$birinci_dizi = array ( “Özbay” , “Muharrem” , “Hasan” , “Şahika” );

$silinen = array_shift ($birinci_dizi);

array_shift(), adını verdiğiniz dizinin içeriğini değiştirir; buradaki örnekte, $silinen adlı değişken dizinin silinen birinci elemanın değerini tutar.

Diziden kesit alma: array_slice()

Bir dizi-değişkenin bütün elemanları yerine bir kesitini kullanmak istiyorsak, bunu array_slice() fonksiyonu ile yapabiliriz. Bu fonksiyona kesit alınacak dizinin adı, kesitin başladığı yer ve kaç adet değişken alınacağı argüman olarak verilir. Örnek

$birinci_dizi = array ( “Özbay” , “Muharrem” , “Hasan” , “Şahika”, “Altun” , “Taç” , “Civelek” , “Tabak”);

$kesit = array_slice ($birinci_dizi ,  3, 4);

Burada, PHP’ye $kesit adlı yeni dizi değişkene, $birinci_dizi adlı dizinin 3’ncü değerinden itibaren (3 dahil) dört değeri yerleştirmesini bildiriyoruz. array_slice(), adını verdiğimiz değişkenin içeriğine dokunmaz; yeni dizi değişken oluşturulur.

Dizileri sıralama: sort() ve rsort()

Bir dizinin içindeki değerleri alfabetik veya küçükten büyüğe doğru sıralamak için sort() fonksiyonunu kullanırız. Örnek:

$birinci_dizi = array ( “Özbay” , “Muharrem” , “Hasan” , “Şahika”, “Altun” , “Taç” , “Civelek” , “Tabak”);

sort ($birinci_dizi);

PHP, dizideki bütün değerleri A’dan Z’ye sıraya sokacaktır. sort() fonksiyonu dizinin içeğini değiştirir. Bir diziyi Z’den A’ya veya büyükten küçüğe doğru sıralamak için de rsort() fonksiyonunu kullanabilirsiniz. (PHP4.0 Türkçe karakterleri tanımıyor.) Bir noktada dikkatli olmak gerekir: bu fonksiyonu ilişkili (değerlerin anahtarı olarak endeks adı bulunan) dizide kullanırsanız, PHP, anahtar değerlerini (endeks adlarını) atar, yerine 0’dan itibaren rakam koyar. Bunu önlemek için, ilişkili dizileri asort() veya ksort() fonksiyonu ile sıralamak gerekir.

İlişkili dizileri sıralama: asort() ve ksort()

İlişkili dizilerin diğer dizi değişkenlere göre farkı, değerlerinin bir de adı bulunmasıdır. Değerlerin adlarına anahtar denir. Bir ilişkili diziyi değerlerine göre sıralamak için asort() fonksiyonu kullanılır. Örnek:

$birinci_dizi = array ( ogr_01=>”Özbay”, ogr_02=>”Muharrem” , ogr_013>”Hasan” , ogr_04=>”Şahika”);

asort ($birinci_dizi);

PHP, bu diziyi değerler itibariyle alfabetik sıraya sokacaktır. Eğer sıranın değere göre değil de değerlerin anahtarına (burada ogr_01, ogr_02 olan kelimeler) göre yapılmasını istiyorsak, ksort() fonksiyonunu kullanırız. Örnek:

$birinci_dizi = array ( ogr_01=>”Özbay”, ogr_02=>”Muharrem” , ogr_013>”Hasan” , ogr_04=>”Şahika”);

ksort ($birinci_dizi);

PHP, şimdi bu diziyi anahtarlara göre alfabetik sıraya sokacaktır.

Nesneler

Nesne yönelimli (Object-oriented) programlama icad edildiğinde, geleneksel programlamaya aşina olanlar önce tereddüt ettiler; sonra bunun ne harika bir teknik olduğnunu gördüler ve nesnelerden vazgeçmez oldular. Kabaca tanımlarsak, nesne, kendi değişkenleri ve icra edeceği komutlardan oluşan fonksiyonları ile bir bütündür. Nesneyi bir kere tanımladıktan sonra istediğimiz kadar örneğini oluşturabiliriz. Bir nesnenin yapacağı işten, o nesnenin metodu diye söz ederiz. Bu açıdan bakarsanız, programlarımızda nesneler sadece metodları için işe yararlar.

Diyelim ki programımızda bir “öğrenci” nesnesi oluşturmak istiyoruz. Bu nesnenin içinde adı, soyadı ve notlar gibi değişkenler, ve bu değişkenlerle yapılan bir takım işler bulunsun. İşe nesnenin tabir yerinde ise şablonu olan class‘ı oluşturmakla başlayalım; gerisini de yaptıkça görelim.

Bir Nesne Oluşturalım

Bir nesne oluşturmak için önce onu tanımlamamız gerekir. Bunu PHP’nin class deyimini kullanarak yapabiliriz. Bir nesnenin özellikleri (properties) ve metodları (methods) vardır. Şu kodu nesneler01.php adıyla kaydedin:

<HTML>

<HEAD>

<TITLE>PHP’de Degiskenler</TITLE>

<meta http-equiv=”content-type” content=”text/html; charset=ISO-8859-9″>

<meta http-equiv=”Content-Type” content=”text/html; charset=windows-1254″>

</HEAD>

<BODY>

<B>

<H2>

<?php

class ogrenci {

// özellikleri tanımlayalım

            var $adi;

            var $soyadi;

            var $sinav1;

            var $sinav2;

            var $not;

// metodları tanımlayalım

function adi_belirle ($n) {

            $this->adi = $n;

            }

function soyadi_belirle ($n) {

            $this->soyadi = $n;

            }

function sinav1_belirle ($n) {

            $this->sinav1 = $n;

            }

function sinav2_belirle ($n) {

            $this->sinav2 = $n;

            }

function not_hesapla() {

            $this->not = ($this->sinav1 + $this->sinav2)/2;

print ($this->adi. ” ” . $this->soyadi . ” için not ortalaması: “. $this->not);

            }

}

//Buraya başka kodlar girecek

$ogr1 =  new ogrenci();

$ogr1 -> adi_belirle(“Şahika”);

$ogr1 -> soyadi_belirle(“Tabak”);

$ogr1 -> sinav1_belirle(7);

$ogr1 -> sinav2_belirle(10);

$ogr1 -> not_hesapla();

?>

</H2>

</B>

</BODY>

</HTML>

Bu programda ogrenci adlı bir nesne tanımlıyoruz; ve daha sonra bir değişken adına new komutu ile bu nesnenin bir örneğini oluşturuyoruz. Nesnelerin yeni bir örneği veya kopyasını çıkartmak ifadeleri aslında yaptığımızı tam anlatmıyor. Nesnenin tanımı bir adet; her new komutu ile bu nesnenin özelliklerine ve metodlarına sahip yeni bir nesne yapmış oluyoruz. Nitekim bu işe insanın dilini dolayan İngilizce bir kelimeyle Instantiation (yeni bir varlığını oluşturma) deniyor. Bu örnekte, $ogr1 adlı değişken gerçekte, ogrenci nesnesinin tam bir örneği: içinde beş değişken ve altı metod var. Nesneyi bir kere tanımladıktan sonra programın daha ileri aşamalarında bu istediğimiz kadar örneğini farklı isimler vererek oluşturabiliriz. Şimdi şu satıra dikkat edelim:

$ogr1 =  new ogrenci();

$ogr1 -> adi_belirle(“Şahika”);

Burada $ogr1’in parametrelerine nasıl değer yazdırdığımızı görüyorsunuz. Nesnenin metodlarından biri olan adi_belirle fonksiyonuna bir değer veriyoruz: “Şahika”; nesne oluşturulurken yazılmış olan bu fonksiyon ise aldığı değeri, kendi ait olduğu nesnenin bir değişkenine kaydediyor:

function adi_belirle ($n) {

            $this->adi = $n;

            }

Bu ve diğer fonksiyonlarda kullandığımız “$this->” ifadesi, kendisine ulaştırılan değeri bir parametre olarak kullanıyor ve “$adi” değişkenine yazıyor. “this” (bu) kelimesi o anda nesnenin o anda oluşturulmakta olan örneğine göndermede bulunur. “->” işlemcisini kullanarak, istediğimiz nesnenin istediğimiz metoduna veya parametresine değer gönderebiliriz. Bir nesnenin yeni bir örneğini oluşturduğumuz zaman, bu örneğin bütün parametrelerini sağlamak veya bütün metodlarını kullanmak zorunda değiliz.

Yukarıdaki örneğe göre yeni örnekler oluşturarak en az dört öğrencinin not ortalamasını hesabedebilir misiniz?

PHP ile Web programcılığı yolunda hızlı adımlarla yol alıyoruz. Bu bölümde gördüğümüz dizi değişkenler ve nesneler, Web sayfalarımızda bir çok işi adeta otomatik hale getirecek unsurlar olarak kullanılacak.

PHP İşbaşında

PHP’de bir programı oluşturmaya ve programın akışını kontrol etmeye yetecek kadar bilgi sahibi olduk. Bu bölümde, bu bilgilerimizi uygulamaya koyacağız; ve bu arada halâ öğrenmemiz gereken bir iki noktaya ayrıntılı olarak değineceğiz. Özellikle metinlerin düzenlenmesi konusuna bakmamız ve ve Düzenli İfadeler (Regular Expressions) denen kavramla tanışmak ve bunun araçlarını öğrenmek zorundayız. PHP’nin işbaşında olması demek, PHP bilgimizi HTML sayfalarımızı PHP ile oluşturma, Form bilgilerini derleme, bir veritabanından veri alarak bunları sayfalarımızda kullanma ve ziyaretçinin vereceği bilgileri veritabanına işleyebilmek demektir. Şimdi kolları yeniden sıvayalım ve PHP’yi uygulamaya koyulalım.

Formlar

Web sunucusu ve istemcisi (Browser) arasındaki etkileşme ve alışverişin nasıl işlediğine ilişkin bilgilerimiz olduğunu varsayarak, sadece Internet’te Form, bir Web sayfasının ziyaretçiden veri alabildiği ve bunları Web sunucusuna ulaştırabildiği başlıca araç olduğunu hatırlayalım. Form, ziyaretçinin bizim istediğimiz bilgilerin yanı sıra ziyaretçinin bilgisayarından Web sunucusu bilgisayara, daha bir çok bilgiyi de beraberinde getirir. Web programcısı ve Web tasarımcısı olarak bu bilgileri bilmeye daima ihtiyacımız var. Söz gelimi, ziyaretçimizin Browser türünü ve sürümü belirleyerek, onu, uygun sayfaya yönlendirmekten tutun, ziyaretçiden istediğimiz bilgilerin Sunucu’ya ulaştığında nerede ve hangi değişkende tutulduğuna kadar, gerekli bir çok bilgi Sunucu çievre değişkenleri ve Sunucu değişkenleri dediğimiz dizilerde bulunur. Form tasarımına ve bir Form’un bilgilerini PHP ile yakalamaya ve işlemeye geçmeden önce Web Server’ı ve bize verdiği bilgileri daha yakından tanınamız yararlı olur.

Bunun için önce şu programı formlar01.php adıyla kaydedin ve çalıştırın:

<HTML>

<HEAD>

<TITLE>PHP’de Nesneler</TITLE>

<meta http-equiv=”content-type” content=”text/html; charset=ISO-8859-9″>

<meta http-equiv=”Content-Type” content=”text/html; charset=windows-1254″>

</HEAD>

<BODY>

<?php

foreach ($GLOBALS as $anahtar=>$deger ) {

            print ($anahtar . ” =  ” . $deger . “<br>”);

            }

?>

</BODY>

</HTML>

Şimdi Browser penceresinde gördüğünüz bilgileri irdeleyelim; çünkü biraz sonra ziyaretçiden Form ile gelen verileri yakalarken ve işlerken bu bilgilerden yararlanacağız. (Bu programı kişisel bilgisayarınızda, kişisel Web sunucuda çalıştırıyorsanız, aynı programın gerçek bir Unix-tabanlı Web sunucuda (Apache) nasıl sonuç verdiğini http://www.mycgiserver.com/~ocal/formlar01.php adresinde görebilirsiniz. Sunucu’nun oluşturduğu diğer değişkenleri ise http://www.mycgiserver.com/~ocal/php.php adresinde inceleyebilirsiniz.)

Bu programla PHP’nin daima varolan $GLOBALS dizisinin üyelerini görüntülüyoruz. $GLOBALS bir ilişkili-dizi-değişken, yani değişken değerlerinin endeks adı (anahtarı) bulunan bir dizi olduğu için, içerdiği değerlere adları ile ulaşabiliriz. Bu programda, $GLOBALS’ın anahtarlarını $anahtar, değerlerini ise $değer değişkenine yazdırıyoruz ve bir foreach döngüsü ile Brnowser penceresine gönderiyoruz. Programı çalıştırdığımız sisteme ve Web sunucu programına bağlı olmak üzere, ekranımızda bir çok değişken görebiliriz. Bunlar arasında bütün HTTP Server programları için ortak ve Web programcısı için önemli değişkenler şunlardır:

HTTP_ENV_VARS   HTTP Sunucu programın çalışmakta olan PHP dosyası için oluşturduğu çevre değişkenlerinin yazılı olduğu dizi değişken. Bu değişkenin içinde şu unsurlar bulunur:

                                    HOSTNAME: Sunucunun IP adresi

                                    SHELL: Unix sisteminde kullanılan Shell programı

                                    HOSTTYPE: Sunucunun adı ve sürünü

                                    OSTYPE: Sunucu’nun işletim sistemi

                                    HOME: Çalışan programın kök dizini

                                    PATH: Çalışan programın Sunucu’daki yolu

HTTP_SERVER_VARS       Sunucu programın çalışmakta olan PHP dosyasına sunduğu bazı bilgilerin bulunduğu dizi değişken. Bu değişkenin içinde şu unsurlar bulunur:

                                    PHP_SELF: Çalışan PHP programının bulunduğu dizin ve adı

                                    PATH_TRANSLATED: Çalışan PHP programının fiziksel yolu

HTTP_GET_VARS    Bir Form’dan GET metoduyla alınan bilgilerin anahtar=değer çiftleri olarak kaydedildiği dizi değişken

HTTP_POST_VARS  Bir Form’dan POST metoduyla alınan bilgilerin anahtar=değer çiftleri olarak kaydedildiği dizi değişken

HTTP_USER_AGENT  Ziyaretçinin bilgisayarında kurulu Internet Browser programı

QUERY_STRING     Form ile bilgi alırken GET metodunu kullandığımız takdirde, Browser’ın göndereceği bilgilerin tutulduğu değişken

REMOTE_ADDR      Ziyaretçinin bilgisayarına ISS tarafından atanmış IP adresi

REQUEST_METHOD   Form ile gelen bilgilerin gönderildiği metod: GET veya POST

REQUEST_URI         O anda çalışmakta olan PHP dosyasının adı ve varsa bu ada eklenmiş Query_String

SCRIPT_FILENAME    O anda çalışmakta olan PHP programının dosya adı

SCRIPT_URI             O anda çalışmakta olan PHP programının tam URL adresi

SERVER_ADDR       Sunucunun IP adresi

SERVER_PROTOCOL Sunucunun HTTP protokolünün sürümü

Form’dan GET Metoduyla Gelen Bilgiler

Ziyaretçilerimizin ne tür Browser kullandıklarını HTTP_USER_AGENT değişkeninin değerini alarak ve bu değerin içinde belirli anahtar kelimeleri aratarak bulabiliriz. Form ile gelen bilgiler, GET metodu ile alınıyorsa, hem QUERY_STRING, hem de HTTP_GET_VARS dizisine kaydolur. POST metoduyla aldığımız bilgileri HTTP_POST_VARS değişkenin değerleri arasında buluruz. Bunları öğrendiğimize göre, şimdi gerçekten bir HTML Form’u yapabil ve bununla ziyaretçimizden bilgi alabiliriz.

Basit bir HTML Form’u tasarlayalım. Aşağıdaki kodları formlar02.htm adılyla kaydedin:

<HTML>

<HEAD>

<TITLE>PHP’de Formlar</TITLE>

<meta http-equiv=”content-type” content=”text/html; charset=ISO-8859-9″>

<meta http-equiv=”Content-Type” content=”text/html; charset=windows-1254″>

</HEAD>

<BODY>

<FORM ACTION=”formlar02_isle.php” METHOD=”GET”>

Adınız, Soyadınız: <INPUT TYPE=”TEXT” NAME=”adi”>

<br>

Elektronik Adresiniz: <INPUT TYPE=TEXT” NAME=”adres”>

<br>

<INPUT TYPE=”SUBMIT” VALUE=”Gönder Gitsin!”> <INPUT TYPE=”RESET” VALUE=”Vazgeç, Gönderme!”> 

</FORM>

</BODY>

</HTML>

Bu Form’la Web tasarım yarışmasına katılmayacağımıza göre, şimdilik sadece Web Sunucuya bilgi göndermekte kullanabiliriz. Form’un ACTION parametresine dikkat ederseniz, formlar02_isle.php adlı bir dosyanın adını göreceksiniz. Bu, ziyaretçinin Gönder düğmesini tıklamasıyla birlikte Form’un içerdiği bilgilerin METHOD parametresinde pazılı olan GET yöntemiyle Sunucu’da gönderileceği programın adıdır.  Bu sayfa, Browser’da şöyle bir görüntü verecektir:

<php00021.tif>

Şimdi bir an için ne olacağını düşünmeden, formu doldurun ve Gönder düğmesini tıklayın; ve Browser’ınızdaki hata mesajına aldırmadan, URL adres kutusunda ne yazdığını okuyun:

http://server/formlar02_isle.php?adi=Muharrem+Ta%E7&adres=muharremtac@mynet.com

Bu, HTTP protokolüne göre GET yoluyla bilgi göndermekte kullanılan yöntemin tam bir örneğidir: Browser, GET yoluyla bilgi göndereceği zaman, Form’daki bütün bilgileri URL-Encoding denen sistemle kodlar; Form’un alan adlarına o alanlara ziyaretçinin yazdığı bilgileri bir eşittir işaretiyle ekler; bu tür alan=girdi çiftlerinin arasına & (ve işareti) koyar ve gönderir. Web sunucu, bu bilgileri alınca, önce kendi oluşturduğu bazı değişkenlere (hem QUERY_STRING, hem de HTTP_GET_VARS dizisine) yazar ve sonra URL hanesinde adı yazılı olan programa (sayfaya) verir. Şimdi bizim bu bilgilerin gönderildiği PHP programını kendisine verilecek bu bilgileri işlemeye hazır şekilde yazmamız gerekir. Şu aşağıdaki kodları formlar02_isle.php adıyla kaydedin:

<HTML>

<HEAD>

<TITLE>PHP’de Formlar</TITLE>

<meta http-equiv=”content-type” content=”text/html; charset=ISO-8859-9″>

<meta http-equiv=”Content-Type” content=”text/html; charset=windows-1254″>

</HEAD>

<BODY>

<?php

print (“Sayın  <b>$adi</b>\n\n”);

print (“<p>Elektronik adresiniz: <b>$adres </b></p>\n\n”);

?>

</BODY>

</HTML>

Şimdi, Browser’ınızda formlar02.htm sayfasını yeniden açın, Form’u doldurun ve gönderin. Açılacak sayfa, Form’un gönderecğii bilgileri alacak ve kendi görünteleyecektir.

<php00022.tif>

Fakat burada gördüğünüz gibi Sunucu’nun ziyaretçiden gelen bilgileri depoladığı dizileri kullanmadık. Bunu yaparken, GET ile gelen bilgiler kendisinde verildiğinde PHP programının alan adlarını değişken adı, bunların karşısında yazılı olan verileri de bu değişkenin değeri saymasından yararlandık. Fakat isteseydik, bu değişkenleri, Sunucu’nun oluşturduğu dizilerden de alabilirdik. Şimdi hem Form’umuzu geliştirelim; hem de bu kez okuma işini Sunucu dizisinden yapalım.

Önce Form’umuzu değiştirelim ve formlar03.htm adıyla kaydedelim:

<FORM ACTION=”formlar03_isle.php” METHOD=”GET”>

Adınız, Soyadınız: <INPUT TYPE=”TEXT” NAME=”adi”>

<BR>

Elektronik Adresiniz: <INPUT TYPE=TEXT” NAME=”adres”>

<BR>

Hangi notunuzu öğrenmek istiyorsunuz?

<BR>

<SELECT NAME=”hangi_not”>

<OPTION>–Lütfen seçiniz–

<OPTION>Sınav 1

<OPTION>Sınav 2

<OPTION>Ortalama

</SELECT>

<BR>

<INPUT TYPE=”SUBMIT” VALUE=”Gönder Gitsin!”> <INPUT TYPE=”RESET” VALUE=”Vazgeç, Gönderme!”> 

</FORM>

Yeni Form’da yeni bir HTML unsuruna yer verdiğimizi ve SELECT..OPTION etiketi ile ziyaretçiye bir seçim imkanı verdiğimizi görüyorsunuz. Şimdi, bu Form’un göndereceği bilgileri işleyecek PHP programını yazalım. Aşağıdaki kodları formlar03_isle.php adıyla kaydedelim:

<HTML>

<HEAD>

<TITLE>PHP’de Formlar</TITLE>

<meta http-equiv=”content-type” content=”text/html; charset=ISO-8859-9″>

<meta http-equiv=”Content-Type” content=”text/html; charset=windows-1254″>

</HEAD>

<BODY>

<?php

            foreach ($HTTP_GET_VARS as $anahtar=>$deger ) {

                  print (“<b>$anahtar = $deger <br>\n”);

            }

?>

</BODY>

</HTML>

Demiştik ki, Web sunucu, bir istemci Browser’dan kendisine GET yöntemiyle yollanan Form bilgilerini $HTTP_GET_VARS adlı dizi değişkende tutar. Yine daha önce görmüştük ki dizi değişkenlerin içinde ya sayı ya da isim olarak bir anahtar ve bu anahtarın temsil ettiği bir değer vardır. Burada, $HTTP_GET_VARS değişkeninin anahtar ve değerlerini $anahtar ve $deger değişkenlerine => operatörünün yardımıyla, bir foreach döngüsü içinde atıyoruz. Döngü kullanmamızın sebebi, dizi değişkenin içinde birden fazla anahtar=değer çifti bulunması ihtimali bulunması; döngü olarak da foreach kullanmamızın sebebi dizide kaç adet anahtar=değer çifti bulunduğunu bilmememizdir.

<php00023tif>

Form sayfasının gönderdiği bilgilerin nasıl derlenip toplanıp URL-koduyla Sunucuya gönderildiğini, Form’un Gönder düğmesini tıkladığımızda Browser’ın URL adres hanesinde ilen bilgilerin görülecektir. Buradaki örnekte bu bilgi (HTTP bölümünü  ve URL kodlarını kaldırarak):

adi=Şahika+Tabak&adres=stabak@somenet.com&hangi_not=Sınav+1

şeklindedir. Bu bilgi, sunucu tarafından $HTTP_GET_VARS dizi değişkeninin içine yazıldığına göre, daha önce gördüğümüz gibi dizi değişkenlerin anahtarlarını ve bu anahtarların temsil ettiği değerleri bir döngü içinde $anahtar ve $deger değişkenlerine atarsak, daha sonra bu değişkenlerin değerlerini Browser penceresine göndermemiz mümkün olur.

//////////////////////////////KUTU/////////////////

URL Kodları

HTTP protokolüne göre, temel ASCII listesi içinde yer almayan karakterler, ve tabiî bu arada sadece Türkçe’de bazı diğer alfabelerde bulunan harfler, bir Form’da yer aldığı taktirde, Browser tarafından URL şemasına göre kodlanarak gönderilir. Gerçi bir çok HTTP sunucu programıbu karakterlere tanıyabilir ve bir dosyaya yazarken doğru şekilde yazabilirler; ama bu çevirme işleminin bazen program yardımıyla yapılması gerekebilir. Bizim için önemli karakterler ve URL kodları şöyle:

ü = %FC

Ü = %DC

ö = %F6

Ö = %D6

ı = %FD

İ = %DD

ğ = %F0

Ğ = %D0

ş = %FE

Ş = %DE

ç = %E7

Ç = %C7

% = %25

& = %26

[ = +%5B

] = %5D

{ = %7B

} = %7D

? = %3F

 =  = %3D

/////////////////////KUTU BİTTİ////////////

Şimdi biraz dizi-değişken içine dizi-değişken koyalım! Yani ziyaretçinin göndereceği bilgiler, buradaki gibi SELECT..OPTION etiketinde yapacağı sadece bir unsur seçimi olmasın da çoklu-seçim olsun. HTML bilgilerinizi yoklarsanız, bunu SELECT etiketini MULTIPLE parametresi ile yapabildiğimizi hatırlayacaksınız. Biraz önceki kaydettiğimiz dosyanın sadece Form bölümünü aşağıdaki gibi geliştirerek, formlar03a.htm adıyla kaydedelim:

<FORM ACTION=”formlar03a_isle.php” METHOD=”GET”>

Adınız, Soyadınız: <INPUT TYPE=”TEXT” NAME=”adi”>

<BR>

Elektronik Adresiniz: <INPUT TYPE=TEXT” NAME=”adres”>

<BR>

Hangi notunuzu öğrenmek istiyorsunuz?

<BR>

<SELECT NAME=”hangi_not[]” MULTIPLE>

<OPTION>Sınav 1

<OPTION>Sınav 2

<OPTION>Ortalama

</SELECT>

<BR>

<INPUT TYPE=”SUBMIT” VALUE=”Gönder Gitsin!”> <INPUT TYPE=”RESET” VALUE=”Vazgeç, Gönderme!”> 

</FORM>

Burada, HTML’in SELECT.. OPTION etiketlerini kullanarak, ziyaretçimizden hangi sınav notunu öğrenmek istediğini bize bildirmesini istiyoruz. Dikkat ettiğiniz gibi, bu kez Form, elde edeceği verileri formlar03a_isle.php programına yollamak istiyor. Form’daki <SELECT NAME=”hangi_not[]” MULTIPLE> satırına da dikkat ettiniz mi? Bu satırın özelliği, daha önceki SELECT..OPTION etiketinden farklı olarak ziyaretçinin çoklu seçme yapmasına imkan veriyor; ve elde edilecek değeri “hangi_not[]” alanının değeri olarak bildiriyor. HTTP iletişim ilkelerine göre çoklu-seçim halinde seçilen OPTION değerleri Sunucu’ya aynı alan adının karşısına yazılarak gönderilir. Formumuzun göndereceği bilgi yumağını satırlar haline getirirsek (HTTP bölümünü atar ve URL kodlarını çözersek) bunu görebiliriz:

adi=Şahika Tabak

adres=stabak@somenet.com

hangi_not[]=Sınav 1

hangi_not[]=Sınav 2

hangi_not[]=Ortalama

Kendisine böyle bir bilgi yumağı gelen Server, bunun tümünü $HTTP_GET_VARS dizi değişkeninin içine yazacaktır. Başka bir deyişle, bu dizi değişken çıok-boyutlu çok-elemanlı ilişkili-dizi olduğu için, içinde rahatça aynı isimde değişkenlere farklı endeks sayısı verecektir. Fakat sorun PHP’nin, bu dizinin içinden değişkenleri almasında ortaya çıkacak ve endeks ismi aynı olan değişkenler sorun olacaktır. Bunu değişkenin endeks adı olarak kullanılacak kelimenin yanına köşeli parantez koyarak çözüyoruz. PHP bu adı görünce, bunun çok-elemanlı bir dizi değişken olacağını anlayacaktır.

Eğer bu formu, formlar03_isle.php programına gönderseniz (bunu nasıl yapabilirsiniz?), “hangi_not” değişkeninin değeri olarak Browser penceresinde “array” kelimesinin belirdiğini görebilirsiniz. Çünkü PHP açısından bu değişken bir dizidir ve içinde anahtar=değer çiftleri vardır. Daha önce anahtar=değer çiftlerini geçici değişkenlere atayıp bir döngü ile yazdırmıştık. Şimdi, PHP kodumuzu bu duruma uygun hale getirelim. Biraz önce yazdığımız Form işleme programının sadece PHP bölümünü şöyle değiştirerek, formlar03a_isle.php adıyla kaydedelim:

<?php

            foreach ($HTTP_GET_VARS as $anahtar=>$deger ) {

                  if ( gettype ($deger ) == “array” ) {

                        print (“$anahtar == <br>\n”);

                        foreach ( $deger as  $yeni_degerler )

                              print (“.. $yeni_degerler<br>”);

                              }

                  else {

                  print (“<b>$anahtar = $deger <br>\n”);

                  }

            }

?>

PHP’nin gettype() fonksiyonunu daha önce görmüş ve bir değişkenin türünü anlamaya yaradığını öğrenmiştik. Burada $HTTP_GET_VARS değişkeninden aldığımız değerlerden herhangi birinin gerçekten bir değişken değeri mi, yoksa bir dizi (array) mi olduğunu gettype() ile anlayabiliriz. Eğer değer olarak karşımıza “array” kelimesi çıkarsa, bunu kendi içinde anahtar ve değer olarak bölebilir ve herbirini ayrı ayrı görüntüleyebiliriz. Eğer $HTTP_GET_VARS değişkeninden aldığımız değer, dizi değil de gerçekten bir değişken ise (else) doğruca bu değeri ve anahtarını yazdıracaktır. Sonuç ise dizi-değişken içindeki dizi-değişkenin değerlerinin tek tek görüntülenmesi olacaktır.

<php00024.tif>

Form’dan POST Metoduyla Gelen Bilgiler

HTML Form etiketinin METHOD parametresinin değeri GET olabildiği gibi POST da olabilir; ve HTTP sunucusu bu yöntemle gelen bilgileri $HTTP_POST_VARS dizi-değişkeninde tutar. Yukarıdaki çok-seçmeli Form’un FORM etiketini şöyle değiştirerek, formlar03b.htm adıyla kaydedelim:

<FORM ACTION=”formlar03a_isle.php” METHOD=”POST”>

Aynı şekilde son Form işleme programımızda da sadece şu değişikliği yapalım:

foreach ($HTTP_POST_VARS as $anahtar=>$deger ) {

Bu dosyayı da formlar03b_isle.php adıyla kaydedelim. HTML sayfasını açarak formu doldurur ve gönderirseniz, sonucun metod olarak GET kullanan Form’dan hiç farklı olmadığını göreceksiniz. Çünkü PHP programı bu Form’un gönderdiği bilgilerin $HTTP_POST_VARS değişkenine yazıldığını biliyordu. $HTTP_POST_VARS da PHP açısından içinde anahtar=değer çiftleri olan bir dizi-değişkendir; bu değişkenin değerlerine de tıpkı daha önce olduğu gibi erişiriz.

HTTP açısından GET ile POST’un tek farkı gelen değerlerin nerede nasıl tutuldueğundan ibaret değildir. GET yönteminde, bir Browser’ın sunucuya gönderebileceği verinin uzunluğu, Sunucunun ayarlarına bağlı olmak üzere, sınırlıdır. Oysa POST ile alacağımız veri miktarı, sadece sunucunun bulunduğu bilgisayarın sabit disk alanıyla sınırlıdır. (Tabiî bu günümüzde sınırsızdır, anlamına geliyor!) Bir başka fark, Browser’ın GET yoluyla gönderdiği verilerin (ve bu arada ziyaretçinin parola olarak yazdıklarında ekrana yıldız olarak çıkan metinler dahil) tümü, sunucuya, URL-kodlanmış metin olarak, Browser’ın URL adres hanesine de yazılmasıdır. Bir çok kullanıcı için bu bir güvensizlik belirtisi sayılır. Bu iki unsur Formlarımızda  metod olarak GET yerine POST kullanmanın daha yerinde olduğunu gösterir.

Tedbirli Web programcılığı, özellikle birden fazla tasarımcı ve programcının birlikte çalıştığı ve Formlarda hangi yöntemin tercih edildiğini bilmenin kolay olmadığı projelerde, Form bilgisi işleyen PHP programlarımızda Form’da hangi metod kullanılmış olursa olsun, işlyeyici programın iki duruma da elverişli olmasını sağlamaktır. Sözgelimi son yazdığımız Form işleme programımızı şöyle değiştirir ve formlar03c_isle.php adıyla kaydedersek, ve Form içeren HTML sayfasını bu programı veri gönderecek şekilde değiştirirsek (nasıl?), her iki metodla gönderilen verileri işleme yeteneğine sahip bir program elde etmiş oluruz.

<?php

$form_bilgisi = ( isset($HTTP_POST_VARS ) )

            ?  $HTTP_POST_VARS : $HTTP_GET_VARS;

                  foreach ($form_bilgisi as $anahtar=>$deger ) {

                  if ( gettype ($deger ) == “array” ) {

                        print (“$anahtar == <br>\n”);

                        foreach ( $deger as  $yeni_degerler )

                              print (“.. $yeni_degerler<br>”);

                              }

                  else {

                  print (“<b>$anahtar = $deger <br>\n”);

                  }

            }

?>

Form ile işlemciyi Birleştirelim

Şu ana kadar yaptığımız bütün Form örneklerinde, Form’un bulunduğu HTML sayfası ile bu Form’un göndereceği verileri işleyen PHP programı iki ayrı belge halinde idi. Bu, buradaki örneklerde olduğu gibi, ziyaretçinin verdiği bilgileri sadece Brıowser penceresine yazdıran bir eğitim çalışması için belki uygun; ama gerçek Web sitelerimizde ziyaretçilerimizin vereceği bilgileri çoğu zaman sadece onların Browser pencerelerinde göstermekle kalmayız, fakat bu bilgileri ya elektronik posta yoluyla kendimize yollarız, ya da sunucuda bir düzyazı veya veritabası dosyasına işleriz. Bu ve diğer amaçlarla yapacağımız Form içeren HTML sayfaları, aslında PHP programımızın bir içinde yer alabilir; ya da başka bir deyişle, Form’umuz ziyaretçinin vereceği bilgileri kendi bulunduğu PHP programına gönderebilir!

Bu karmaşık ifadeyi bir örnekle açalım. Yukarıda yaptığımız son HTML sayfası ile ve PHP programını şöyle birleştirelim; ve bunu formlar04.php adıyla kaydedelim:

<?php

if ( isset ( $HTTP_POST_VARS )) {

print (“<HTML>\n”);

print (“<HEAD>\n”);

print (“<TITLE>PHP’de Formlar</TITLE>\n”);

print (“<meta http-equiv=\”content-type\” content=\”text/html; charset=ISO-8859-9\”>\n”);

print (“<meta http-equiv=\”Content-Type\” content=\”text/html; charset=windows-1254\”>\n”);

print (“</HEAD>\n”);

print (“<BODY>\n”);

            foreach ($HTTP_POST_VARS as $anahtar=>$deger ) {

                  if ( gettype ($deger ) == “array” ) {

                        print (“$anahtar == <br>\n”);

                        foreach ( $deger as  $yeni_degerler )

                              print (“.. $yeni_degerler<br>”);

                              }

                  else {

                  print (“<b>$anahtar = $deger <br>\n”);

                  }

            }

print (“</BODY>\n”);

print (“</HTML>\n”);

}

else {

print (“<HTML>\n”);

print (“<HEAD>\n”);

print (“<TITLE>PHP’de Formlar</TITLE>\n”);

print (“<meta http-equiv=\”content-type\” content=\”text/html; charset=ISO-8859-9\”>\n”);

print (“<meta http-equiv=\”Content-Type\” content=\”text/html; charset=windows-1254\”>\n”);

print (“</HEAD>\n”);

print (“<BODY>\n”);

print (“<FORM ACTION=\”$PHP_SELF\” METHOD=\”POST\”>\n”);

print (” Adınız, Soyadınız: <INPUT TYPE=\”TEXT\” NAME=\”adi\”>\n”);

print (“<BR>\n”);

print (” Elektronik Adresiniz: <INPUT TYPE=\”TEXT\” NAME=\”adres\”>\n”);

print (“<BR>\n”);

print (” Hangi notunuzu öğrenmek istiyorsunuz? \n”);

print (“<BR>\n”);

print (“<SELECT NAME=\”hangi_not[]\” MULTIPLE>\n”);

print (“<OPTION>Sınav 1 \n”);

print (“<OPTION>Sınav 2 \n”);

print (“<OPTION>Ortalama \n”);

print (“</SELECT>\n”);

print (“<BR>\n”);

print (“<INPUT TYPE=\”SUBMIT\” VALUE=\”Gönder Gitsin!\”>\n”);

print (“<INPUT TYPE=\”RESET\” VALUE=\”Vazgeç, Gönderme!\”>\n”);

print (“</FORM>\n”);

print (“</BODY>\n”);

print (“</HTML>\n”);

}

?>

Bu dosyanın tümüyle PHP programı olduğuna dikkat ettiniz, tabiî? Program açıldığında sunucunun $HTTP_POST_VARS dizi-değişkeninin bir değer içerip içermediğini  bir if deyiminin içinden bir değişkenin içeriği olup olmadığını anlamamıza yarayan isset () fonksiyonu ile yapıyoruz. Bu şart doğru ise, yani $HTTP_POST_VARS dizi-değişkeni bir değer içeriyorsa, program, foreach döngüsünün içinde bu değişkenin içindekileri almaya ve Broüwser penceresinde görüntülemeye başlıyor. Bu şart doğru değilse, yani $HTTP_POST_VARS dizi-değişkeni henüz bir değer içermiyorsa, if deyiminin birinci bölümünü içindeki hiç bir kod icra edilmiyor ve prgram else deyimine sıçrıyor. Programın else bölümü ise daha önceki HTML kodlarımızı içeren bir dizi print() fonksiyonu yerine getiriyor; yani Browser’a içinde Form bulunan HTML sayfasını yazdırıyor. Burada FORM etiketine dikkat edelim:

print (“<FORM ACTION=\”$PHP_SELF\”METHOD=\”POST\”>”);

Form’un ACTION parametresinde bir PHP programının adı yerine “$PHP_SELF” değişken adını görüyoruz. Bu, bu bölümün başında ele aldığımız gibi, sunucunun bu PHP programına sağladığı çevre değişkenlerinden biridir ve o anda çalışmakta olan PHP programının dosya adını içerir. (Bizim örneğimizde bu değişkenin değeri nedir?)

/////////////////KUTU/////////////////

Dosya “çıkartma”

Internet’ten hep dosya “indiririz!” Bir sunucuya, Web ziyaretçisi olarak gönderebildiğimiz tek şey ise, Formlara yazdığımız yazılardır! Oysa HTML’in INPUT INPUT etiketinin çok az kullanılan TYPE=”file” parametresi ziyaretçiye Web sunucusuna dosya gönderme (upload) imkanı sağlar. HTTP protokolü buna imkan vermekle birlikte Browser’lar bu imkanı kullanmaya ileri sürümlerinde kavuştular. PHP4, ziyaretçilerimizin sitemize dosya göndermeleri halinde, bu dosyaların yönetimine ayrıca kolaylık sağlayan değişkenlere sahiptir.  Önce şu dosyayı, dosya_gonder.php adıyla kaydedin:

<HTML>

<HEAD>

<TITLE>PHP’de Dosya Gönderme</TITLE>

<meta http-equiv=\”content-type\” content=\”text/html; charset=ISO-8859-9\”>

<meta http-equiv=\”Content-Type\” content=\”text/html; charset=windows-1254\”>

</HEAD>

<?php

$dosya_dizin = “/inetpub/wwwroot/”;

$dosya_url = “http://server/”;

if ( isset ( $dosya_gonder )) {

    print (“<b>Yol:</b> $dosya_gonder<br>\n”);

    print (“<b>Adı:</b> $dosya_gonder_name<br>\n”);

    print (“<b>Boyut:</b> $dosya_gonder_size<br>\n”);

    print (“<b>Tür:</b> $dosya_gonder_type<br>\n”);

    copy ( $dosya_gonder, “$dosya_dizin/$dosya_gonder_name” )or die (“Dosya kopyalanamıyor!”);

      if ( $dosya_gonder_type == “image/gif” ||$dosya_gonder_type == “image/pjpeg”  ) {

      print (“<img src=\”$dosya_url/$dosya_gonder_name\”><p>\n\n”);

      }

}

?>

</BODY>

<FORM  ENCTYPE=”multipart/form-data” ACTION=”<?php print $PHP_SELF?>” METHOD=”POST”>

<INPUT TYPE=”hidden” NAME=”MAX_FILE_SIZE” VALUE=”951200″>

<INPUT TYPE=”file” NAME=”dosya_gonder”><BR>

<INPUT TYPE=”SUBMIT” VALUE=”Dosya Yolla!”>

</FORM>

</BODY>

</HTML>

Bu programda <INPUT TYPE=”file” NAME=”dosya_gonder”> etiketinde kullandığımız NAME parametresine verdiğimiz değer, ziyaretçimizin göndereceği dosyanın sunucu tarafından kaydedileceği geçici dizinin tam yolunun yazılacağı değişkenin adı olacakdır. PHP, bu dosya ile ilgili her türlü bilgiyi bu adla kaydedektir. PHP, ziyaretçiden bir dosya başarıyla aktarıldığı anda otomatik olarak bu isimden yararlanarak şu değişkenleri oluşturur:

$dosya_gonder                           Geçici kayıt dizini yolu (UNIX’te /tmp/phpXXX, Windows’da Windows/TEMP0phpXXX. Burada XXX yerine ziyaretçilerin gönderdiği dosyaların sıra numarasını göreceksiniz.)

$dosya_gonder_name                 Ziyaretçinin gönderdiği dosyanın adı.

$dosya_gonder_size                   Ziyaretçinin gönderdiği dosyanın boyutu.

$dosya_gonder_type                  Ziyaretçinin gönderdiği dosyanın türü

PHP ayrıca bu bilgileri $HTTP_POST_FILES dizi-değişkeninde de tutar.

Yukardaki programda şu iki değişken çok önemlidir:

$dosya_dizin = “/inetpub/wwwroot/”;

$dosya_url = “http://server/”;

$dosya_dizin adıyla oluşturduğumuz değişkene vereceğimiz değer, ziyaretçinin göndereceği dosyanın kopyalanacağı klasörün adı olarak kullanlacaktır. Sözgelimi Windows ortamında buraya kişisel Web sunucunun varsayılan klasörünün adını yazabilirsiniz. Ziyaretçinin göndereceği dosya bir GIF biçiminde grafik dosyası ise bunu Browser’da görünteleyeceğimiz için, bu dizinin Web’e açık olması, başka bir deyişle bizim Web sunucumuzun erişebileceği bir dizin olması gerekir. Nitekim, $dosya_url değişkenine değer olarak bu klasörün URL adresini veriyoruz. Bu iki değişkeni gerçek Web sunucu için yazacağımız zaman, bizim sunucumuzun varnaydığı fiziksel klasör adını ve yolunu bulmamız gerekir. Bunu daha önce yazdığımız php.php veya formlar01.php programlarını sitemizde çalıştırarak bulabiliriz. (Nasıl?) Sözgelimi, http://www.mycgiserver.com/~ocal/ adresindeki sitenin fiziksel adresi ile bu adresin URL’ini dikkate alarak bu iki değişkeni yazmış olsaydık, şunu yazacaktık:

$dosya_dizin = “/wwwroot/mycgiserver.com/members/uNhM13/”;

$dosya_url = “http://www.mycgiserver.com/~ocal/”;

Bu uygulamayı kendi sunucunuzda yapmak isterseniz, mutlaka bu iki değişkeni doğru yazmanız gerekir. http://www.mycgiserver.com/~ocal/ dosya_gonder_server.php programı ile bir dosya gönderme (upload) işleminin sonucu şöyle:

<php00025.tif>

//////////////////KUTU BITTI//////////

Dosya İşlemleri

Web programıcısı olarak ziyaretçinin bize göndereceği bilgileri yakalamayı öğrendik. Şimdilik sadece ziyaretçinin Browser’ına geri gönderdiğimiz bu bilgileri, sunucu tarafından çeşitli işlemlerde kullanabiliriz. Bu işlemlerin başında dosya girdi/çıktı işlemleri gelir. Başka bir ifade ile ziyaretçiden aldığımız bu bilgileri sunucuda bir dosyaya yazdırabiliriz. Bu bölümde PHP ile sunucuda yapabileceğimiz dosya işlemlerine bakacağız. Tabiî dosya işlemleri dendiğinde sadece ziyaretçiden aldığımız bilgileri bir dosyaya yazdırmakla yetinmeyeceğiz; PHP programlarımıza sunucuda bir dosyada bulunan bilgileri okumasını da öğreteceğiz.

Harici Dosya (include)

PHP programlarımızda bilmemiz gereken ilk dosya işlemi, bir PHP programına, kendi dışındaki dosyayı, tabir yerinde ise, okutmak ve içindekileri aynen alıp, görüntülemesini sağlamaktır. Bunu include komutu ile yaparız. Bu komut, kendisine adı verilen düzyazı dosyasının içeriğini aynen bu komutun bulunduğu noktaya “yazar.” Bu yolla bir PHP programına sık kullandığınız bir metni veya program parçasını dahil edebilirsiniz. Bir güvenlik önlemi olarak bu tür dosyaların uzantılarını, sunucu ve Browser’ların tanıdğı MIME türlerine ait uzantılardan farklı yaparsanız, ziyaretçiler şans eseri de olsa bu dosyaları doğruca edinme imkanı bulamazlar. Bir örnek yapalım. Önce şu metni, harici_dosya01.x adıyla ve düzyazı biçiminde kaydedin (Windows ortamında Notepad’i kullanıyorsanız, dosya adı uzatması olarak .x harfinden sonra .txt harflerini eklediğine dikkat edin!):

“Ben harici bir dosyanın içindeki yazıyım.. Beni bir PHP programı alıp buraya getirdi! Kendisine teşekkür ederim”

Sonra, şu programı dosya_ekle01.php adıyla kaydedin, ve Browser’da açın:

<HTML>

<HEAD>

<TITLE>PHP’de Harici Dosya Ekleme</TITLE>

<meta http-equiv=\”content-type\” content=\”text/html; charset=ISO-8859-9\”>

<meta http-equiv=\”Content-Type\” content=\”text/html; charset=windows-1254\”>

</HEAD>

<?php

include (“harici_dosya01.x”);

print (“\n<p> Ben zaten bu programının içinde olan bir yazıyım. Baştan beri burada olduğuma çok memnununum.. Harici dosyaya hoşgeldin diyorum!</p>”);

?>

</BODY>

</BODY>

</HTML>

Buradaki include komutu biraz önce yazdığımız harici dosyayı alacak, içeriğini aynen kendi bulunduğu noktada, PHP’nin oluşturacağı HTML dosyasına katacaktır. Bu programı çalıştırdığınızda görüntü şöyle olacaktır:

<php00026.tif>

Bu görüntüyü aldığınız sırada Browser’ınızda kaynağı görüntülerseniz, iki metnin adeta birleştirilmiş olduğunu göreceksiniz. Fakat dışardan PHP programına sadece düz metin eklemeyiz; program veya fonksiyon da ekleyebiliriz. Harici dosyada şu değişikliği yaparak, harici_dosya02.x adıyla kaydedin.

<?php

print (“Ben de harici dosyayım.!<br>”);

print (“Ama ben hesap da yaparım.. Örneğin iki iki daha “. (2 + 2). ” eder!”);

?>

Haricî dosya okuyan programı da programı içinde, okunacak dosya adını düzelttikten sonra dosya_ekle02.php adıyla kaydedin; ve çalıştırın.

<php00027.tif>

Haricî dosyamızda yer alan …iki iki daha “. (2 + 2). ” eder!”); şeklindeki ifadenin programa gelirken “..iki iki daha 4 eder!” şekline gelmesinin izahı, PHP’nin dışarıdan aldığı dosyanın içinde PHP programı olduğunu gördüğü anda, bu dosyanın içeriğini metin olarak değil, program olarak ele almasıdır. Bu yolla, PHP programlarımıza bir değerin dönmesini de sağlayabiliriz. Haricî dosyamızda şu değişikliği yapalım ve harici_dosya03.x adıyla kaydedelim:

 <?php

$sonuc = ( 2 + 2 );

return $sonuc;

?>

Bu satır bakalım programa dahil olacak mı?

Sonra, program metninde şu değişlikliği yaparak, dosya_ekle03.php adıyla kaydedin ve çalıştırın:

<?php

$donen_sonuc = include(“harici_dosya03.x”);

print (“\n<p> Harici dosyadan dönen sonuç: $donen_sonuc </p>”);

?>

<php00028.tif>

Haricî dosyamızın içindeki program, return komutu ile sadece kendi içinde elde ettiği sonucu, onu çağıran programa verdi; ve bu sonucu alan programımız, sadece kendi içindeki bir değişkenin değerini Browser’a gönderdiği halde, bu değer haricî dosyadan alınmış oldu.

Haricî dosyaların include yoluyla PHP programlarımıza katılması, özellikle bir sitenin bir çok programında sık sık kullanılan metinlerin ve hesaplamaların bir kere yazılmasını ve tek satırla çağrılmasını sağladığı için kolaylık sağlar ve hata ihtimalini azaltır.

//////////////KUTU//////////////

include mu, require mı?

PHP4.0 ile, include komutu gibi işleyen ancak ondan farklı olarak kendisini çağıran programa değer veremeyen require komutu da kullanılabilir hale geldi. İçinde bir hesaplama bulunmayan veya kendisini çağıran dosyaya bir return komutu ile bir değer dönmesini sağlaması beklenmeyen dosyaları require komutu ile de ana programımıza dahil edebiliriz.

/////////////////KUTU BİTTİ//////////

include ile alacağımız dosyaların adını PHP programının oluşturmasını sağlayarak kimi zaman pogramlarımıza dinamizm sağlamamız mümkündür. Sözgelimi bir menü maddesinin tıklanmasıyla harekete geçen bir Javascript fonksiyonunun, ziyaretçinin gideceği sayfaya göndereceği değeri include komutuna dosya adı oluşturmakta kullanabiliriz. Bazen include komutuna dosya adı oluşturmakta program içindeki döngülerden yararlanınız. Örnek:

for ( $i = 1 ; $i <= 3 ; ++$i) {

            include (“dosya0” . $i . “.x”);

            }

Haricî dosyalarımızın adlarının dosya01.x, dosya02.x ve dosya03.x olmalı halinde, bu döngü sırasıyla her üç dosyayı da çağıracak ve altalta ana programa dahil edecektir.

Dosyalar hakkında bilgi

PHP’de yukarıda ele aldığımız include ve require komutları ve biraz sonra değineceğimiz dosya okutma ve yazdırma işlemleri dolayısıyla bir dosyanın varlığı veya yokluğu, ya da bir dosyaya ait sandığımız ismin bid klasöre ait olması, programımızın sağlıklı işleyebilmesi açısından büyük önem taşır. PHP bu amaçla bize bir kaç kullanıma hazır fonksiyon sağlıyor. Burada kısaca bu fonksiyonlara ve nasıl kullanıldıklarına değinelim:

Dosya var mı? file_exits()

Bir dosyanın var olup olmadığını denetleyen bu fonksiyon, dosya varsa true/doğru, yoksa false/yanlış sonucunu verir. Örnek:

if ( file_exits ( “bir_dosya.txt” ) )

print (“Dosya var!”);

Dosya yoksa, program “Dosya var!” yazmadan yoluna devam edecektir.

Dosya mı, dizin mi? is_file() ve is_dir()

Kimi zaman klasörler de tıpkı dosyalar gibi adlandırılabilir. Bir dizinde gördüğümüz ismin gerçekten bir dosyaya ait olup olmadığını bu fonksiyonla sınarız. Sınama doğru, yani isim bir dosyaya ait ise fonksiyon true/doğru, değilse false/yanlış sonuç verir. Örnek:

if ( is_file ( “bir_dosya.txt” ) )

print (“Bu bir dosyadır!”);

İsim bir dosyaya ait değilse program “Bu bir dosyadır!” yazmadan yoluna devam edecektir. Sınamayı ismin bir klasöre ait ait olup olmadığına bakrarak da yaparız. Bu durumda is_dir() fonksiyonunu kullanırız. isim bir dizine aitse fonksiyon true/doğru, değilse false/yanlış sonuç verir. Örnek:

if ( is_dir ( “/bir_isim” ) )

print (“Bu bir dizindir!”);

İsim bir dizine ait değilse program “Bu bir dizindir!” yazmadan yoluna devam edecektir.

Dosya okunabilir mi? is_readable()

Programda kullanmaya karar vermeden önce bir dosyanın erişilebilir ve PHP tarafından okunabilir olup olmadığını sınayan bu fonksiyon, dosya okunabilir ise true/doğru, değilse false/yanlış sonuç verir. Örnek:

if ( is_readable ( “bir_dosya.txt” ) )

print (“Bu dosya okunabilir!”);

Dosya okunabilir değilse program “Bu dosya okunabilir!” yazmadan yoluna devam edecektir. (Unix ortamında varlığını görebildiğimiz her dosyanın okuma izni bulunmayabilir.)

Dosya yazılabilir mi? is_writable()

Programda kullanmaya karar vermeden önce bir dosyanın yazılabilir olup olmadığını sınayan bu fonksiyon, dosya yazılabilir ise true/doğru, değilse false/yanlış sonuç verir. Örnek:

if ( is_writable ( “bir_dosya.txt” ) )

print (“Bu dosyaya yazılabilir!”);

Dosya yazılabilir değilse program “Bu dosyaya yazılabilir!” yazmadan yoluna devam edecektir. (Unix ortamında varlığını görebildiğimiz hatta okuyabildiğimiz her dosyanın yazma izni bulunmayabilir.)

Dosya çalıştırılabilir mi? is_executable()

PHP programında kimi zaman sunucunun kullanmamıza izin verdiği haricî programları çalıştırız; PHP programımızın düzgün işlemesi bu harici programa bağlı olabilir. Böyle bir programı çalıştırmaya karar vermeden önce bir dosyanın çalıştırılabilir olup olmadığını sınayan bu fonksiyon, dosya çalıştırılabilir ise true/doğru, değilse false/yanlış sonuç verir. Örnek:

if ( is_executable ( “bir_dosya” ) )

print (“Bu dosya çalıştırılabilir!”);

Dosya çalıştırılabilir bir program değilse PHP programı “Bu dosya çalıştırılabilir!” yazmadan yoluna devam edecektir. (Unix ortamında varlığını görebildiğimiz her pprogram dosyasının çalıştırma izni bulunmayabilir.)

Dosya boyutu: filesize()

Adını verdiğimiz dosyanın boyutunu byte olarak bildirir: Örnek:

print (“Dosyanın boyutu:”);

print filesize( “bir_dosya.txt” );

Dosyaya son erişim tarihi: fileadate(), filemtime() ve filectime()

Adını verdiğimiz dosyaya son erişim tarihini bildirir. ne var ki bu bilgi Unix’in “epoch” biçimindedir: Örnek:

print (“Dosyanın son erişim tarihi:”);

$dosya_tarihi = fileadate( “bir_dosya.txt” );

print ( ” $dosya_tarihi ” );

Eğer bu dosyanın son erişim tarihi 28 Temmuz 2000, Cuma 24:00:00 ise, PHP, Browser penceresine 964731600 yazacaktır. Bu komutun ürettiği bilgiyi, date() fonksiyonu ile anlaşılabilir hale getirebiliriz:

print (“Dosyanın son erişim tarihi:”);

$dosya_tarihi = fileadate( “bir_dosya.txt” );

print date(“D d M Y G:i:s H”, $dosya_tarihi );

Bu kez PHP Browser penceresine 28 Jul 2000 242:00:00 00  yazdıracaktır. Tarih verilerinin date() fonksiyonu ile biçimlendirilmesini daha sonra ayrıntılı ele alacağız.

filemtime(), bir dosyanın son değiştirildiği tarihi; filectime(), ise oluşturulduğu tarihi, yine Unix Epoch biçiminde bildirir; bu verinin anlaşılır biçimde görüntülenmesi için PHP’nin date() fonksiyonu kullanılır.

Dosyalar oluşturma ve silme

PHP ile yapabileceğimiz önemli dosya işlemlerinin başında olmayan bir dosyayı oluşturmak ve olan bir dosyayı silmek gelir. PHP’nin dosya oluşturma komutu touch() fonksiyonudur. Bu fonksiyona oluşturulmasıın istediğimiz dosyanın adını vermemiz gerekir. Örnek:

<?php

$dosya_dizin = “/inetpub/wwwroot/”;

                  touch (“$dosya_dizin/yeni_belge.txt”);

print (“yeni_belge adlı bir dosya oluşturuldu!”);

?>

</BODY>

</HTML>

Bu programı kişisel Web sunucuda denerken yeni dosyanın oluşturulacağı dizin olarak “/” işaretiyle sadece kökdizini belirtirseniz, dosya C: diskinde kökdizinde oluşturulur. Bu programı gerçek sunucuda çalıştırabilmek için yazma/okuma izni bulunan ve Web sunucunun erişebileceği bir dizinin adını vermeniz gerekir. Örneğin:

<?php

$dosya_dizin = “/wwwroot/mycgiserver.com/members/uNhM13Qnm/”;

touch (“$dosya_dizin/yeni_belge.txt”);

print (“yeni_belge adlı bir dosya oluşturuldu!”);

?>

Bu komutla oluşturacağınız dosya içi boş bir metin dosyası olacaktır. Eğer belirttiğiniz dizinde bu adı taşıyan bir dosya varsa, PHP dosyanın içeriğine dokunmayacak, fakat dosyanın erişim ve değişim tarihlerini  değiştirecektir.

PHP ile mevcut bir dosyayı silmek için unlink() fonksiyonunu kullanırız. Bu fonksiyon da silinecek dosyanın adı ile birlikte yolunu ister. Örnek:

<?php

$dosya_dizin = “/wwwroot/mycgiserver.com/members/uNhM13Qnm/”;

unlink (“$dosya_dizin/yeni_belge.txt”);

print (“yeni_belge adlı dosya silindi!”);

?>

Bu komut Windows sistemlerinde işlemeyebilir.

Dosya açma

PHP’de bir dosyanın içeriğini alarak sayfalarımızda kullanma veya bir dosyanın içeriğini değiştirmek gibi işlemler için önce dosyanın açılmış olması gerekir. Bunu gerçekleştiren fopen() fonksiyonudur. Bu fonksiyonla bir dosyayı okumak (‘r’), yazdırmak (‘w’) veya ek yapmak (‘a’) için açabiliriz. Bu fonksiyon dosyanın başarıyla açılması halinde bir tamsayı verecektir. PHP programlarımızda, açılan dosyanın mutlata ona işaret eden bir değişkene (file pointer) bağlı olması gerekir; daha sonra bu dosya ile ilgili bütün işlemleri bu işaret değişkeni ile yaparız. Örnek:

$dosya = fopen( “bir_dosya.txt” , ‘r’ );

PHP, bu dosyayı sadece okumak amacıyla açacak ve fonksiyondan dönen değeri $dosya değişkenine atayacaktır. Olmayan bir dosyayı açmak istediğimiz zaman PHP hata mesajı verir. Bir dosyayı yazmak amacıyla açacağımız zaman, bu kodu şöyle yazarız:

$dosya = fopen( “bir_dosya.txt” , ‘w’ );

Olmayan bir dosyayı yazmak amacıyla açmak istediğimizde PHP önce bu dosyayı oluşturur. Bir dosyaya ek yapmak istediğimiz zaman ise kodumuz şu şekilde yazılır:

$dosya = fopen( “bir_dosya.txt” , ‘a’ );

Olmayan bir dosyayı ek yapmak amacıyla açmak istediğimizde PHP hata mesajı verir.

//////////////////KUTU///////////////

Bir Fonksiyonu durdurmak için: Öl!

Bir PHP fonksiyonunun kendisinden beklenen işi yapamaması halinde oracıkta durdurulmasını die() komutu sağlar. “Öl!” anlamına gelen bu fonksiyona ekranda görüntülenmesini istediğimiz bir metni parametre olarak verebiliriz. Bu bölümdeki örnekler bu komutla birlikte şöyle yazılabilir:

$dosya = fopen( “bir_dosya.txt” , ‘a’ ) or die (“Dosya açılamıyor!”) ;

////////////////////KUTU BİTTİ//////////////

Bu komutu kişisel Web sunucusunda denerken, dosyanın açılacağı dizinin yolunu belirtmemiz gerekir. Örneğin:

<?php

$dosya_dizin = “/inetpub/wwwroot/”;

if ($dosya = (fopen (“$dosya_dizin/bir_dosya.txt” , ‘r’) ) ) {

            print (“Dosya açıldı!”);

            }

            else {

            print (“Dosya açılamadı!”);

            }

?>

PHP, bu dosyayı açtığında Browser penceresinde dosyanın açıldığını belirten mesajı görüntülecektir. Bu işlemi Internet’teki bir Web sunucuda uygulayabilmek için yazma/okuma izni bulunan ve Web sunucunun erişebileceği bir dizinin adını vermeniz gerekir. Örneğin:

<?php

$dosya_dizin = “/wwwroot/mycgiserver.com/members/uNhM13Qnm/”;

if ($dosya = (fopen (“$dosya_dizin/bir_dosya.txt” , ‘r’) ) ) {

            print (“Dosya açıldı!”);

            }

            else {

            print (“Dosya açılamadı!”);

            }

?>

Açtığımız bir dosya ile yaptığımız bütün işlemler bittikten sonra, dosyanın kapatılması gerekir. Dosya kapatma işlemini fclose() fonksiyonu yapar. Bu fonksiyona parametre olarak dosya adını değil, dosyanın işaretçisi olan değişkenin adını veririz. Örnek:

fclose  ( $dosya );

Dosya okuma: fgets(), fread() ve fgetc()

Açtığımız bir dosyanın içindeki yazıları çoğu zaman programımıza satır satır okuturuz. PHP’de bir dosyanın içeriğini satır satır okutmamızı fgets() fonksiyonu sağlar. Bu fonksiyona daha önce açılmış olan dosyanın işaret değişkenin adını ve okunmasını istediğimiz asgari byte ölçüsünü parametre olarak veririz. fgets() fonksiyonu verdiğimiz uzunluk ölçüsüne ulaşmadan önce dosyada bir yeni satır işareti görürse, veya dosyanın sonuna ulaşırsa, okumaya son verir. Bu fonksiyonu çoğu zaman bir döngünün içinde kullanırız. Ancak döngünün hata vermemesi için, PHP’nin dosyanın sonuna ulaştığında döngüyü durdurmamız gerekir. fgets() fonksiyonunun okuyacağı satırı bir fonksiyona değer olarak verebilir ve daha sonra bu değeri programlarımızda kullanabiliriz. Örnek:

<?php

$dosya_dizin = “/inetpub/wwwroot/”;

if ($dosya = (fopen (“$dosya_dizin/bir_dosya.txt” , ‘r’) ) ) {

            print (“Dosya açıldı!<br>”);

            }

            else {

            print (“Dosya açılamadı!”);

            }

while ( ! feof  ($dosya ) ) {

            $satir = fgets ( $dosya, 1024 ) ;

            print (“$satir<br>”);

            }

fclose ($dosya);

?>

Bu program kişisel Web sunucuda önce varolan bir dosyayı açıyor; ve bu dosyanın işaretçisi olarak $dosya değişkenini kullanıyor. Daha sonra bir while() döngüsü içinde  bu değişkeni ve 1 KB (1024 byte) ölçüsünü parametre olarak vererek fgets() fonksiyonu ile dosyadan bir satır okutuyoruz. fgets() fonksiyonundan dönen bir satırlık metni, burada $satir değişkenine atıyoruz; ve daha sonra print() fonksiyonu ile bu satırı Browser penceresine gönderiyoruz. Bu işlemi Internet’teki bir Web sunucuda uygulayabilmek için yazma/okuma izni bulunan ve Web sunucunun erişebileceği bir dizinin adını vermeniz gerekir. Bu işlemin içinde yapıldığı while() döngüsünün devam şartı olarak kullandığımız ifadede yer alan feof() fonksiyonu bir dosyanın dosya-sonu (end-of-file) durumuna ulaşıp ulaşmadığını sınar. PHP, her dosyanın sonunda yer alan eof  (Ctrl-z, ^z) işaretine eriştiği anda feof() fonksiyonu doğru/true değerini verir. while() döngüsü, feof() doğru değilken devam etmek üzere kurulmuş olduğu için, dosya sonuna ulaştığımızda döngü duracaktır. Okuma işlemini durabilen bir döngüye bağlamazsak, fgets() PHP’nin bir programın sona ermesi için verilmiş varsayılan süresi doluncaya kadar dosyayı okumak isteyecektir.

Kimi zaman dosyalarımızın içeriğini satır-satır okutmak yerine, kendi tayin edeceğimiz uzunlakta parçalar halinde okutmak isteriz. Bunu, fread() fonksiyonu ile sağlarız. Örnek:

<?php

$dosya_dizin = “/inetpub/wwwroot/”;

if ($dosya = (fopen (“$dosya_dizin/bir_dosya.txt” , ‘r’) ) ) {

            print (“Dosya açıldı!<br>”);

            }

            else {

            print (“Dosya açılamadı!”);

            }

while ( ! feof ($dosya) ) {

            $paragraf = fread ( $dosya, 1024 ) ;

            print (“$paragraf<br>”);

            }

fclose ($dosya);

?>

fread() fonksiyonu da daha önce açılmış olan dosyanın işaret değişkenin adını ve okunmasını istediğimiz asgari byte ölçüsünü parametre olarak alır. fread() fonksiyonu verdiğimiz uzunluk ölçüsüne ulaşmadan önce dosyada bir yeni satır işareti görürse, veya dosyanın sonuna ulaşırsa, okumaya son verir. Bu fonksiyondan yararlanırken, verdiğiniz uzunluk ölçüsünün, almak istediğiniz metin parçasına uygun olduğunu sınamalısınız. fread(), bu ölçüye ulaştığında okumayı keser. Buradaki örneği 1024 byte ölçüsünü değiştirerek ve mesela 1, 2, 3 yaparak deneyebilir ve böylece vereceğiniz ölçünün okunan metnin uzunluğunu nasıl tayin ettiğini görebilirsiniz.

//////////////////KUTU///////////////////

fseek() ile ölçü belirleme

PHP’nin dosya işleminde kullabileceğiniz bir diğer fonksiyonu fseek() adını taşır. Daha önce açılmış olan dosyanın işaret değişkenin adını ve ve programın bu metin içinde zıplamasını istediğiniz noktanın dosyanın başından itibaren byte değerini parametre olarak alan bu fonksiyon ile, bir dosyanın içinnde istediğimiz yere gitme imkanı vardır. Örnek:

<?php

$dosya_adi = “/inetpub/wwwroot/bir_dosya.txt”;

if ($dosya = (fopen ($dosya_adi , ‘r’) ) ) {

            print (“Dosya açıldı!<br>”);

            }

            else {

            print (“Dosya açılamadı!”);

            }

$dosya_boyut = filesize($dosya_adi);

$olcu = (int) ($dosya_boyut / 2 );

while ( ! feof ($dosya) ) {

            $paragraf = fread ( $dosya, $olcu) ;

            print (“$paragraf<br>”);

            }

fclose ($dosya);

?>

Burada, okutulacak dosyanın boyutunun yarısını atadığımız $olcu değişkenini, okutulacak metnin ölçüsü olarak kullanıyoruz. Bu durumda PHP, dosyayı iki paragraf halinde görüntüleyecektir.

/////////////////////KUTU BİTTİ///////////////

Dosyalarımızın içeriğini satırlar veya belirli ölçüde parçalar halinde değil de, tek-tek karakter olarak okutmak için fgetc() fonksiyonundan yararlanırız. Bu fonksiyon, daima 1 byte ölçüsünde (bir karakter) metin okuyabileceği için, parametre olarak sadece daha önce açılmış olan dosyanın işaret değişkenin adını alır. Örnek:

<?php

$dosya_adi = “/inetpub/wwwroot/bir_dosya.txt”;

if ($dosya = (fopen ($dosya_adi , ‘r’) ) ) {

            print (“Dosya açıldı!<br>”);

            }

            else {

            print (“Dosya açılamadı!”);

            }

while ( ! feof ($dosya) ) {

            $karakter = fgetc ( $dosya ) ;

            print (“$karakter<br>”);

            }

fclose ($dosya);

?>

Burada fgetc() fonksiyonundan dönen değeri (yani dosyadan okunan bir karakteri), $karakter değişkenine atıyoruz ve daha sonra print() fonksiyonu ba karakteri  ve HTML’in satır bölme kodu olan <br> işaretini Browser penceresine gönderiyor. Programı bu şekliyle sınarsanız, dosyadaki metnin tek karakter olarak Browser penceresinin soluna dizildiğini göreceksiniz. Programı <br> kodunu silerek çalıştırırsanız, bu kez dosyadaki metinde var olan satır sonu işaretlerinin de kaldırıldığını ve metnin bir paragraf oülarak görüntülendiğıini görebilirsiniz.

Dosyaya yazma ve ek yapma: fwrite() ve fputs()

Bir dosyaya yazma veya ek yapma, PHP açısından aynı işlemdir; sadece dosyaların açılışında fark vardır. Hatırlayacaksınız, bir dosyayı yazmak amacıyla açmak için:

$dosya = fopen( “bir_dosya.txt” , ‘w’ ) or die (“Dosya açılamıyor!”) ;

ek amacıyla açmak için ise

$dosya = fopen( “bir_dosya.txt” , ‘a’ ) or die (“Dosya açılamıyor!”) ;

kodunu yazmamız gerekir. Dana sonra yapılacak yazma ve ekleme işlemlerinin farkı, ‘w’ parametresi ile açılan dosyaya yazma işlemi en başından başlar ve devam eder; ‘a’ parametresi  ile açaılan dosyaya yazma işlemi ise en sondan başlar ve devam eder.

PHP’nin bir dosyaya metin yazdırma fonksiyonları olan fwrite() ve fputs() aynı biçimde yazılır ve aynı işlevi yerine getirirler; aralarında kesinlikle fark yoktur. Örnek:

<?php

$dosya_adi = “/inetpub/wwwroot/bir_dosya.txt”;

$dosya = fopen ($dosya_adi , ‘w’) or die (“Dosya açılamadı!”);

$metin = “Bu satır dosyaya yazılacak: Merhaba Dünya!\n”;  

fwrite ( $dosya , $metin ) ;

fputs ( $dosya , “Bu satır ise sonradan eklenecek\n” ) ;

fclose ($dosya);

?>

Bu programı çalıştırdığınızda, bir_dosya.txt adlı dosyada mevcut bütün içerik silenecek ve yerini $metin değişkeninin içerdiği “Bu satır dosyaya yazılacak: Merhaba Dünya!” yazısı ile “Bu satır ise sonradan eklenecek” cümlesi alacaktır. Her iki metnin sonunda da yeni satır işareti bulunduğuna dikkat edin. Bu programda dosya açma kıomutundaki ‘w’ parametresini siler, yerine ‘a’ yazarsanız, bu metinlerin dosyanın içeriğine eklendiğini görebilirsiniz.

/////////////////////KUTU///////////////////

Kullanımdaki dosyayı kilitleyin!

Web sunucusundaki dosyalarımızla sadece bir kişi işlem yapıyor olsa idi, bir sorun olmazdı; ne var ki, bir Web sitesine aynı anda birden fazla kişi eriyebilir ve dosyalarla işlem yapan programları çalıştırıyor olabilir. Bu, PHP’nin dosya işlemlerine engel olabilir. Bu sebeple, işlem için açacağımız bir dosyayı, önce kilitlemek yerinde bir önlem sayılır. Bunu, flock() fonsiyonu ile yaparız; bu fonksiyona kilitlemek istediğimiz dosyanın işaret değişkeninin adını ve kilit türünü belirten endeks sayısını parametre olarak yazarız. Örnek:

<?php

$dosya_adi = “/inetpub/wwwroot/bir_dosya.txt”;

$dosya = fopen ($dosya_adi , ‘w’) or die (“Dosya açılamadı!”);

flock ( $dosya , 2); // dosyayı kilitle

$metin = “Bu satır dosyaya yazılacak: Merhaba Dünya!\n”;  

fwrite ( $dosya , $metin ) ;

fputs ( $dosya , “Bu satır ise sonradan eklenecek\n” ) ;

flock ( $dosya , 3); //dosyayı kilidini aç

fclose ($dosya);

?>

Bu fonksiyon ile kullanabileceğimiz endeks parametreleri şunlardır:

1                               Paylaşım            Diğer proseslerin dosyayı paylaşmalarına imkan verir

2                               Tam       Diğer proseslerin dosyaile işlem yapmasına engel olur

3                               Serbest  Dosyanın 1 veya 2 olan kilidini kaldırır

Bir dosya, herhangi bir PHP programı tarafından kilitlendiği anda, aynı dsyayı daha sonra kilitlemeye kalkan diğer programlar kendilerinden önce konulmuş kilide  saygı gösterirler.

////////////////KUTU BİTTİ/////////////////////

Dizinlerle İşlemler

PHP ile sunucuda, Web dizini olarak kullandığımız alanda yeni dizinler oluşturabiliriz, silebiliriz, ve bunlar hakkında bilgi edinebiliriz. Bu işlemleri Web sunucuda yapabilmek için Web dizininde okuma ve yazma izni bulunması gerekir.

Dizin içeriğini listeleme: opendir() ve readdir()

Belirttiğiniz bir dizindeki tüm dosya ve alt-dizin adlarını bir liste, hatta ilişkilendirilmiş hypertext (köprü, link) listesi olarak sunabilmek için önce dizini içeriğini okuyabilmek için opendir() fonksiyonu ile açmak, sonra da içindeki bilgileri readdir() fonksiyonu ile edinmek gerekir. readdir() fonksiyonu dizinin içindeki alt-dizin ve dosyaların adlarını sırayla, tek-tek okur. Bu fonksiyondan gelen bilgileri bir değişkene atayarak ve bir döngü içinde yazdırarak, dizin listesi çıkartabiliriz. Örnek

<?php

$dizin_adi = “./”;

$dizin = opendir ($dizin_adi);

while ( gettype ( $bilgi =  readdir( $dizin ) ) != boolean ) {

            if ( is_dir( “$dizin_adi/$bilgi” ) )

            print ” [Dizin] ” ;

            print (“<A href=\”$dizin_adi/$bilgi\”>$bilgi</A><br>\n”);

}

closedir ($dizin);

?>

Kişisel Web sunucuda sınama amacıyla çalıştırabilmek için dizin adı olarak bu dosyanın içinde bulunduğu dizini verebiliriz. opendir() fonksiyonu da okunmak amacıyla açacağı dizine işaret eden bilgiyi bir değişkene yazmak zorundadır; bu işaret değişkenine burada $dizin adını veriyoruz. $dizin değişkeninin işaret ettiği dizini okuyan readdir() fonksiyonundan dönen bilgileri ise $bilgi değişkenine yazıyoruz. readdir() fonksiyonu dizin bilgisini okumanının sonuna vardığında, bir dosya ve dizin adı yerine doğru veya yanlış şeklinde bir mantıksal (boolean) değer verecektir; buradaki while döngüsü $bilgi değişkeninin türünü gettype() fonksiyonu ile sürekli sınayarak, henüz dizin ve dosya adı edinildiği sırada bu bilgileri print() fonksiyonuna verecektir. Bu bilginin bir dizine ait olup olmadığını is_dir() fonksiyonu ile sınayan if döngüsü ise bilgi bir dizine aitse, bu bilgnin baştarafına “[Dizin]” kelimesini yazdıracaktır. (Bu programı geliştirerek, önce dizinleri, sonra dosyaları yazabilen biçime getirmek mümkündür. Bunun bir örneği bu kitapçığı örnek kod dosyaları arasında dizin_oku01a_server.php ve dizin_oku01a_pws.php aadıyla bulhabilirsiniz.)

Dizin oluşturma: mkdir()

PHP programlarımız gerektiğinde sunucunun yazma yetkisi verdiği Web’e açık kök ve alt-dizinlerde yeni dizinler oluşturabilir. Bunu, mkdir() fonksiyonu ile yaparız. Bu fonksiyona oluşturulacak dizinin adı ve 8 tabanlı (octal) sayı cinsinden ve önüne bir sıfır konarak dizinin okuma/yazma/çalıştırma izinlerini belirten parametre verilir. Örnek:

mkdir (“deneme”, 0777);

Burada yer alan 0777, bu dizinin herkes için okuma ve yazma izni olduğunu gösterir. Bu parametre sadece Unix işletim sisteminde çalışan sunucular için geçerlidir.

Dizin silme: rmdir()

PHP programlarımızda gerektiğinde sunucunun yazma yetkisi verdiği Web’e açık kök ve alt-dizinlerde mevcut dizinleri silebiliriz. Bunu, rmdir() fonksiyonu ile yaparız. Bu fonksiyona oluşturulacak dizinin adı parametre verilir. Örnek:

rmdir (“deneme”);

Bir Dosya İşlemi Örneği: Konuk Defteri

Böylece PHP ile “iş yapmak” için gerekli araçlarımıza bir yenisini ekledik. Artık PHP programlarımızdan sabit diskteki dosyalara ulaşmayı ve dosyalarla çalışmayı biliyoruz. Buraya kadar öğrendiklerimizi bir PHP programı üzerinde uygulayabiliriz. Bunun için birlikte bir konuk defteri yapalım.

Diyelim ki konuk defterimize sadeceziyaretçimizin adını, elektronik posta adresini ve kısa bir mesajını isteyeceğiz. Öyle bir sayfa yapalım ki; ziyaretçi bu sayfayı ilk kez açtığında, yani henüz Form’dan sunucuya bir veri gelmemiş dolayısıyla $HTTP_POST_VARS dizi değişkenin içinde değer bulunmadığı sırada, programımız bu durumu belirleyerek ziyaretçiye konuk defteri Form’nu sunmalı; ziyaretçi formu doldurup gönder düğmesini tıkladığı zaman programımız bir yandan ziyaretçinin gönderdiği bilgileri kendisine gösterir ve teşekkürlerimizi aktarırken, diğer yandan da bu bilgileri bir düzyazı programı girmeli. Bu sırada ziyaretçimize isterse defterimizdeki diğer mesajları okuma imkanı da sunabilmeliyiz. Biraz uzunca olan şu programı kd_01.php adıyla kaydedelim. (Bu dosyayı, kitapçığın örnek kodlar arasında bulabilirsiniz; fakat bu alıştırmayı bir düz yazı programı ile buradaki örnek ifadeler ve alan/değişken adlarını değiştirerek tekrar etmeniz yerine olur:

<?php

if ( isset ( $HTTP_POST_VARS )) {

// Form dolduruldmuş ise

echo (“

    <HTML>

    <HEAD>

    <TITLE>PHP’de Misafir Defteri</TITLE>

    <meta http-equiv=’content-type’ content=’text/html; charset=ISO-8859-9′>

    <meta http-equiv=’Content-Type’ content=’text/html; charset=windows-1254′>

    </HEAD>

    <BODY>

    <P><font size=’3′ class=’s4′ face=’Arial, Helvetica’>

    “);

Programımızın buraya kadar olan bölümü, if ile  $HTTP_POST_VARS dizi değişkeninde değer bulunup bulunmadığına ilişkin sınamanın olumlu sonuç vermesi halinde uygulanan bölümüne dahil. Burada dikkatini echo() fonksiyonu ile birden fazla satır yazdırdığımız çekmiş olmalı. echo(), fonksiyonuna Browser penceresine göndereceğimiz değerleri çift-tırnak içinde  yazacağımız için, HTML etiketlerinin çift-tırnak gerektiren etiketlerinde tek tırnak kullandığımıza dikkat edin. if sınavının olumlu sonucuna ilişkin bölümü yazmaya devam edelim:

$dosya_adi = “mesajlar.txt”;

if (file_exists(“$dosya_adi”)) {

      $yazilacak_dosya = fopen($dosya_adi,’a’);

      }

else {

      $yazilacak_dosya = fopen($dosya_adi,’w’);

      }

foreach ($HTTP_POST_VARS as $anahtar=>$deger ) {

       $yeni_anahtar = strtoupper($anahtar);

       print (“$yeni_anahtar: $deger<br>”);

       $metin = “$yeni_anahtar: $deger<br>”;

       fputs($yazilacak_dosya, $metin);

       }

       fputs($yazilacak_dosya, date(“D d M Y h:i:s”));

       fputs($yazilacak_dosya, “<br>\n”);

       fputs($yazilacak_dosya, “<center>

       <img src=’nokta.gif’ width=100% height=1 border=0></center>\n”);

fclose($yazilacak_dosya);

Konuk defteri programımızHTML için gerekli temel etiketleri ürettikten sonra bu bölümde veritabanı dosyası olarak kullandığımız mesajlar.txt isimli dosyanın bulunup bulunmadığını sınıyor; dosya varsa ek yapmak için (‘a’),dosya yoksa yazmak için (‘w’), dosyayı açıyoruz. Sonra, $HTTP_POST_VARS dizi-değişkenine Form’dan gelmiş olan anahtar=değer çiftlerinin her birini (yani, Browser’dan gelen örneğin “adi” değişkeni ve bunun değeri olan ismi) önce print() ile ziyaretçinin Browser’ına, sonra da fputs() ile biraz önce açtığımız veritabanı dosyasına yazdırıyoruz. Fakat burada bundan önce Form’dan küçük harf olarak gelen değişken adlarını (anahtarları) strtoupper() fonksiyonu ile büyük harfe çeviriyoruz.Şimdilik bu fonksiyonun üzerinde durmayın; biraz sonra metin düzenleme ve düzenli ifadeler konusuna geleceğiz. Ancak bu sırada ziyaretçilerin mesajlarını daha sonra güzel görüntelemek için aralarına çizgi olarak kullanmak üzere bir resim dosyasını IMG etiketi ile yerleştirdiğimize de dikkat edin. Bu grafik dısyasının eni-boyu 1 piksel olduğu halde burada ziyaretçinin Browser penceresinin eni kadar genişleterek çizgi üretmiş oluyoruz! Evet, koda devam:

echo (“

    <HTML>

    <HEAD>

    <TITLE>PHP’de Misafir defteri</TITLE>

    <meta http-equiv='”content-type’ content=’text/html; charset=ISO-8859-9′>

    <meta http-equiv=’Content-Type’ content=’text/html; charset=windows-1254′>

    </HEAD>

    <BODY>

    <P><font size=’3′ class=’s4′ face=’Arial, Helvetica’>

    <center><img src=’nokta.gif’ width=100% height=1 border=0></center>

    Sayın: $adi<br>

    Defterimi imzaladığınız için teşekkür ederim</P>

    <p>Ana Sayfaya Dönmek için <A HREF=\”index.htm\”> tıklayın</A><BR>

    Mesajları okumak için<A HREF=\”mesajlar.php\”> tıklayın</A>

    </BODY>

    </HTML>

    “);

}

Programımızın bu bölümünde, ziyaretçiye teşekkür ediyoruz; ve isterse diğer mesajları okumak üzere tıkllayacağı köprüyü sağlıyoruz. Mesajların çok uzaması halinde bu köprüyü bir sayfanın üstünde, bir de altında vermekte yarar var. Şimdi, programımızın Form doldurulduktan sonra işleyen bölümünü yazmış olduk. Taa en başta yaptığımız  $HTTP_POST_VARS dizi-değişkeninin değer içerip içermediğine ilişkin sınamanın olumsuz olması halinde, prıogramımız, işe buradan başlayacaktır:

else {

      echo (“

      <HTML>

      <HEAD>

      <TITLE>PHP’de Formlar</TITLE>

    <meta http-equiv='”content-type’ content=’text/html; charset=ISO-8859-9′>

    <meta http-equiv=’Content-Type’ content=’text/html; charset=windows-1254′>

      </HEAD>

      <BODY>

      <FORM ACTION=\”$PHP_SELF\” METHOD=\”POST\”>

      <P><font size=’3′ face=’verdana, Arial, Helvetica’>

      Defteri imzalamadan okumak için <a href=’mesajlar.php’>

      burayı tıklayın</a></FONT></P>

      <P><font size=’3′ face=’Arial, Helvetica’>

      Adınız, Soyadınız: <br><INPUT TYPE=\”TEXT\” NAME=\”adi\”><BR>

      Elektronik Adresiniz: <br><INPUT TYPE=\”TEXT\” NAME=\”adres\”><BR>

      Mesajınız:<BR>

      <TEXTAREA NAME=\”mesaj\” ROWS=10 COLS=30 WRAP=virtual></TEXTAREA>

      <BR><BR><BR>

      <INPUT TYPE=\”SUBMIT\” VALUE=\”Defteri imzala!\”>

      <INPUT TYPE=\”RESET\” VALUE=\”Tümünü sil!\”>

      </FORM>

      </BODY>

      </HTML>

      “);

}

?>

Bu bölümde çift-tırnak işaretlerini değiştirmek yerine, bunları ESC karakteri ile özel işaret değil, metin olarak ele alınacak hale getirdik. Programımız burada yine echo() ile düz ve basit bir HTML Formu oluşturuyor. Programın akış planını anlamış olmalısınız: ziyaretçi önce Form’u dolduracak ve gönder düğmesini tıklayacak.

<php00029.tif>

Bu ACTION, Form’da INPUT alanlarındaki değerleri POST yöntemiyle yine kendisine gönderecek; böylece PHP, programı yeniden çalıştırırken, bu kez en baştaki şartın yerine geldiğini (yani $HTTP_POST_VARS dizi-değişkeninin değer içerip içermediğine ilişkin sınamanın olumlu sonuç verdiğini) görerek, işe baştan baştan başlayacaktır. Bu, INPUT etiketinin alanlarından oluşturulan değişkenlerden yararlanarak, ziyaretçiye bize ulaştırdığı bilgileri ve bizim teşekkür mesajımızı yollamaktan ibarettir.

<php00030.tif>

Program bu şekliyle ne güvenlik önlemlerine sahip, yani kötüniyetli kişilerin INPUT alanlarına kötü niyetli kodlar yazmaları halinde bunları ayıklıyor; ne de ziyaretçinin boş Form gönderip göndermediğini sınıyor. Bu gibi işleri, PHP ile metin düzenlemeyi öğrendikten ve Düzenli İfadeler denen kavramı ile tanıştıktan sonra yapacağız.

Metin Düzenleme ve Düzenli İfadeler

Web programlarımızda bir ziyaretçinin bize ulaştırdığı Form bilgilerini ve bir veritabanı dosyasından aldığımız ham verileri yeniden düzenlememiz gerekir. PHP bunu yapabilmek için bize 50’den fazla fonksiyon sağlar. Bunlardan sık kullanmamız gerekenleri ele alacağız. Daha sonra, özellikle Unix işletim sistemine, Perl veya Javascript diline aşina olanların hatırlayacağı Düzenli İfadedeler denen metin ve sıralanış (pattern) eşleştirme araçlarının üzerinde duracağız. Bu iki araçla, elimize aldığımız berhangi metne istediğimiz biçimi vermek veya metnin içinden istediğimiz bölümü hemen hemen tamamen seçip biçimlendirmek ve kullanmak mümkün olur.

Temel Alfanümerik Fonksiyonları

PHP’nin metin olarak gördüğü değişkenlere alfanümerik (String) türü değişkenler adını vermiştik. PHP’nin alfanümerik fonksiyonları, bu tür değişkenlerin değerlerinin içinden bir bölümü alma, atma veya değiştirme imkanı sağlar. Programlarımızda sık kullanacağımız bir kaç fonksiyonu ele alalım. Bu fonksiyonların tam listesini bu kitapçığın örnek kodları arasında alfa_fonksiyonlar.htm adlı dosyada bulabilirsiniz. (Aşağıdaki örnekler de alfa_fonksiyonlarXX.php adlı dosyalarda bulunabilir.)

substr()

Bir alfanümerik değişkenin değerinin veya bir metnin tanımladığınız bölümünü verir. İkisi zorunlu, biri seçmeli üç parametre ile kullanılır. Yazılışı:

substr($degisken, başla, [boyut] );

Burada, $degisken yerine içinden bir bölümü seçmek istediğiniz metni tutan değişkenin adını; başla yerine seçme işleminin başlayacağı karakterin baştan itibaren kaçıncıdan sonra olduğunu ve isterseniz boyut yerine de seçilmesini istediğimiz karakter sayısını yazarız. Kaç karakter seçileceğini gösteren boyut parametresini yazmazsanız, PHP  değişkenin veya metnin sonuna kadar seçer. Örnek

$secilen = substr (“abcdef”, 1);

Burada $secilen değişkeninin değeri “bcdef” olacaktır; çünkü birinci karakterden sonra seçime başlatıyoruz ve seçimin boyutunu belirlemiyoruz. PHP, verdiğimiz metnin sonuna kadar seçecektir.

$degisken = “Olumsuz düşünce ve mekanizmalar üzerine olumlu şeyler bina edilemez!”;

$secilen = substr ($degisken, 8, 20);

Burada ise seçime 8’nci karakterden sonra başladığımız ve 20 karakterlik seçim yapılmasını belirttiğimiz için seçilen değer “düşünce ve mekanizma” olacaktır.

Başlanıç olarak verdiğiniz sayı negatif ise (önünde – işareti varsa) seçim işlemine değişkenin sonundan itibaren başlanır. Yukarıdaki substr() fonksiyonunu:

$secilen = substr($degisken, -9);

şeklinde yazarsak, dönen değer, “edilemez!” olacaktır.

trim()

Bir alfanümerik değişkenin değerinin baş ve son tarafındaki boşlukları atar. Yazılışı:

trim($degisken);

Bu fonksiyon değişken değerinin veya metnin başındaki ve sonundaki “\n”, “\r”, “\t”, “\v”, “\0”, ve aralık işaretini boşluk sayar.  Örnek:

$degisken = “\0   Olumsuz düşünce ve mekanizmalar üzerine olumlu şeyler bina edilemez!\n\r\t”;

$secilen = trim ($degisken);

Burada seçilen metinde, baştaki boşluk, sondaki yeni satır, satır başı ve sekme karakterleri olmayacaktır.

chr()

Parametre olarak ASCII değerini belirttiğimiz karakteri sağlar. Örnek:

echo (chr(34);

Bu komutla Browser penceresinde çift-tırnak işareti görüntülenir.

ord()

Parametre olarak yazdığınız karakterin ASCII değerini sağlar. Örnek:

echo (ord(“A”);

Bu komutla Browser penceresinde 65 rakamı görüntülenir. bu fonksiyonun başlıca kullanım alanı, bir değişkenin değerini arzu ettiğimiz bir karakterin ACSII koduyla karşılaştırmak olabilir. Örneğin:

if ( ord($karakter) ==  60 { // karakter “<” işareti ise

            $karakter = “” ;

            }

koduyla, bir Form’dan gelen verileri karakter-karakter sınayabilir ve içinde normal olarak bulunmaması gereken, zararlı kod parçası olması ihtimali bulunan karakterleri ayıklatabiliriz.

strlen()

Bir alfanümerik değişkenin değerinin kaç karakter içerdiğini bildirir. Yazılışı:

strlen($degisken);

Bu fonksiyondan dönen değer tam sayıdır; aritmetik işlemlerde kullanılabilir. Örneğin, ziyaretçinin bir INPUT alanına yazdığı yazının uzunluğunun arzu ettiğimiz ölçülere uygun olup olmadığını sınamakta bu fonksiyondan yararlanabiliriz:

if ( strlen($degisken) >  30 { // girilen değer 30 karakterden uzun ise

            echo (“Lütfen 30 karakterden uzun yazmayınız!);

            }

printf() ve sprintf()

Bu fonksiyonları bir değişkeni biçimlendirmekte kullanırız. Birincisinin elde ettiği sonuç ziyaretçinin Browser penceresine gönderilir; ikincisin elde ettiği sonuç ise değer olarak döner. Önce bu fonksiyonlarla kullanabileceğimiz biçim parametrelerini sıralayalım:

%                Yüzde işareti. Yanında biçim parametresi gerekmez.

b                 Değişken tamsayı olarak işlem görür ve ikili sayı olarak döner. 

c                 Değişken tamsayı olarak işlem görür ve ASCII değerinin karşılığı olan karakter olarak döner.

d                 Değişken tamsayı olarak işlem görür ve ondalık sayı olarak döner.

f                  Değişken kesirli  sayı olarak işlem görür ve  kesirli sayı olarak döner.

o                 Değişken tamsayı olarak işlem görür ve sekiz-tabanlı (octal) sayı olarak döner.

s                  Değişken alfanümerik olarak işlem görür ve alfanümerik olarak döner.

x                 Değişken tamsayı olarak işlem görür ve 16 tabanlı (hexadecimal) sayı olarak döner. (Harfler, küçük harf olur).

X                Değişken tamsayı olarak işlem görür ve 16 tabanlı (hexadecimal) sayı olarak döner. (Harfler, büyük harf olur).

Her iki fonksiyonun da kullanılış biçimi aynıdır:

printf( “biçim” , $degisken1, $degisken2, … “metin” );

Burada “biçim” yerine yukarıdaki biçim parametlerini yazarız. Biçim parametrelerinin önüne yüzde işareti konur; en fazla beş belirleyici özellik alabilir. Yukarıdaki tür belirten biçimlendirme parametlerine ek olarak diğer özellikler şöyle sıralanır:

Doldurma karakteri: tek tırnak ve onu izleyen bir karakterden oluşur.

Hizalama: Eksi işaretinin varalığı yazının sola, yokluğu ise sağa hizalanma anlamına gelir.

En az-en çok uzunluk: Sayı-nokta-sayı (örneğin 40.40 gibi) yazılır; birinci sayı azamî, ikinci sayı asgarî uzunluğu belirtir.

Bu üç özelliğe bir örnek verelim.Bir değişkenin değerinin sonuna yanyana yeteri kadar nokta konarak uzunluğunun 40 karaktere çıkartılmasını şu deyimle sağlarız:

$degisken = ” İyilik üzerine ” ;

printf( “%’.-40.40s” , $degisken);

Burada “%’.-40.40s” şeklindeki biçim komutu, Browser penceresinde şu görüntüyü oluşturur:

“İyilik üzerine……………………..”

Burada “İyilik üzerine” değeri 14 karakter olduğu için, sonuna  26 adet nokta eklenmiş ve bütün değer sola hizalanmış olacaktır. Şu komut ise iki değişkenin değerini ve vereceğimiz bir metni aynı satıra yazdıracaktır:

$degisken1 = ” İyilik üzerine ” ;

$degisken2 = ” İyilik üzerine ” ;

$metin = “<br>\n” ;

printf( “%’.-40.40s%’.2d%s” , $degisken1, $degisken2, $metin);

Bu komut Browser penceresinde şu görüntüyü oluşturur:

“İyilik üzerine……………………..86”

Burada eklediğimiz ikinci  “%’.2d” şeklineki biçim komutu ile, ikinci değişkenin değeri, en az sıfır en çok iki adet nokta ile doldurulmak ve sağa hizalanarak ondalık sayı olarak görüntülenmek üzere biçimlendiriliyor. Üçüncü biçim komutu olan “%s” ise üçüncü değişkenin sadece alfanümerik olarak muamele görmesini sağlıyor. Biçim komutlarının arasında boşluk bulunmaması, ait oldukları değişken değerlerinin de aralarına boşluk konmamasına sebep oluyor. Üçüncü değişkenin etkisini, kağıt üzerinde göremiyoruz; ancak bu Browser penceresinde bundan sonra gelecek unsurların bir satır aşağı kaymasını sağlayacaktır.

Dördüncü biçim özelliği, ondalık sayıların virgülden (veya nokdtadan) sonra ondalık bölümünün kaç hane olacağını belirler. Bunu da bir örnekle görelim:

$degisken = ” 124 ” ;

printf( “Değeri (ABD) $%.2f” , $degisken);

Bu biçimlendirme komutu da Browser penceresine şu yazıyı yazdırır:

Değeri (ABD) $124.00

number_format()

Türü sayı olan değişken değerlerini bin-basamakları şeklinde biçimlendirmekte kullanılır. Parametre olarak sayı içeren değişkenin adını, ondalık bölümün kaç haneli olacağını, ondalık hanesini ve binler basamaklarını ayırmakta kullanılacak karakteri kabul eder. Örnek:

$degisken = 1234567890.1234567890 ;

echo (number_format($degisken, 4 chr(44) , “.”) ); //chr(44)=virgül

Bu deyimle 1234567890.1234567890 şeklindeki değer, Browser penceresine “1.234.567.890,1235” şeklinde yazdırılacaktır.

Tarih ve Saat Düzenleme

PHP’nin tarih ve zaman bilgisini kullanmamızı sağlayan getdate() fonksiyonunun yanı sıra, elde ettiğimiz bilgileri çok daha esnek biçimlendirmemizi sağlayan date() fonksiyonu da sık kullanılır. Bu fonksiyon çağrıldığı yerde bize Unix sisteminin Epoch zaman-tarih damgasını verir. Bu verinin biçimlendirilmesi için çeşitli parametreler vardır. Bu parametreler, gün adlarının dili ve tarihlerin yazılışı bakımından Web sunucusunun bulunduğu bilgisayardaki bölgesel ayarlara göre sonuç verir.

date() $tarih date( biçimlendirme_parametreleri );

Burada biçimlendirme_parametleri yerine şunları yazabilirsiniz:

a          12 saat esasına dayanan Anglo-Sakson sistemlerinde öğleden önce (“am”) veya öğleden sonra (“pm”) işaretinin verilmesini sağlar.

A         Aynı işaretlerin büyük harfle yazılmasını sağlar.

d          İki haneli gün sayısı, tek haneli günlerin önüne sıfıır konur: “01” – “31”

D         Üç haneli gün adı kısatması: “Cum”

F          Uzun ay adı: “Ocak”

h           12 saatlik sistemde saat: “01” – “12”

H         24 saatlik sistemde saat: “00” – “23”

g          12 saatlik sistemde tek haneli saatlerin önüne sıfır konmadan saat: “1” – “12”

G         24 saatlik sistemde tek haneli saatlerin önüne sıfır konmadan saat: “0” – “23”

i           Dakika: “00” – “59”

j           Tek haneli sayıların önüne sıfır konmadan gün sayısı “1” – “31”

l           (küçük L harfi) Uzun gün  adı: “Cuma”

L         Artık yıl olup olmadığına ilişkin Boolean (doğru/yanlış) değişken. Artık yıl ise 1, değilse 0.

m         Tek hanelilerin önüne sıfır konarak ay sayısı: “01” – “12”

n          Tek hanelilerin önüne sıfır konmadan ay sayısı: “1” – “12”

M        Kısaltılmış ay adı: “Şub”

s          Saniye: “00” – “59”

S          İngilizce (‘ncı anlamına) 2 karakter ek: “th”, “nd”

t           Belirtilen  ayın gün sayısı; “28” – “31”

w         Haftanın gün sayısı: “0” (Pazar veya Pazartesi) – “6” (Cumartesi veya Pazar)

Y         Dört haneli yıl: “2000”

y          İki haneli yıl “00”

z          Yılın gün sayısı: “0” – “365”

Örnek:

print (date (“l dS of F Y h:i:s A”));

Browser penceresine İngilizce bölgesel ayarlar yapılmış bir bilgisayara kurulu Web sunucusunda: “Sunday 30th of July 2000 07:51:08 AM” yazdırır.

print (date (“l, d F Y g:i:s”));

Browser penceresine Türkçe bölgesel ayarlar yapılmış bir bilgisayara kurulu Web sunucusunda: “Pazar, 30 Temmuz 2000 07:51:08” yazdırır.

date() ve mktime() fonksiyonlarını birlikte kullanarak geçmiş veya gelecek tarihleri bulma imkanı de vardır. Örnek:

$yarin  = mktime (0,0,0,date(“m”)  ,date(“d”)+1,date(“Y”));

$gecen_ay = mktime (0,0,0,date(“m”)-1,date(“d”),  date(“Y”));

$gelecek_lyl = mktime (0,0,0,date(“m”),  date(“d”),  date(“Y”)+1);

Düzenli İfadeler

Unix işletim sistemini geliştirenlerin bilişim teknolojisine kazandırdığı bir diğer değer biçilemez araç olan Düzenli İfadeler (Regular Expressions), belki de işaretlerinin karmaşıklığı sebebiyle programcıların fazla dokunmak istemedikleri bir alandır. Bu kavramla daha önce tanışmış olmayanlara, CGI veya Javascript kodlarında gördükleri,

^.+@.+\\..+$

işaretlerinin, Düzenli İfade işlemlerine ait olduğunu belirtilim. Bu işaretler ve onların arasına koyduğumuz karakter örnekleri ile, PHP’nin aradığımız bir metnin karakterlerinin hangi diziliş, sıralanış konumunda olduğuna bakarak, bize o metni bulmasını sağlarız; ya bu metni kullanırız, sileriz veya değiştiririz. Dolayısıyla, Düzenli İfade demek, bir diziliş, sıralanış biçimi demektir. Düzenli İfade oluşturarak, PHP’ye “İşte buradaki gibi sıralanmış karakterleri bul!” demiş oluruz. Düzenli İfade, PHP’ye verdiğimiz sıralanışa uygun metnin nerede ve kaçıncı kez bulunmasını istediğimizi de belirtir. Ayrıca, bu ifade ile, PHP’nin bulduğu metni (veya metinleri) ne yapmasını istediğimizi de söyleriz.

Eşleştirme deyimleri ve işaretler

PHP’nin karakter ve sıralanış eşlemede kullanılan düzenli ifade komutlarını kısaca ele alalım; sonra bunları kullanmamıza imkan veren fonksiyonları görelim.

^hakk

“hakk” ile başlayan bütün kelimeleri bulur. ^işareti, onu izleyen karakterin sadece alfanümerik değişkenin başında olması gerektiğine işaret eder. Bu deyimle, “Hakkı Öcal bugün buradaydı!” veya “Hakkıdır hakka tapan, milletimin istiklâl!” eşleşebilir; fakat “Anaların hakkı ödenmez!” eşleşmez; çünkü PHP açısından ^işaretinin anlamı, “Başlangıcında ‘hakk’ karakterlerinin sıralanıyla aynı sıralanıştaki alfanümerik değeri bul!” demektir.

edilemez$

Bu deyim ise PHP’ye “edilemez” ile biten bütün kelimeleri bulur. Sözgelimi, “Kötümser insanın yükselişinden bahsedilemez” cümlesi bu deyimle bulunabilir; fakat sonunda nokta olduğu için “.. edilemez.” diye biten hiç bir cümle bu deyimle eşleşemez.

^hakkı$

PHP, başında ^ işareti, sonunda $ işareti bulunan kararter sıralanışını, aynen arar; yani bu deyim, birinci örnekteki üç cümleyi de bulamaz.

hakk

Bu deyim ise her üç cümleyi de buldurur; çünkü üçünde de bu dört karakter bu sıralanışla mevcuttur. PHP’nin Düzenli İfadeleri, bütün rakam ve harfleri eşleştirebilir. Fakat sorun, özel karakterlerde çıkar. Sözgelimi, sekme işareti, satır sonlarında yeni-satır/satırbaşı işareti, gibi özel karakterleri, ancak önlerine Escape işareti olan ters bölü işaretini koyarak buluruz.

/////////////////////KUTU/////////////////////

Düzenli İfadelerde Özel Karakterler

[\b]           Geri (Backspace) karakterini bulur.

\b             Belirtilen karakterle sınırlanan kelimeyi bulur: k\b, “hak mücadelesi” ifadesindeki birinci k’yı bulur; çünkü bu harf, bir kelime sınırlayıcıdır.

\B             Belirtilen karakterle sınırlanmayan kelime yoksa, başlayanı bulur: k\Bi, “üç kişi” ifadesindeki ‘ki’yi bulur.

\cX           X yerine yazacağımız kontrol karakterini bulur. Örneğin, \cA, Ctrl+A’yı, \cZ ise Ctrl+Z’yi bulur.       

\d             0’dan 9’ya kadar bir rakamı bulur: IE\d, her ikisi de herhangi bir rakamla biten “IE5” ve “IE4” değerlerini ikisini de bulur,

\D            Herhangi bir ondalık işaretini bulur.

\f              Form-feed (kağıt çıkart) karakterini bulur.

\n             Newline (yeni satır) karakterini bulur.

\r              Return (satırbaşı) karakterini bulur.

\s              Boşluk (space) bulur.

\S             Yatay ve düşey sekme, kağıt-çıkart, yeni satır, satırbaşı ve boşluk dışındaki herhangi bir karakteri bulur.

\t              Yatay sekme (Tab) karakterini bulur.

\v             Düşey sekme karakterini bulur.

\w            Herhangi bir harf, rakam veya alt-çizgiyi bulur.

\W            Harf, rakam ve alt-çizgi dışındaki karakteri bulur.

\xHex       Verilen 16 tabanlı (Hexadecimal) sayıya uygun Escape karakterini bulur. Örneğin, \n25, % işaretini bulur.         

///////////////////////KUTU BİTTİ///////////

Bu arada noktalama işaretlerini arattırırken, önlerine ters bölü işareti koymak gerekir. Ters bömü işaretini de yine önüne ters bölü işareti koyarak (\\) arttırabilirsiniz.

Karakter Grupları

PHP’nin Düzenli İfadeleri’nde kolaylık sağlayan ve mesela ziyaretçinin bir Form’da bir INPUT etiketine verdiği yanıtıların içinde olmaması veya olmaması gereken karakterleri bulmamıza imkan veren karakter grupları oluşturma yöntemini de kullanabiliriz. Sözgelimi bütün sesli hafleri aratmak için şöyle bir karakter grubu oluşturabiliriz:

[OoUuÖöAaOoEeıIiİ]

Karakter gruplarını köşeli parantez içinde yazarız. Bu deyimle, PHP, içinde herhangi bir sesli harf bulunan bütün değerleri eşleştirecektir. Bu yöntemden yararlanarak, şu grupları kullanabiliriz:

[a-z]              Herhangi bir küçük harfi bulur.

[A-Z]            Herhangi bir büyük harfi bulur.

[a-zA-Z]       Herhangi bir büyük veya büyük harfi bulur.

[0-9]             Herhangi bir rakamı bulur.

[0-9\.\-]         Herhangi bir rakamı, noktayı veya kesme çizgisini bulur.

[ \f\r\t\n]        Herhangi bir Form-feed (kağıt çıkart), Newline (yeni satır), Return (satırbaşı) karakterini veya  boşluğu (space) bulur.

Sözgelimi, bir alfanümerik değer kümesinde b3, u2, n9 gibi birincisi küçük harf, ikincisi rakam olan iki karakterlik dizileri bulmak istiyorsak, arama grubunu şöyle kurarız:

^[a-z][0-9]$

Bu deyim PHP’ye, a’da z’ye küçük harfle başlayan, (^işareti aranan unsurun değerin başında olması gerektiğini söylüyor) ve sonunda 0’dan 9’a bir rakam bulunan kelimeleri bulmasını söyleyecektir. PHP, bu kelimenin sadece iki harfli olmasına dikkat edecektir; çünkü grubumuzun bir başı ve bir de sonu belirlendiğine göre, üç karakterli değerlerin bulunması imkanı yoktur.

^işareti köşeli parantez içinde grup deyimi oluştururken kullanılırsa, bu olumsuzluk anlamı taşır. Sözgelimi, iki rakamlı ancak birinci karakteri rakam olmayan fakat ikinci karakteri rakam olan değerlerin bulunması için şu deyim gerekir:

^[^0-9][0-9]$

Burada en baştaki ^işareti “başında” demektir; ancak hemen arkasından gelen grupta “rakam olmayan” demiş oluyoruz; ikinci grup ve sonundaki $ işareti ile “rakamla biten” anlamına geliyor. Deyimde sadece baş ve sonu gösteren iki eşleştirme unsuru bulunduğuna göre bu deyim, “başında rakam olmayan, sonunda rakam olan iki karakterli değerleri” bulmaya yarayacaktır. Bu deyim söz gelimi 13’ü bulmayacak, fakat u2’yi bulacaktır. Bu yöntemle şu grupları yapabiliriz:

[^a-z]            Küçük harf olmayan herhangi bir harfi bulur.

[^A-Z]          Büyük harf olmayan herhangi bir harfi bulur.

[^\\\/\^]          \ , / veya ^ dışında herhangi bir karakteri bulur.

[^\”\’]            Çift ve tek tırnak dışında herhangi bir karakteri bulur.

Grup oluşturmada kullandığımız özel karakterler de vardır. Örneğin nokta işareti (.), yeni satır başlangıcı olmayan herhangi bir karakter anlamına gelir. Dolayısıyla,

^.0$

deyimi yeni satırla başlamayan ve sıfır ile biten herhangi iki karakterli değeri bulacaktır.

PHP’nin kullanılmaya hazır özel Düzenli İfade eşleştirme grupları da vardır:

[[:alpha:]]      Herhangi bir harf

[[:digit:]]       Herhangi bir rakam

[[:alnum:]]    Herhangi bir harf veya rakam

[[:space:]]     Herhangi bir boş karakter

[[:upper:]]     Herhangi bir büyük harf

[[:lower:]]     Herhangi bir küçük harf

[[:punc:]]      Herhangi bir noktalama işareti

[[:xdigit:]]     Herhangi bir Hexadecimal karakter. [0-9a-fA-F]

Karakter eşleştirmede tekrar sayısı da bir özellik olarak kullanılabilir. Tekrar sayısı belirtmek için süslü parantez ({}) kullanırız. Örnekler:

^a{4}$                        İçinde sadece dört adet küçük a harfi bulunan kelimeleri seç: aaaa.

^a{2,4}$                     İçinde sadece iki üç veya dört adet küçük a harfi bulunan kelimeleri seç: aa, aaa, aaaa gibi

^a{2, }                        İki veya daha fazla küçük a harfi bulunan kelimeleri seç: haar, haaar, haaaar gibi. Bu deyim “har” kelimesini seçmez.

\t{2}                           Ardarda iki sekme işaretini bul

.{2}                            Herhangi çift karakteri bul: aa, &&, == gibi

^\-{0,1}[0-9]{1,}$     Negatif veya pozitif herhangi bir tam sayıyı bul

^[0-9]{1,}$                 Pozitif herhangi bir tam sayıyı bul

Bu tür deyim oluşturma işlemleri giderek karmaşıklaşabilir. Örneğin:

^\-{0,1}[0-9]{0, }\.{0,1}[0-9]{0, }$

Bu karmaşık deyim aslında sadece “Negatif veya pozitif bir ondalık (double) değeri bul,” anlamına geliyor. Kısaca irdelersek, aranan degerin sıfır veya bir kere tekrarlanan bir kesme çizgisiyle başlayabileceğini (“Sıfır veya bir kere” demek, olsa da olur, olmasa da anlamına geliyor!) bunu sıfır veya daha fazla kere tekrarlanan bir rakamın izleyebileceğini, onu da sıfır veya bir kere tekrarlanan bir nokta işareti ile sonunda sıfır veya daha fazla kere tekrarlanan herhangi bir rakamın izleyebileceğini söylemiş oluyoruz.

PHP bu tür karmaşık ifadelerin hatasız yazılmasını sağlayan kısayollara sahiptir. Bunları sıralayalım:

?          {0,1} anlamına gelir. Kendisinden önce yer alan unsurun en az sıfır en çok bir kere tekrar edilmesi gerektiğini (olmayabileceğini ama olursa en fazla bir kere olabileceğini) belirtir.

*          {0, } anlamına gelir. Kendisinden önce yer alan unsurun sıfır veya daha fazla kere tekrar edilmesi gerektiğini (tümüyle opsiyonel olduğunu) belirtir.

+          {1, } anlamına gelir. Kendisinden önce yer alan unsurun en az bir veya daha çok kere tekrar edilmesi gerektiğini (bulunmasının zorunlu olduğunu) belirtir.

Bu kısa-yolları kullanarak, yukarıdaki karmaşık ifadeleri basitleştirelim:

^[a-zA-Z0-9_]+Ş     En az bir harf veya rakam veya altçizgi içeren herhangi bir kelime

^[0-9]+Ş                               Herhangi bir pozitif tamsayı

^\-?[0-9]+Ş                           Herhangi bir tamsayı

^\-?[0-9]*\.[0-9*$]+Ş           Herhangi bir kesinli (double) sayı

Bir Düzenli İfade’nin yazılışında birden fazla arama-sıralanış deyimine yer verebiliriz. Bunu yapmamızı sağlayan | işaretidir. Örneğin,

\.com|\.co\.uk

ifadesi ile, ya “.com” ya da “.co.uk” değerlerinin bulunmasını sağlayabiliriz. Burada | işareti “veya” kelimesi gibi düşünebilirsiniz.

Düzenli ifadeler yoluyla INPUT etiketinden gelen değerleri incelerken hata yapmak kolaydır. Bunun için kendi ifadelerinizi mutlaka sçeşitli olasılıklara karşı sınamalısınız. Bu bölümün başında örnek olarak verdiğimiz Düzenli İfade’yi hatırlıyor musunuz?

^.+@.+\\..+$

Örneğin bu ifade, ziyaretçinin elektronik posta adresini yazması gereken bir INPUT etiketinin sağladığı değerin gerçekten elektronik adres biçimi taşıyıp taşımadığını sınar. Baştaki ^ ve nokta işaretleri ile artı işareti değerin önünde boşluk olmamasını sağlıyor; @ işareti ise değerin içinde @ bulunması gerektiğine işaret ediyor. Tekrar eden nokta ve artı işaretleri “ne kadar olursa olsun ve ne olursa olsun” anlamına geliyor. Bunu izleyen nokta karakterini gösteren (\.) işaret buralarda bir de gerçekten nokta olması gerektiğini ve bunu izleyen nokta ve artı tekrar “ne olursa olsun, ne kadar olursa olsun” anlamını taşıyor. Başka bir deyişle, aradığımız değerin “herhangi bir şey” @ “herhangi bir şey daha” . “birşeyler daha” şeklinde olduğunu belirtmiş oluyoruz. Ne var ki deyimiçinde iki nokta veya iki @ işareti olan veya @ işareti ile nokta arasında bir şey bulunmayan veya @ veya noktadan öncesi ya da sonrası boş olan bütün değerleri safdışı etmeye yetmeyecektir.  Sözgelimi bir ziyaretçimiz “@@@@.@@@” yazarsa, bu deyim  bu değeri geçerli bir elektronik adres sayacaktır.

PHP programlarımızda ziyaretçilerimizin verdiği değerleri çeşitli bakımlardan sınamak ve seçmek mümkündür; ancak hiç bir zaman yazılanların doğruluğunu garanti edemeyiz. Fakat özellikle bir metinde bulunmaması gereken işaretlleri PHP’ye aratabiliriz. Bunu Düzenli İfade Fonksiyonları sağlar.

Düzenli İfade Fonksiyonları

Yukarıda öğrendiğimiz Düzenli İfade yazma tekniklerini, PHP’nin bize sağladığı beş fonksiyonda parametre olarak kullanırız. PHP’nin ayrıca Perl-tarzı düzenli ifade fonksiyonları da vardır. Bu fonksiyonlardan, ya bize bir boolean (doğru/yanlış) değer döner; ya da fonksiyon istediğimiz işi yaparak vardığı sonuçları verdiğimiz değişkene yazar. Biz, daha sonra bu değere bakarak veya değişkenin değerlerini kullanarak, PHP programımızın akışını kontrol edebiliriz. Burada ele alacağımız fonksiyonlara ilişkin örneklerde, daha önceki bölümlerde oluşturduğumuz konuk defteri programı ile Web ziyaretçilerimizin sunucuya göndereceği bilgileri doğrulamaya ve muhtemel zararlı kodlardan ayıklamaya çalışacağız.

ereg() ve eregi()

PHP’nin temel Düzenli İfade Fonksiyonu, ereg(), arattığımız karakter sıralanışı bulunduğu taktirde doğru, bulamadığı taktirde yanlış karşılığı bir değer verir. Fonksiyonu şöyle yazarız:

$bir_degisken = ereg(“eşleştirilecek_sıra” , $kaynak , $yeni_değişken);

Fonksiyonun aradığımız eşleştirmeyi yapması halinde, buradaki $bir_degisken’in değeri true/doğru, yapamaması halinde false/yanlış olacaktır. Eşleştirme sırasının nasıl oluşturulduğunu yukarıda gördük; bu ifadelerden işimize uygun olanı buraya tırnak içinde yazarız. $kaynak, eşleştirilecek sıralamanın içinde aranacağı değeri tutan değişkendir. Fonksiyonun bir diğer becerisi, eğer eşleştirilecek sıralamayı gruplar halinde verirsek, kaynakta yapacağı eşleştirme olursa, buna uygun değerleri bir dizi değişkene yazabilmesidir; istersek bir parametre olarak bu yeni değişkenin almasını istediğimiz adı veririz; böylece eşleştirme sonucu bulunan değerler kaydedilmiş olur.

eregi(), aynen ereg() fonksiyonu gibi çalışır; sadece eşleştireceği değerlerde büyük-harf/küçük-harf farkı gözetmez.

Daha önceki bölümde oluşturduğumuz ve kd_01.php adıyla kaydettiğimiz konuk defteri programının akış planını, ziyaretçinin Form’a yazdığı ve sunucuda $HTTP_POST_VARS dizi-değişkeninde tutulan değişkenlerinden elektronik posta adresi ilge ilgili olanı gerçekten içinde en az bir @ işareti ile en az bir adet nokta içip içermediğine bakarak sınayabiliriz. Böyle bir sınama için gerekli kod şöyle olabilir:

if (eregi(“^.+@.+\\..+$”, $adres, $email)) {

            }

            else {     

            $hata = “Elektronik posta adresinizde bir hata var!<br>”;

                        echo $hata;

                        include(“kd_hata_halinde.htm”);

                        exit;

            }

Program, bu örnekte $adres değişkeninde kayıtlı değerin içinde aradığı sıralamayı bulursa, eşleşen değeri $email adlı yeni bir değişkene yazacak ve if sınavının sonucu doğru olacaktır. Bu sıralamaya uygun bir değer bulunamazsa, if sınavı else deyimine atlayacak ve bir hata mesajı üretilerek, bu program durdurulacaktır. (Burada, yaptığı hayatı düzeltmesi yani geçerli bir elektronik posta adresi vermesini sağlayan yeni sayfanın, include komutu ile ziyaretçiye gönderildiğine dikkat edin. Bu programın yeni biçimi kitapçığın örnek kodları arasında kd_02.php adıyla bulunabilir.)

ereg_replace() ve eregi_replace()

Gördüğümüz gibi, ereg() arattığımız karakter sıralanışı bulunduğu taktirde doğru, bulamadığı taktirde yanlış karşılığı verdikten sonraduruyor! Oysa kimi zaman arattığımız ve bulunan değerin başka bir değierle değiştirilmesi gerekebilir. Bunun için ereg_replace() ve eregi_replace() fonksiyonlarını kullanırıız:

ereg_replace(“eşleştirilecek_sıra” , yeni_metin , $kaynak);

Fonksiyonun aradığımız eşleştirmeyi bulursa, bu değerin yerine verdiğimiz yeni metni koyacaktır; yeni metni bir değişkenin değeri olarak da verebiliriz. Uygulama örneği için yine konuk defteri örneğine dönelim. Ziyaretçilerimiz kimi zaman yanlışlıkla, kimi zaman pek de iyi niyet sonucu olmadan, kendilerinden beklediğimiz isim, adres ve mesaj yerine sunucu veya başka ziyaretçilerin Browser programları tarafından kod gibi algılanacak metinler yazabilirler. PHP’de güvenlik bölümünde bu konuda daha ayrıntılı bilgi bulacaksınız. Burada sadece bu tür zararlı metinlerin genellikle programlarda bulunması gereken karakterler içerdiğini söylemekle yetinelim. Bu tür karakterlerin başında < ve > işaretleri bulunur! Dolayısıyla, biz de ziyaretçimizden gelecek verilerin yazıldığı değişkenlerin değerlerinde bu işaretleri aratabilir ve  bunları içi boş bir alfanümerik değer ile değiştirebilir; yani silebilir. Zararlı olabilecek kodların arasında daha bir çok karakter bulunabilir; ancak Script diliyle yazılması gereken bu kodlardan < ve > işaretlerini kaldırılması kodları işlemez hale getireceği için, şu aşağıdaki örnek yeterli olabilir:

            $adi = ereg_replace(“<“,””,$adi);

            $adi = ereg_replace(“>”,””,$adi);

            $adres = ereg_replace(“<“,””,$adres);

            $adres = ereg_replace(“>”,””,$adres);

            $mesaj = ereg_replace(“<“,””,$mesaj);

            $mesaj = ereg_replace(“>”,””,$mesaj);

Burada ereg_replace() fonksiyonu, ziyaretçiden gelecek üç değişkenin değerlerinde < ve > işaretlerini aramakta onların yerine içi boş bir metin (“”) yazmaktardır. (Bu örneği içeren konuk defteri, bu kitapçığın örnek kodları arasında kd_03.php adıyla bulunabilir.)

split()

Düzenli İfade ile çalışan bu fonksiyon, vereceğimiz eşleştirme sıralamasını sınırlayıcı olarak kullanarak, belirteceğimiz değerde bulduğu değer parçalarını ayırır ve bunları ayrı ayrı bir dizi değişkenin elemanları olarak kaydeder. Bu fonksiyonu şöyle yazarız:

$yeni_dizi_değişken = split(“eşleştirilecek_sıra” , $kaynak, sınır_sayısı);

Fonksiyon, aradığı sıralamayı bulamazsa, false/yanlış sonucunu verir. Burada sınır sayısı olarak vereceğimiz rakam, oluşturulacak yeni dizi değişkene en fazla kaç eleman yazılmasını istediğimizi gösterir. Bu sayıyı vermezsek, PHP yeni dizi değişkenin gerektiği kadar elemana sahip olmasını sağlar. Bir örnek vererek, bu fonksiyonu nasıl kullanibileceğimizi görelim:

<?php

$metin = “İnsan sözüyle kendini gösterir, davranışlarıyla ruh halini aksettirir.”;

$aranan = ” “;

$yeni_dizi_değişken = split($aranan, $metin);

foreach ($yeni_dizi_değişken as $eleman) {

print “$eleman <br>”;

}

?>

Bu programda PHP, $metin değişkeninin içerdiği değerde $aranan değişkeninin içerdiği değeri, yani boşluğu, eşleştirilecek unsur olarak kullanacak ve $metin değişkeninin değerini boşluklarından parçalara ayıracaktır. Ayrılıcak her yeni parça, $yeni_dizi_değişken adlı değişkenin elemanları olarak atanacaktır. Programın geri kalan kısmı ise, bu yeni dizinin elemanlarını görüntülemekterdir.

sql_regcase()

İçinde büyük harf-küçük harf ayrımı olan bir değeri büyük harf-küçük harf ayrımı olmayan Düzenli İfadeler haline çevirir. Bu fonksiyon bizden Düzenli İfade almaz, tersine Düzenli İfade oluşturur. Örnek:

<?php

$metin = “Sözler”;

echo(sql_regcase($metin);

?>

Bu program, Browser penceresine şu metni yazdırır:

[Ss][Öö][Zz][Ll][Ee][Rr]

PHP ile Veritabanı

PHP’yi bir veritabanından veri çekecek, bunlarla HTML etiketlerinin içeriğini oluşturacak ve ziyaretçimizden alacağımız bilgileri bir veritabanına işleyecek işlemleri öğrenebilecek kadar biliyoruz artık. Bu kitapçığın baş tarafındaki kurma işlemlerini birlikte yaptıysak, şu anda PHP programlarını geliştirdiğiniz kişisel bilgisayardaki kişisel Web sunucusunda MySQL sürücüleriniz ve veritabanı yönetim programınız çalışıyor olmalı. Bir kere daha tekrar etmek gerekirse, PHP ile veritabanına dayanan sayfalar yapmak için mutlaka ve sadece MySQL sürücülerini kullanmak gerekmez. Bunun yerine sözgelimi Microsoft’un ODBC sürücülerini kullanabilirsiniz. Ancak Web sitenize evsahipliği yapan firmanın size ODBC desteği verip vermediğini öğrenmeniz gerekir. Aslında aynı şekilde, evsahibi firmanın MySQL desteği verip vermediğini de öğrenmek zorundasınız. (PHP ile MS-ODBC sürücülerini kullanabilmek için Andrew Stopford’un ASP Today sitesinde http://www.asptoday.com/articles/20000202.htm adresindeki yazısında daha geniş bilgi bulunmaktardır.)

Web sitemizde, HTML sayfalarımızı ve PHP programlarımızı neden veriya dayalı hale getirmeliyiz? Bu sorunun cevabı, “Başka türlü elde edilemeyecek bir otomasyon, ziyaretçilerimizle gerçek anlamıyla etkili biralışveriş sağlamak için!” diye yanıtlayabiliriz. Yukarıda, bir PHP programının ziyaretçiden Frm ile alacağı bilgileri, yine kendisine gönderebileceğini ve bu bilgileri işleyebileceğini gördük. PHP programımızın bu bilgileri bir veritabanına işlediğini ve ziyaretçi bir başka sayfaya gitmek istediğinde o sayfanın içeriğinin, ziyaretçinin birkaç saniye önce yaptığı tercihlere göre belirlendiğini düşünün. Bir başka örnek, Web sitemizdeki sayfalarda yer alan unsurların güncelleştirilmesi için her güncelleştirmede çok sayıda programı yeniden yazmak veya sayfayı yeniden yapmak zorunluğu varsa, bu program ve sayfaların içeriklerini bir veritabanından alıyor olması halinde, sadece veritabanını güncelleştirmekle onlarca, belki de yüzlerce, HTLL ve PHP belgesini yeniden yazmış gibi olabiliriz.

Bu bölümde önce bir örnek veritabanı dosyası hazırlayacağız; daha sonra bunun içindeki verileri PHP programı ile sayfalarımıza katacağız. Bu dizinin ikinci kitabında Unix/Linux sistemlerinde veritabanı uygulamaları üzerinde daha geniş duracağız. Burada Windıows sisteminde bir MySQL uygulamasını ele almakla yetineceğiz.

MySQL Veritabanı

Gerçi bu kitapçığın konusu kendisi başlı başına bir dil olan SQL değil, ama burada sadece MySQL programı ile veritabanı oluşturmakla kalmayalım, bir anlamda SQL diline de çok kısa bir giriş yapalım. SQL çook geniş bir dildir. Burada yapabileceğimiz giriş ancak ilk alıştırmamaızı  yapmamıza yetebilir.

SQL, (Structured Query Language, Yapısal Sorgu Dili) veritabanı endüstrisinin standart dilidir. Fakat HTML konusunda farklı firmaların sadece kendi Browserlarının tanıdığı türden etiketler geliştirmeleri gibi, SQL alanında da farklı firmaların ekleri ve dilde yaptıkları değişiklikler vardır.

MySQL, teknik tabiriyle sunucuda daemon olarak çalışır ve arzu eden programa, bildireceği (ve erişim hakkı bulunan) veritabanı dosyasından veri çekerek, sunar. Bir veritabanında farklı sayıda tablolar olabilir. Bir veritabanı dosyasında yer alan tablolarda, sütunlar ve satırlar vardır: bunların kesiştikleri yerlere biz verilerimizi yazarız. Bir SQL veritabanı dosyasında her bir kutunun ne tür veri kabul edeceği önceden belirlenir; dolayısıyla türü sayı olan verinin yazılacağı kutuya, alfanümerik değer yazılmaz. MySQL, sayısal verilerin türünü INT, belirli bir sınıra kadar değişen sayıda karakterden oluşacak verilerin türünü VARCHAR komutuyla belirler.

//////////////////KUTU////////////////

mySQL veri türleri

MySQL’de bir çok veri türü oluşturulabilir. Ancak Web programları açısından önemli olan bir kaçı ve özellikleri şöyle saralanabilir:

INT                             Tamsayı: -2147483648’den 2147483647 kadar değişen diziye “signed” (işaretli), 0’dan 4294967295’e kadar değişenine “unsigned” (işaretsiz) denir.

VARCHAR(n)           n sayısını geçmemek şartıyla değişen boyutta karakter olabilir.

CHAR(n)                    Kesinlikle n sayısı kadar karakter olabilir.

TEXT                          En fazla 65535(2^16-1) karakter alabilen metin alanı.

MEDIUMTEXT         En fazla 16777215(2^24-1) karakter alabilen metin alanı.

DATE                         1000-01-01’den 9999-12-31’e kadar değişebilen tarih alanı.

TIMESTAMP             1 Ocak 1970’den 18 Ocak 2038’e kadar olan ve Yıl+Ay+Gün+Saat+Dakika+Saniye biçimindeki zaman bilgisi.

/////////////////KUTU BİTTİ//////////////

MySQL’de bir tablo oluşturmak için gerekli CREATE TABLE komutu şöyle kullanılır:

CREATE TABLE uyeler (adi VARCHAR(30), soyadi VARCHAR(30), üye_no INT ) ;

Bu komutla, “uyeler” isimli üç sütunlu bir tablo oluşturulur: birinci ve ikinci sütunlarda en fazla 30, karakterlik değişen boyutta alfanümerik değerler yer alırken, üçüncü sütunda sadece tam sayı olan değerler bulunabilir. Bu komutla oluşturulan tabloya INSERT  INTO komutuyla veri girebilirsiniz:

INSERT  INTO uyeler (adi, soyadi, uye_no) VALUES (‘Muharrem’,’Taç’,’1234′)

Bir tablonun oluşturulması ile içine veri yerleştirilmesi komutları ayrı ayrı zamanlarda, ayrı işlemler olarak yapılabileceği gibi, toplu bir metin halinde, otomatik olarak da yapılabilir.

MySQL veritabanından bilgi edinmek için SELECT komutunu kullanırız:

SELECT * FROM uyeler ;

Bu, MySQL’e, uyeler adlı tablodaki bütün değerlerin okunmasını bildirir. Buradaki “*” işareti, “bütün sütunlardaki bütün değerler” anlamına gelir. Diyelim ki yukardıda oluşturduğumuz tablonun sadece “adi” ve “soyardi” sütunlarındaki bilgileri almak isteseydik, bu komutu şöyle yazacaktık:

SELECT adi soyadi FROM uyeler ;

Bir veritabanındaki bilgilerin yenileriyle değiştirilmesini, yani veritabanı dosyasının güncelleştirilmesini UPDATE komutu sağlar. Bu komutu kullanarak veritabanımızdaki bazı kutucukların içindeki bilgileri değiştirebiliriz. Veritabanı dosyalarını güncelleştirme zorunluğu bulunması ise bize veritabanı tasarımının çok önemli olduğunu gösterir. Örneğin:

UPDATE uyeler SET adi = “Şahika” ;

Bu komut, veritabanındaki bütün satırlarda, birinci sütundaki değerleri “Şahika” olarak değiştirmekle sonuçlanırdı. Amacımız bu ise, sorun değil; ancak çoğu kez MySQL’e hangi satırda (veritabanı tekniğindeki terimle söylersek, hangi kayıtlarda) değişiklik yapılacağını daha ayrıntılı sölememiz gerekir. Veritabanı dosyamızı oluştururken, her kaydın diğer kayıtlarda olmayan (unique) bir sütun (bunu da veritabanı tekniğindeki terimle söylersek. alan) bulunmalıdır, ki MySQL’e yapılacak değişikliğin tam yerini söyleyelim. Örneğin

UPDATE uyeler SET adi = “Şahika” WHERE uye_no = 1234;

MySQL bu komutu alınca sadece üye numarası 1234 olan kişinin (yani uye_no alanındaki değer 1234 olan kaydın) “adi” alanındaki değeri silecek ve yerine verdiğimiz yeni değeri yazacaktır. Böyle birincil alanı bulunan, iyi düşünülmüş bir veritabanından seçim yapmak da kolay olur. Örneğin:

SELECT adi soyadi FROM uyeler WHERE uye_no >= 123;

deyimi ile tablomuzda bulunan kayıtlardan sadece üye numarası 123’den büyük olanları seçebiliriz.

Bir MySQL veritabanındaki kaydı silmek için DELETE komutunu kullanırız:

DELETE FROM uyeler WHERE uye_no = 1234;

Vveritabanında sadece bir kayıtta üye numarası 1234 olacağı için bu komutla sadece bir satır silinecektir. Bu komutu, diyelim ki üyelik kaydını yenilememiş kişilerin tümünü silmek için de kullanabiliriz. Veritabanımızda üyelik kaydının yenilendme tarihini gösteren bir alan bulunduğunu varsayalım:

DELETE FROM uyeler WHERE yenileme_tarihi < 2000-01-31;

Bu komutla, üyeliğini yenileme tarihi 31 Ocak 2000’den eski olan bütün üyelerimizin kaydını veritabanından silmiş oluruz.

Bu komutların MySQL’in DOS komut işlemcisi ile komutsatırından yapılacağını belirtmemiz gerekir. Bunu yapabilmek için MySQL Server’ın Windows’da çalıştırılması gerekir. MySQL’in paylaşım sürümünü kullanmak için Windows sistemlerinde mysqld-shareware.exe programını çalıştırmanız gerekir. Bunun için DOS komut istemcisi penceresinde “C:/mysql/bin” dizinine giderek, şu komutu vermemiz yeter:

mysqld-shareware

MySQL sürücülerinizin kişisel Web sunucusunda başarıyla çalıştığına, kitapçığın  baş tarafında belirttiğimiz küçük alıştırmayı yaparak emin olduktan sonra gerçek bir veritabanı dosyası yazabiliriz.

Yukarıda gördüğümüz komutları komut istemci satırından tek tek verebileceğimiz gibi, bir düzyazı dosyasında toplayıp, MySQL programına da otomatik olarak yaptırabiliriz.  Bu dosyaya, içindeki verileri alıp veritabanına boca edeceğimiz için, Dump dosyası denir.

Aşağıdaki metni MySQL programının kurulu olduğu dizindeki /bin/ alt-dizinine (muhtemelen c:\mysql\bin) veri.dump adıyla kaydedin (Notpad kullanıyorsanız, dosya adına .txt eklendiğine dikkat edin!)

CREATE TABLE calisanlar ( id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY (id), adi VARCHAR(20), soyadi VARCHAR(20), adres VARCHAR(60), pozisyon VARCHAR(60));

INSERT INTO calisanlar VALUES (1 , ‘Sahika’ ,’Tabak’ ,’PCLife Dergisi, Istanbul’ , ‘Yazar’);

INSERT INTO calisanlar VALUES (2 , ‘Muharrem’ , ‘Tac’ , ‘Işık Kultur Merkezi, Bursa’ , ‘Yonetmen’);

Bu metnin sadece üç satır olmasına, örneğin Notpad’de Düzen menüsünde Sözcük Kaydır maddesinin işaretsiz olmasına dikkat edin. Daha sonra yine DOS komut istemcisi penceresinde MySQL programının dizininde /bin alt-dizinine gidin ve şu komutu yazın:

mysqladmin -u root create veri

MySQL veri adlı veritabanının oluuştuğunu bildirecektir. Şimdi içi boş bir veri dosyamız oldu. Yazdığımız dump dosyasındaki bilgileri veritabanı dosyasına işletmek işini MySQL yapacakatır. Bunu, şu komutla yapabiliriz:

mysql –u root veri < veri.dump

İşlerin yolunda gidip gitmediğini c:\mysql\data dizininde veri adlı bir klasör oluşturulduğunu kontrol ederek anlayabiliriz. Bu klasörün içinde calisanlar.frm, calisanlar.isd ve calisanlar.ism adında dosyalar bulunması gerekir.

PHP-MySQL İlişkisi

Böylece, MySQL ile bir veritabanı dosyası oluşturma işlemi bitmiş oldu. bir PHP programı yazarak bu veritabanındaki kayıtları okutabiliriz. Bunu yapmadan önce yine hızlı şekilde PHP-MySQL ilişkisinini sağlayan fonksiyonlara gözatalım.

PHP programlarımızda veritabanından yararlanabilmek için programın önce Web sunucusu aracılığıyla veritabanı dosyası ile bağlantı kurması gerekir. Başka bir deyişle, PHP programının veri ile arasında bir yol açması gerekir. MySQL açısından ise bu bağlantı, veri sunucusunda yeni bir oturum açılması anlamına gelir. İki program arasındaki bu ilişkiyi PHP’nin mysql_connect() fonksiyonu yapar. Bu fonksiyonun alabileceği üç parametre vardır:

$veri_yolu = mysql_connect (“localhost” , “root” , “parola” );

Burada “localhost” yerine MySQL programının parçası olarak çalıştığı sunucunun adı yazılır. “root” bu MySQL sunucusunda açılacak oturumun kimin adına açılacağını belirter. “root” kelimesi, sunucunun yönetici olarak oturum açılacağı anlamına gelir: “parola” kelimesinin yerine de MySQL’i kurarken belirlediğimiz bir kullanıcı parolası varsa, onu yazarız. Bu komutta yer alan $veri_yolu değişkeni, açılacak veri yolunun, PHP ile MySQL veritabanı sunucusu arasındaki bağın tanıtıcı işareti olacaktır. Bu bağlantı kurulduktan sonra, açtığımız veri yolundan gelecek bilgiler ve veritabanına gidecek bilgiler bu değişken aracılığıyla gerçekleşecektir. Veri sunucusu ile veri yolu bağlantısı kurulursa, bu değişken değer tutar hale gelir; bağlantı kurulamazsa bu değişken boş kalır. mysql_connect() fonksiyonunun başarılı olup olmadığını bu değişkenin durumunu sınayarak anlayabiliriz. Örneğin:

$veri_yolu =mysql_connect(“kara-murat”, “root”);

if ( ! $veri_yolu) die (“MySQL ile veri bağlantısı kurulamıyor!);

Burada veri sunucusunun bulunduğu Web sunucusunun adının “kara-murat” olduğuna, ve ooturumun “root” yetkileriyle açıldığına dikkat edin. İkinci satırdaki if deyimi, $veri_yolu değişkeninin değer içerip içermediğine bakıyor ve değişkende bir değer yoksa, bağlantı kurma girişini durdurarak, ziyaretçiye hata mesajı gönderiyor.

Bağlantı başarıyla kurulduktan sonra PHP programı, bu yoldan, veritabanı sunucusuna, hangi veritabanı dosyasından yararlanmak istediğini bildirmelidir. Buna veritabanı dosyası seçme işlemi denir ve mysql_select_db() fonksiyonu ile yapılır:

mysql_select_db( “veritabanın_adı” , $veri_yolu ) or die (“Veritabanı açılamıyor!”.mysql_error() );

Bu fonksiyonun başarıyla icra edilip edilmediği fonksiyondan dönen değerin true/doğru veya false/yanlış olmasından anlarız. Bu değer false ise bu deyimin die() bölümü icra edilecek ve Browser penceresine veritabanının açılamadığı mesajıyla birlikte MySQL’in hata mesajı da gönderilecektir. PHP’nin MySQL veritabanını seçememesi çoğu zaman kullanıcı yetkilerinin Internet ziyaretçilerini kapsayacak şekimde düzenlenmemiş olmasından kaynaklanır. Bu durum gerçek Web sunucusunda ortaya çıkarsa, Web sunucusu yönetimine başvurmak gerekir.

Şimdi bu anlattıklarımızı biraraya getiren kolay bir PHP programıyla biraz önce oluşturduğumuz “veri” adlı veritabanından bir birinci kişiye ait verileri “okutarak, HTML sayfamızda kullanalım. Aşağıdaki programı, veri_01.php adıyla kaydedelim:

<HTML>

<TITLE>PHP ile Veri Örnegi</TITLE>

<meta http-equiv=”content-type” content=”text/html; charset=ISO-8859-9″>

<meta http-equiv=”Content-type” content=”text/html; charset=windows-1254″>

</HEAD>

<BODY>

<?php

$veri_yolu = mysql_connect(“kara-murat”, “root”);

if ( ! $veri_yolu ) die (“MySQL ile veri bağlantısı kurulamıyor!”);

mysql_select_db(“veri” , $veri_yolu)

            or die (“Veritabanına ulaşılamıyor!” . mysql_error() );

$sonuc = mysql_query(“SELECT * FROM calisanlar”,$veri_yolu);

            printf(“Adı: %s<br>\n”, mysql_result($sonuc,0,”adi”));

            printf(“Soyadı: %s<br>\n”, mysql_result($sonuc,0,”soyadi”));

            printf(“Adresi: %s<br>\n”, mysql_result($sonuc,0,”adres”));

            printf(“Görevi: %s<br>\n”, mysql_result($sonuc,0,”pozisyon”));

?>

</BODY>

</HTML>

Burada, mysql_connect() fonksiyonu ile “kara-murat” isimli sunucuda root adına MySQL sunucu ile bağ kurduktan sonra mysql_select_db() fonksiyonu ile bu bağı kullanarak veri isimli veritabanından veri çekeceğimizi bildiriyoruz. Daha sonra mysql_query() fonksiyonu ile bu veritabanındaki “calisanlar” isimli tablodan “herşeyi” seçiyoruz ve seçilenleri $sonuc dizi-değişkeninde topluyoruz. $sonuc değişkenin değerlerini görüntülemek için PHP’nin özel bir fonksiyonu olan mysql_result() fonksiyonu kullanıyoruz. Burada metin biçimlendirmekte yararlandığımız printf() fonksiyonunu daha önce tanımıştık.

<php00031.tif>

mysql_query() fonksiyonu, PHP’nin SQL dilini kullahnarak veritabanı işlemleri yapmasını sağlayan başlıca aracıdır. Yukarıda kısaca değindiğimiz bütün SQL komutlarıyla yazacağımız bütün “query” deyimlerini bu fonksiyon ile icra ettireceğiz. mysql_result() ise SQL değil, Data Manipulation Language (DML) denen başka bir veri-biçimlendirme dilinin inceliklerinden yararlanmamızı sağlar. Burada $sonuç değişkeninde veritabanı kayıt biçiminde tutulan verileri PHP’nin ve dolayısıyla HTML’in anlayacağı biçime çeviren bu fonksiyondur.

Şimdi bu programı biraz geliştirilim ve daha önce kendi kendine bilgi veren Form örneğimizi buraya uygulayalım; ancak bu kez, ziyaretçimizin vereceği bilgileri veritabanına ekleyelim; ve kendi adının veritabanına eklendiğini sayfadaki tabloyu güncelleyerek bildirelim. Önce şu programı, veri_02.php adıyla kaydedelim:

<?php

// Form doldurulduktan sonra program buradan başlıyor

if ( isset ( $HTTP_POST_VARS )) {

$veri_yolu = mysql_connect(“server”, “root”);

if ( ! $veri_yolu ) die (“MySQL ile veri bağlantısı kurulamıyor!”);

mysql_select_db(“veri” , $veri_yolu) or die (“Veritabanına ulaşılamıyor!” . mysql_error() );

$ekle = mysql_query(“INSERT INTO calisanlar ( adi , soyadi , adres , pozisyon ) VALUES (‘$adi’, ‘$soyadi’, ‘$adres’, ‘$pozisyon’ )”, $veri_yolu );

echo (“

      <HTML>

      <HEAD>

      <TITLE>PHP’de Veritabanı</TITLE>

      <meta http-equiv=’content-type’ content=’text/html; charset=ISO-8859-9′>

      <meta http-equiv=’Content-Type’ content=’text/html; charset=windows-1254′>

      “);

$sonuc = mysql_query(“SELECT * FROM calisanlar”, $veri_yolu);

echo (“

      <TABLE>

      <TR>

          <TD><B>Uzmanın Adı</B></TD>

          <TD><B>Çalıştığı Yer</B></TD>

          <TD><B>Görevi</B></TD>

          </TR>

      \n”);

while ($satir = mysql_fetch_row($sonuc)) {

      printf(“<TR><TD>%s %s</TD><TD>%s</TD></TD><TD>%s</TD></TR>\n”, $satir[1], $satir[2], $satir[3], $satir[4]);

      }

echo (“

      </TABLE>\n

      <p><B>Teşekkür ederiz.</B></P>

      <A HREF=’index.php’>Ana sayfaya dönmek için tıklayınız</A>

      “);

}

// program ilk kez açılıyorsa buradan başlayacak

else {

echo (“

      <HTML>

      <HEAD>

      <TITLE>PHP’de Veritabanı</TITLE>

      <meta http-equiv=’content-type’ content=’text/html; charset=ISO-8859-9′>

      <meta http-equiv=’Content-Type’ content=’text/html; charset=windows-1254′>

      </HEAD>

      <BODY>

      <p><B>Mevcut Üyelerimiz</B></P>

      “);

$veri_yolu = mysql_connect(“server”, “root”);

mysql_select_db(“veri”, $veri_yolu);

$sonuc = mysql_query(“SELECT * FROM calisanlar”, $veri_yolu);

echo (“<TABLE>

      <TR>

          <TD><B>Uzmanın Adı</B></TD>

          <TD><B>Çalıştığı Yer</B></TD>

          <TD><B>Görevi</B></TD>

      </TR>

      \n”);

while ($satir = mysql_fetch_row($sonuc)) {

      printf(“<TR><TD>%s %s</TD><TD>%s</TD></TD><TD>%s</TD></TR>\n”, $satir[1], $satir[2], $satir[3], $satir[4]);

      }

echo (“

      </TABLE>\n

      <p></p>

      <p><B>Siz de aramıza katılmak ister misiniz?</B></P>

      <FORM ACTION=’$PHP_SELF’ METHOD=’POST’>

      <TABLE>

      <TR><TD>Adınız: </TD><TD><INPUT TYPE=’TEXT’ NAME=’adi’></TD></TR>

      <TR><TD>Soyadınız: </TD><TD><INPUT TYPE=’TEXT’ NAME=’soyadi’></TD></TR>

      <TR><TD>İş Yeriniz: </TD><TD><INPUT TYPE=’TEXT’ NAME=’adres’></TD></TR>

      <TR><TDALIGN=’left’>Göreviniz: </TD><TD><INPUT TYPE=’TEXT’ NAME=’pozisyon’></TD></TR>

      <TR><TD ALIGN=’center’><INPUT TYPE=’SUBMIT’ VALUE=’Defteri imzala!’></TD><TD ALIGN=’center’><INPUT TYPE=’RESET’ VALUE=’Tümünü sil!’></TD></TR>

      </TABLE>

      </FORM>

      </BODY>

      </HTML>

      “);

}

?>

Program, ilk kez çalıştığında, çalışmaya ikinci yarısındaki else() deyiminden itibaren icra ediliyor;  ziyaretçilerimize mevcut üyelerimizin listesini veriyor ve üye olmak isteyip istemediğini soruyor. Arzu edenin üye olabilmesi için gerekli Form’u da sunuyoruz.

<php00032.tif>

Programın her iki bölümünde de veri okuyan ve bunu görüntüleyen, yani programın canalıcı noktası, mysql_fetch_row() fonksiyonudur. PHP’nin DML araçlarından olan bu fonksiyonun marifeti, bir veritabanından elde edilen sonucu satır-satır okumasıdır. Nitekim, burada bu fonksiyondan dönen değeri $satir adını verdiğimiz dizi-değişkene yazıyoruz ve sonra printf() bu dizinin elemanlarını sırayla Browser penceresine gönderiyor. (Burada olduğu gibi $satır değişkenin içinde kaç kaç sütun olduğunu bildiğimiz durumlarda printf() fonksiyonunu döngüsüz kullanmak mümkündür. Ancak veritabanının sütun sayısını bilmiyorsak bunu sözgelimi count($satir) yoluyla öğrenip, bu bilgiyle bir for döngüsü kurmak yerinde olur.

Programın iki bölümü arasındaki tek fark, $HTTP_POST_VARS dizi-değişkeninin bir değer tutması halinde (yani ziyaretçi sayfayı açtığında karşısına çıkan Form’u doldurduğu ve gönderdiği zaman) çalışan birinci bölümünde, mysql_query() fonksiyonunun bu kez veritabanı dosyasına ziyaretçinin verdiği bilgileri işlemek üzere farklı bir SQL deyimi içermesidir. Nasıl yazıldığını daha önce ele aldığımız bu fonksiyon “calisanlar” tablosundaki dört alana elimizdeki dört değişkenin değerlerini SQL’in INSERT komutuyla ekliyor.

<php00032.tif>

PHP’nin MySQL ile yapabileceğimiz veritabaynı yönetimi için 20’ye yakın fonksiyonu vardır; MySQL de bu fonksiyonlar yardımıyla çok sayıda iş yapabilir. Bu konuda ayrıntılı bilgiyi MySQL ve PHP’nin Internet sitelerin yanı sıra, http://hagen.let.rug.nl/~s0367672/pm_lin_e.htm adresinde bulabilirsiniz.

Bu konuya son verirken, Form örneğindenden farklı olarak yukarıdaki veritabanı örneğinde ziyaretçinin gireceği bilgilerle ilgili güvenlik önlemleri alınmadığına dikkatinizi çekerim.

PHP’de Güvenlik

Günümüzde Internet’te ne kadar güvenlik önlemi alınsa, yeridir. Sadece iyi niyetli olmayan kişilere karşı değil, fakat daha çok ne yaptığını tam bilmeyen Web ziyaretçilerini de düşünmek ve PHP programlarınızın güvenliğini arttırmak zorundasınız.

Internet’te iyiniyetli olunmaz. Acı, ama gerçek. Internet’e içine zararlı kod yerleştirilebilecek bir Form koyarsanız, emin olmalısınız ki, birisi bu zararlı kodu koyacaktır. Sadece kötüniyetli kişilerin size söz gelimi elektronik posta adresi veya mesaj görünümünde zararlı kod göndermesini önlemek için değil, fakat normal kullanıcıların yapabilecekleri sıradan hataları yakalamak ve düzeltmek için de önlem almanız gerekir.

Server güvenliği son derece önemli bir konu olmakla birlikte, bunu sağlamak genellikle tasarımcının sorumluluğunda değildir. Bununla birlikte sayfalarımızın ve veritabanımızın güvenliği ve Web uygulamalarımızın doğru işlemesi bizden sorulur.

Bir form ile sizin sayfalarınıza veya veritabanınıza ne gibi zararlar verilebilir? Bu zararların başında, en hafifinden sizin sayfanızı başka yere yönlendirmek gelebilir. Kötüniyetin ölçüsü arttıkça bu, Server programının açıklarından yararlanarak, Server’daki dosyaları değiştirmeye veya tahrip etmeye kadar gidebilir. Normal ziyaretçi hataları arasında ise sözgelimi elektronik posta adresini iki @ işaretiyle yazmaktan tutun, bu işareti koymamaya, metktubun gideceği bilgisayarın adresini eksik yazmaya kadar uzanan bir dizi yanlışlık bulunabilir. Ziyaretçiler formu eksik doldurabilirler. Bu gibi eksiklikler ve yanlışlıkları daha sonra düzeltmek zaman kaybına yol açar. Kimi zaman eksik doldurulmuş bir Form, bu bilgilerin ulaştırılacağı programda hataya yol açabilir. Bu sebeple, özellikle Form yoluyla alınan bilgilerin denetimi ve doğrulatılması şarttır.

Bir Form’un içerdiği bilgilerin denetimi ve doğrulanması iki yerde yapılabilir: istemci-tarafında, sunucu-tarafında. İstemci tarafında, yani ziyaretçiye göndereceğimiz HTML sayfasının içinde yer alan kodlarla yapacağımız denetim-doğrulama, hızlı çalışır; ve ziyaretçi ile sunucu arasında iletişim kurulmadan önce yapılır; böylece ziyaretçinin sözgelimi gönder düğmesini tıkladıktan sonra çok beklemesi gerekmez. Ne var ki bu yöntemde denetim-doğrulama kodu ziyaretçiye gönderilmiştir; kötü niyetli kişi neyi denetlediğinizi görecek ve isterse bu denetimi kaldıracak size zararlı kod parçacıkları gönderebilecektir. Denetimin sunucu tarafında yapılması, belki biraz daha fazla zaman harcamayı gerektirir, fakat güvenlik açısından daha etkili olabilir. Elektronik posta adresi doğırulama ve mesajların içinden zararlı kodları ayıklama yöntemlerinden Düzenli İfadeler bölümünden söz ettik. Orada ele aladığımız örnek kodlar geliştirilerek ziyaretçilerin girdilerinde daha sıkı aramalar yapılabilir.

Parola ve SSL

PHP gibi, kendisi ziyaretçinin Browser’ına gönderilmeyen bir dille, sitelerimi parola ile korumak mümkün ve kolaydır. Sitenize sadece sizin vereceğiniz parola ile girilmesini istiyorsanız, ana sayfanın şöyle başlaması yeter:

<?php

if (!isset($parola) || $parola != “gizli_kelime”) {

?>

<FORM ACTION=”parola_igir.php” METHOD=”POST”>

Parola: <INPUT NAME=”parola” TYPE”password”><BR>

<INPUT TYPE=”submit”>

</FORM>

<?php

}

else {

// Buraya gizlenen sayga girecek

?>

PHP ayrıca mevcut hemen hemen bütün sunucu kullanıcı kimlik doğrulama protokolleri ile uyumludur; ve sunucu yönetimi ile ilişki kurularak daha karmaşık kullanıcı kimlik doğrulama yöntemleri uygulanabilir. Bu yöntemler arasında Secure Socket Layer (SSL) yöntemlerini, ve OpenSSL ve ModSSL teknikleri sayabiliriz.

Tırnak İşareti Sorunu

PHP4.0’ü tasarlayanlar, özellikle zararlı kodları gizlemekte kötüniyetli kişilerin yararlandığı tek ve çift tırnak işaretlerinin sisteme zarar vermesini önlemek amacıyla, ziyaretçi girdilerindeki tırnak işaretlerinin otomatik olarak Escape karakteri ile zararsız hale getirilmesini sağlamış bulunuyorlar. Buna göre bir ziyaretçi bir forma söz gelimi “PHP’nin yararları” yazacak olursa bu “PHP\’nin Yararları” haline dönecektir. Kimi zaman çirkin görünse de bu, bir sitenin güvenliği için önemli bir kazançtır.

Bu sistemin işleyebilymesi için sunucu yönetiminin PHP kurulumu sırasında php.ini dosyasında gereken düzenlemeyi yapmış olması gerekir. Bunun yapılmadığı durumlarda, programcı olarak siz, PHP’nin değişkenlerin değerlerinde gerektiğinde  tersbölü işareti uygulamasını, bu değişkeni addslashes() fonksiyonu ile birlikte kullanarak çözümleyebilirsiniz. Örnek:

$yeni_degisken = addslashes($eski_degisken)

Bu dizinin ikinci kitabında güvenlik konusuna daha geniş yer vereceğiz.

PHP Kaynakları

Güvenlik dahil, PHP konusunda başvurulacak kaynakların bir kısmı şöyle sıralanıyor. Ayrıca bu kitapçığın örnek kodları arasında, PHP Hosting Companies Search the Directory.htm adlı belgede çık sayıda kurum ve firmasın listesini bulabilirsiniz:

http://www.php.net/FAQ.php

http://www.php.net/manual/config-odbc.html

http://www.techdevelopers.com

http://www.lilali.net

http://www.sqlcourse.com/

ttp://www.apache.org/info/apache_users.html

PHP – 1

PHP

 

Önsöz

PHP Desteği veren sitelerle ilgili not:

PHP’ye Giriş

PHP ve Veritabanı

PHP ve Web Sunucusu

Unix/Linux Sistemleri

Linux’ta program derlediniz mi?

Güvenli socket ve Internet Erişimi Katmanı

Windows-PWS ve IIS

IIS 4.0 ve 5.0

Browser Yetenek Dosyası: Browscap.ini

PWS 4.0

Windows’da Apache!

Windows’da MySQL

PHP’nin Yapı Taşları

PHP programını durdurmak

Değişkenler

Veri Türleri

Tür Değiştirme

Fonksiyon

Escape

Dört yararlı fonksiyon

İşlemciler (Operatörler)

Bir Arttırmak veya Azaltmak için

Sabit Değerler

Tarih ve saat Verisi

PHP’de Program Denetimi

if Deyimi

switch deyimi

switch için kısa yol

Döngüler

while döngüsü

do..while

for döngüsü

foreach

Döngüyü sona erdirmek için: break

Döngüyü sürdürmek için: continue

Fonksiyonlar

Fonksiyon Tanımlama ve Çağırma

Fonksiyona varsayılan değer verebiliriz

Değişkenlerin kapsamı: global ve static

Dizi-Değişkenler, Nesneler

Dizi Değişkenler

Dizi Değişken Oluşturalım

Dizi değişkenleri kullanalım

Dizi Değişkenlerin Düzenlenmesi

Dizileri birleştirme: array_merge()

Dizilere değişken ekleme: array_push()

Dizinin ilk elemanını silme: array_shift()

Diziden kesit alma: array_slice()

Dizileri sıralama: sort() ve rsort()

İlişkili dizileri sıralama: asort() ve ksort()

Nesneler

Bir Nesne Oluşturalım

PHP İşbaşında

Formlar

Form’dan GET Metoduyla Gelen Bilgiler

URL Kodları

Form’dan POST Metoduyla Gelen Bilgiler

Form ile işlemciyi Birleştirelim

Dosya “çıkartma”

Dosya İşlemleri

Harici Dosya (include)

include mu, require mı?

Dosyalar hakkında bilgi

Dosya var mı? file_exits()

Dosya mı, dizin mi? is_file() ve is_dir()

Dosya okunabilir mi? is_readable()

Dosya yazılabilir mi? is_writable()

Dosya çalıştırılabilir mi? is_executable()

Dosya boyutu: filesize()

Dosyaya son erişim tarihi: fileadate(), filemtime() ve filectime()

Dosyalar oluşturma ve silme

Dosya açma

Bir Fonksiyonu durdurmak için: Öl!

Dosya okuma: fgets(), fread() ve fgetc()

fseek() ile ölçü belirleme

Dosyaya yazma ve ek yapma: fwrite() ve fputs()

Kullanımdaki dosyayı kilitleyin!

Dizinlerle İşlemler

Dizin içeriğini listeleme: opendir() ve readdir()

Dizin oluşturma: mkdir()

Dizin silme: rmdir()

Bir Dosya İşlemi Örneği: Konuk Defteri

Metin Düzenleme ve Düzenli İfadeler

Temel Alfanümerik Fonksiyonları

substr()

trim()

chr()

ord()

strlen()

printf() ve sprintf()

number_format()

Tarih ve Saat Düzenleme

Düzenli İfadeler

Eşleştirme deyimleri ve işaretler

Düzenli İfadelerde Özel Karakterler

Karakter Grupları

Düzenli İfade Fonksiyonları

ereg() ve eregi()

ereg_replace() ve eregi_replace()

split()

sql_regcase()

PHP ile Veritabanı

MySQL Veritabanı

mySQL veri türleri

PHP-MySQL İlişkisi

PHP’de Güvenlik

Parola ve SSL

Tırnak İşareti Sorunu

PHP Kaynakları

 

Önsöz

Rasmus Lerdorf,  tarihin ilk dönemlerinde yani Internet’in henüz yayıldığı 1990’ların ortalarına doğru iş arıyordu; hayat öyküsünü bir kişisel sayfada yayınlamak ve başvuracağı yerlere bu sayfanın adresini verebileceğini düşündü. Fakat o dönemde özellikle üniversitelerin Unix ağlarında kurulan Web Sunucularda kişisel sayfa yapmak kolay değildi. Rasmus, kendisi için hazırladığı yazılımın Web’e aşina olmayanlar starafından da kolayca kullanabileceğini düşündü. Bu yazılımın büyükçe bir bölümü Perl dilinden alınmıştı. Adına Personal Home Page (Kişisel Ana Sayfa) dediği bu programın çok tutulması üzerine Rasmus Lerdorf, Internet Sitesi kuran herkesin birinci gün değilse bile ikinci gün farkına vardığı ihtiyacı, yani bir form yoluyla ziyaretçiden gelen bilgileri işlemeyi sağlayan ekleri yazdı ve programın adı PHP/FI (Form Interpreter/Form Yorumlayıcı) oldu. Kimileri programın bu sürümüne PHP2 adını taktı; ve bu ad, programın çok değişmesine ve gelişmesine rağmen uzun süre değişmeden kaldı.

Rasmus Lerdorf, 1995’in ortalarında, Zeev Suraski, Stig Bakken, Shane Caraveo ve Jim Winstead ile bir grup kurdu ve PHP’yi Perl’den ödünç alma rutinlerle iş yapan bir paket olmaktan çıkartıp, Nesne-Yönelimli (Object-Oriented) bir programlama dili haline getirdi. Bu grup, bugün PHP4 adı verilen bu dili geliştirmekte ve yeni işlevsellikler kazanması için sürekli çalışmaktadır. PHP, Linux gibi, Açık Sistem kurallarına tabidir; isteyen programda istediği değişikliği yapabilir; ancak bu değişiklikten para kazanamaz ve yaptığı değişiklikleri isteyen herkese açıklamak zorundadır.

Linux’un önümüzdeki yıllarda en çok kullanılan işletim sistemi olacağı yolundaki bilgiler kuşkusuz en çok Linus Torvalds’ı şaşırttı. Linux’un bu başarısındaki en önemli anahtar nokta olan açık kaynak geliştiriliyor ve dünyanın heryerinden yazılım geliştiricilerin desteğini alıyor olması. Aynı başarıyı Web yazılım geliştirme dili PHP de gösteriyor. PHP bundan iki yıl öncesine kadar adı duyulmamış basit bir dildi. Ancak şimdi gerek performans gerek destek açısından diğer Web yazılım geliştirme dilleri ile kolayca yarışıyor; hatta bunları fazlasıyla geçiyor. Hemen her türlü işletim sistemiyle çalışıyor olması da cabası. PHP, her türlü veritabanıyla sorunsuz çalışıyor olmasıyla ve  Zend derleyicisiyle daha da yaygınlık ve güç kazanacak. PHP ve açık kaynak olarak geliştirilmeye başlanan MySQL’in birlikte kullanıldıklarında yakaladıkları etkinlik binlerce Dolar verilerek alınan veritabanı ve uygulama dilleriyle yarışmanın ötesinde farklara sahip.

Türkiye’de PHP oldukça yeni kullanılmaya başlandı. Dünyadaki PHP kullanıcılarının tercih ettikleri PHP editörü PHPed’i bir Türk’ün geliştirmiş olması, hepimize haklı bir gurur veriyor. Ayrıca http://www.php.org.tr adresindeki oluşum çok kısa sürede Türkiye’de PHP’nin layık olduğu yeri alacağını gösteriyor.

Bu kitapçığı PHP’nin 4’ncü sürümüne göre yazdık. Burada verdiğimiz örnekleri uyguladığınızda beklenen sonucu alamazsanız, önce sizin sisteminizde kurulu PHP’nin sürümünü kontrol etmelisiniz. Bu kitapçıktaki örnek kodları PC Life dergisinin Internet sitesinde, http://www.pclife.com.tr/………./php_kodlar.zip adresinde bulabilirsiniz. Ayrıca bu kitapçıktaki kodların tümünün gerçek bir Web sunucuda nasıl işlediğini görmek için  http://www.mycgiserver.com/~ocal/ adresine bakabilirsiniz.

Bununla birlikte bir programlama dilinin incelikleri, ancak kodlarınızı kendiniz yazarsanız öğrenilebilir. Örnek kodlardan, ancak kendi yazdığınız kodlar beklediğiniz sonucu vermediği taktirde, karşılaştırma amacıyla yararlanmalısınız. Sizi biraz da buna zorlamak için yer yer konuları bu kodların yazıldığı varsayımı ile ele alacağım.

Bugüne kadar PHP programlarrına .php3 uzatmasını vermek adeta gelenek halini almıştı; ancak PHP’nin 4’ncü sürümüyle birlikte, konfigürasyon ve INF dosyaları, yapılandırma sırasında işletim sistemlerine ve Web sunucularına varsayılan değer olarak sadece .php uzatmasını tanımasını bildiriyorlar. PHP programlarınıza bundan başka uzatmalar verecekseniz, Linux’ta Apache konfigürasyon dosyasını, Windows’da ise Registry kayıtlarını değiştirmeniz gerekir.

İki bölüm olarak sunacağımız PHP kitapçığının birinci bölümünün yazılmasında yurdumuzda PHP kullanıcılarını eğitme ve destekleme hareketinin öncüleri Sayın Kayra Otaner, Serdar Soydemir ve  Özgür Akan, değerli yardımlarını esirgemediler. İkinci kitapçıkta yer alacak uygulamaların tümünü bu grup geliştirdi ve Açık Kaynak hareketinin gerçek temsilcileri olduklarını göstererek, serbestçe kullanılmak üzere okuyucularımıza sundular. Kendilerine sonsuz teşekkürlerimizi sunarız. Bununla birlikte bu kitapçıkta varolan hataların tümü bana aittir.

PHP Desteği veren sitelerle ilgili not:

Bu kitapçıkta bir kaç sayfa ilerledikten sonra, yapmak isteyeceğiniz ilk işlerden birinin ücretli veya ücretsiz PHP desteği veren bir Wes sitesi evsahibi (Hosting) firması aramak olacağını tahmin ediyorum. Bu amaçla aramalarınıza http://www.pageresource.com/putweb/index.html adresinden başlamanızı salık veririm. Eğer doğruca böyle bir evsahibi firmaya ulaşmak isterseniz http://www.mycgiserver.com adresine gidebilirsiniz. Kitapçığın sonunda çeşitli PHP kaynaklarının bir listesini de bulabilirsiniz.

PHP’ye Giriş

C/C++, Pascal, hatta Visual Basic bilen kişiler için PHP öğrenmek hemen hemen bir öğleden sonrayı ayırmak suretiyle yapılabilecek bir iştir. Bu dillere aşina olmayanlar ise belki bir kaç öğleden sonralarını ayırmak zorunda kalabilirler! PHP, bir Script dilidir; yani kodları düz yazı dosyaları halinde kaydedilir ve kullanılacağı ortamda bir yorumlayıcı tarafından yorumlanır. Bu, PHP ile yazacağınız programları, derlemek yani ortaya bir EXE veya çalıştırılabilir başka bir dosya çıkartmaya gerek olmadığı anlamına gelir. Fakat PHP Script’lerinizi çalıştırabilmek için bu dili bilen bir programa ihtiyacınız vardır. Bu programın tek başına (komut istemci penceresinde veya terminal ekranında) çalışması mümkün olduğu gibi, Web Server tarafından da çalıştırılabilir olması gerekir. Başka bir deyişle Web Sunucu programının PHP anlar hale getirilmesini sağlamak zorundayız.

PHP yorumcusu, bugün Zend-çekirdeği adı verilen bir Scripting teknolojine dayalı olarak, Zeev Suraski ile Andi Gutmans tarafından sıfırdan, tamamen yeniden yazılmış bulunuyor. Zend, tıpkı Windows Script Host ve mesela Visual Basic for Applications (VBA) gibi, işletim sistemine kendisi ile uyumlu Script dilleriyle yazılmış programları çalıştırma imkanı kazandıran bir teknolojidir (Zend konusunda ek bilgiyi Internet’te www.zend.com adresinde bulabilirsiniz.) Bugün bu dilin resmî adı “PHP: Hypertext Preprocessor” (Hiper-metin ön-işlemcisi) olarak değiştirildi, ve çeşitli Web Server’ların PHP dili anlaması için gerekli yorumlayıcıları yeniden üretlidi. 20 Ocak 200’de İsrail’de PHP’nin ilk uluslararası konferansı yapıldı ve 4’ncü sürümünün betası ortaya kondu.

Peki ama PHP nedir?

PHP ile artık oturup her türlü işlevselliği sahip programlar yazabilirsiniz; yani PHP başlı başına uygulama alanları bulabilecek düzeye ulaşmıştır. Başka bir deyişle PHP ile oyun programından tutun veritabanı yönetimine kadar hemen her türlü programı yazabilirsiniz. Bizi bu kitapçıkta ilgilendiren tarafıyla PHP, Web Sunucu’ya bir takım işler yaptırmak için program yazma dilidir. Tıpkı CGI/Perl veya ASP ya da ColdFusion, Java (Javascript değil!) gibi! PHP kodları, oluşturacağımız HTML sayfalarında HTML etiketlerinin arasında kendi özel ayracı içinde yazılır:

            <html>

            <?PHP

                  echo (“Merhaba Dünya!”);

            ?>

            </html>

İster kişisel bilgisayarımızda, ister gerçek Internet ortamında olsun, bir Web Sunucu, ziyaretçinin (Internet istemci programının, Browser’ın) talep ettiği dosya adının uzatması olarak “.PHP,”  “.PHP2,” “.PHP3,” veya “.PHP4” görünce, kendine kendine, “Yine bana iş çıktı!” diye düşünür! Çünkü Web Server, uzatması “.htm” veya “.html” olan bir dosyayı, kendi sabit disklerinden birinde bulur ve zahmetsizce, ziyaretçinin bilgisayarına gönderir. Fakat, “.asp,” .pl,” “.cfm” gibi, “.PHP” uzatması, Web Sunucu’ya bu sayfayı olduğu gibi, alıp ziyaretçinin Browser’ına göndermek yerine, önce PHP yorumlayıcıyı çağırarak, ona teslim etmesi gerektiğini bildirir. PHP yorumlayıcısı (yani Windows ortamında PHP.exe veya 4’ncü sürümle gelen PHP4isapi.dll, Unix ve türevlerinde çalıştırılabilir PHP dosyası), kendisine teslim edilen bu belgede önce “<?PHP” ve “?>” ayraçları arasındaki PHP kodlarını seçerek alır ve gereği ne ise onu yapar. Bu ayraçların içinde kalan kodlar, bizim yapılmasını istediğimiz işlemin komutlarıdır. HTML ile yetinmeyip, PHP kullanmamızın sebebi, bu komutların HTML’in yapayacağı şeyleri yapmasıdır.

HTML’in yapamayacağı şeylerin başında, Web Sunucusu’nda yapılacak işler vardır. Sözgelimi HTML etiketlerini kullanarak, Web Sunucusu’ndaki bir veritabanı dosyasını açıp, içindeki verileri okuyamayız. HTML yoluyla Web Sunucusu’nun sabit disklerindeki düz yazı dosyalarını da okuyamayız ve bu disklere dosya yazamayız. HTML etiketleri ile Web ziyaretçimizden bilgi edinebilir ve bunları Sunucu’ya yollayabiliriz; ama o kadar! Bu bilgileri işe yarar şekle sokmak için bize Server’da çalışan bir program gerekir. Server’da çalışan program, EXE ve DLL veya JSP (Java Server Pages)  gibi bir “gerçek program”; veya Perl, ASP ve PHP gibi Script diliyle yazılmış bir program olabilir. (Gerçek programları yazanlar, tabiî, sizin Script diliyle yazılmış programlara “program” demenize çok kızarlar! Ama bu Script pogramlarının program olmasını hiç engellemez.)

Ne diyorduk? Web Sunucu, “.PHP” uzatmasını görünce telaşa kapılır, bu dosyayı PHP yorumlayıcısına verir ve o da “<?PHP” ve “?>” ayraçları içindeki kodları icra eder, demiştik. Bu icraatın sonunda ortaya çıkan ürün eğer ziyaretçiye gönderilecekse, HTML etiketleri içinde gönderilir; yani ziyaretçi asla PHP kodlarını göremez. Kimi zaman PHP programımızın çalışması sonucu ortaya ziyaretçiye gönderilecek bir ürün çıkmaz; elde edilen sonuç ya başka bir programa (örneğin elektronik ileti gönderen bir Sendmail progamına) hammadde olarak verilir, ya da Server’da sabit diske yazılır. Fakat her durumda, Web ziyaretçimiz bizim PHP kodlarımızı göremez; bu Web sayfalarımızda PHP kodu kullanmamız halinde, sayfalarımızın Browser tarafından tanınması veya tanınmaması gibi bir durumun ortaya çıkmaması demektir. Ziyaretçi ne tür Browser kullanırsa kullansın, kendisine Sunucu’dan daima saf HTML kodu geleceği için, sayfalarımızı rahatça görebilecektir. Tabiî bir nokta var: Sayfalarımızda herhangi bir Browser’ın arızalı yorumladığı veya hiç yorumlayamadığı HTML etiketleri bulunabilir; ya da söz gelimi ziyaretçiye giden HTML’in içinde Browser’da çalıştırılacak olan başka Script kodları bulunabilir; ve Browser bu kodları anlamayabilir. Örneğin, HTML sayfanızda VBScript kodları kullanmış iseniz, Netscape ile sitenize bağlanmış olan kişiler bu kodun oluşturmasını istediğiniz etkiyi göremeyeceklerdir; çünkü Netscape VBScript anlamaz! PHP ile yazacağınız Web programlarının (eski deyimiyle “sayfaların”) oluşturacağı HTML belgesinin Browser türleri ve sürümleri ile uyarlılığını sağlamak yine Web programcısı olarak sizin sorumluluğunuzdadır.

Özetlersek, PHP bir CGI programlama dilidir; bu dille, Web Sunucusu ile Web ziyaretçisi arasındaki buluşma noktası olan CGI’da bilgi alışverişi yapılabilir; Sunucu’da bulunan başka programlar çalıştırılabilir ve böylece Web sayfalarımıza HTML’in sınırlamalarının ötesinde hareket ve ziyaretçi ile etkileşme olanağı kazandırılabilir.

Sanırım iyi bir Web programcısı olarak şu anda ekrana “Merhaba Dünya!” yazdırmak için sabırsızlanıyorsunuz. Ama bunun için, PHP sayfanızı ya PHP-uyumlu bir Web Sunucusu’ndaki Web sitenize yüklemek, ya da kişisel bilgisayarınızdaki kişişel Web Sunucusu’na PHP öğretmek zorundasınız. Bu ikinci yöntemi kuvvetle tavsiye ederim; çünkü yazacağınız PHP programlarını gerçek Internet Sunucusunda sınamak, bazen arzu edilmeyen durumlara yol açabilir. Oysa kişinin bu denemeleri, evinde ve işyerinde kendi bilgisayarında yapması, çoğu zaman daha az başağrısı ve gözyaşına yol açar! En azından, PHP hatalarınızı ve gözyaşlarınızı sizden başka gören olmaz!

PHP ve Veritabanı

Kişisel bilgisayarınızdaki kişisel Web sunucusuna PHP öğretme işlemine geçmeden önce, hemen hemen PHP’nin ikiz kardeşi sayılan MySQL’den ve onun rakibi PostgreSQL’den kısaca söz edelim.

PHP’nin varlık sebeplerinin başında, ticarî Unix ve Microsoft Windows işletim sistemlerinden ayrı, ticarî olmayan Açık Sistem ortamlarında çalışan bir Script dili ile bu dille kullanılabilecek yine Açık Sistem ürünü bir veritabanı erişim ve yönetim aracına sahip olmak gelir. Perl, gerçi PHP’den çok önce Açık Sistem ürünü olarak, isteyen Web Programcısı’nın ücretsiz edineceği bir CGI programlama dili olarak Web’in ilk gününden beri Web Programcısının emrinde idi. Ama Perl, metin dosyalarından yazı çekmek ve bunları biçimlendirerek rapor haline getirmek amacıyla geliştirilen bir dil olduğu için, özellikle veritabanına dayalı işlemlerde programcıya çok güçlük çıkartıyordu. ASP ise (ASP desteği sağlayan ve ücretsiz Web sitesi veren firmaların giderek artmasına ve veritabanı konusunda hem kolaylık, hem de büyük bir etkinlik sağlamasına rağmen) çoğunlukla ücretli Web sitesi aldığımız ticarî amaçlı evsahibi (Hosting) firmalarının sağladığı bir teknoloji olarak görüldü. PHP, tasarımcılarının MySQL ve PostgreSQL teknolojilerini geliştiren kurum ve firmalarla yaptığı yakın işbirliği sonucu ikinci sürümünden itibaren veri-yönlendirmeli Web uygulaması alanında önemli bir araç olarak belirdi. Dolayısıyla, PHP kurulumu dendiği zaman, kendiliğinden, MySQL kurulumu da kastedilmiş olur. Şimdi PostgreSQL da ekleyebiliriz.

PHP, bir dildir; MySQL ve PostgreSQL ise bir demet sürücüdür. PHP ile, Web Server’a sayfanızı Internet ziyaretçisine göndermeden önce bir takım komutları icra etmesini, bir takım veri dosyalarını açıp içindeki bilgileri alıp bunları HTML kodlarıyla bezeyip, Browser’a bildiğimiz klasik HTML sayfası olarak göndermesi talimatını veririz. MySQL ve PostgreSQL ise, Windows sistemlerinde Denetim Masası’nda gördüğünüz ODBC Veri Kaynağı Yönetmeni adlı araç gibi, bir vertabanı sunucusu, yani Database Server pprogramlarıdır. Yakın zamana kadar bu iki veritabanı yönetim aracı arasında fazla bir çekişme yoktu. Ancak şimdi özellikle Linux kullanıcıları topluluklarında iki program arasında verimlilik testleri yapılıyor; hangisinin daha iyi olduğnuna ilişkin yoğun bir tartışma sürüyor. PHPBuilder.com uzmanları, yaptıkları bir çok denemede, MySQL’in daha hızlı ve daha etkin çalıştıkları sonucuna varıyorlar. (Bu konuda daha geniş bilgi edinmek için Internet’te www://PHPbuilder.com/columns/tim20000705.PHP3 adresine bakabilirsiniz.)

MySQL, bir kullanıcı lisansı 200 Dolar olan ticarî bir program iken 2000 yılı ortalarında GPL (GNU General Public License/GNU Kamusal  Lisans) uygulamasına geçmiş ve ücretsiz dağtılır hale gelmiş bulunuyor. Buna göre MySQL’i bir ticarî uygulamanın içinde motor olarak kullanacaksanız üreteci firmaya lisans ücreti ödemeniz gerekir; bunun dışındaki uygulamalar için programı Internet’ten indirerek kullanabilirsiniz. PHP için MySQL’e gerek yoktur. PHP, bir NT veya Win9x tabanlı Web Server’da çalıştırılıyorsa, Microsoft’un ODBC sürücüleri ile çalışabilir; ve ODBC’nin okuduğu bütün veritabanlarından veri çekebilir. (ODBC’nin Unix-Linux sürümü de vardır.)  Ayrıca PHP için Adabas, dBase, Empress, FilePro, Informix, InterBase, mSQL, Oracle, Solid, Sybase, Velocis ve bir çok Unix veritabanı yöneticisi için geliştirilmiş add-on (sonradan eklenen) modüller vardır. PHP, bir çok LDAP istemci programı için yazılmış API’lere de sahiptir. PHP ile IMAP, SMTP gibi Internet elektronik mektup protokollerini kullanmak da mümkündür.

Oracle

ORACLE 

 Giriş

Teknolojinin her dalında olduğu gibi VTYS alanında da çok hızlı gelişmeler yaşanmaktadır. Bu haftaki dersimizde size bazı güncel VTYS’leri bir miktar tanıtmaya çalışacağız. Tabii ki bu tanıtımda örnek VTYS’lerin tüm özelliklerini tanıtma iddiasında değiliz. Sadece temel ve ayırdedici özelliklerini tanıtmayı amaçlıyoruz. Daha ayrıntılı bilgiyi VTYS’nin web sitesinden veya ilgili şirketlerden edinebilirsiniz. 

Örnek VTYS’lerimiz: 

ORACLEOracle Corporation  

INFORMIXInformix Corporation 

ASESybase, Inc.  

ORACLE

İlişkisel Veritabanı Yönetim Sistemleri (Relational Database Management Systems – RDBMS) büyük miktarlardaki verilerin güvenli bir şekilde tutulabildiği, bilgilere hızlı erişim imkanlarının sağlandığı, bilgilerin bütünlük içerisinde tutulabildiği ve birden fazla kullanıcıya aynı anda bilgiye erişim imkanının sağlandığı programlardır. Oracle veritabanı da bir ilişkisel veri tabanı yönetim sistemidir.

                Oracle veritabanının özellikleri şunlardır:    

  • Büyük miktarda veri tutabilmekte ve verilerin depolandığı alanları ayarlama imkanı vermektedir.
  • Aynı anda çok sayıda kullanıcıya verilerin bütünlüğünü bozmadan hizmet verebilmektedir. Oracle 8 sürümü ile birlikte on binlerce kullanıcıya hizmet verebilmektedir.
  • Günün 24 saati ve haftalar boyu hiç kapatılmadan çalışabilmektedir.
  • İşletim sistemi, veri erişim dilleri ve ağ iletişim protokolleri standartlarıyla uyumludur.
  • Yetkisiz erişimleri engelleme ve kontrol edebilme imkanı sağlamaktadır.
  • Bütünlüğü veritabanı düzeyinde sağlayabilmektedir, böylece daha az kod yazılmaktadır.
  • İstemci/Sunucu mimarisinin bütün avantajlarını kullanabilmektedir.

Oracle ile ilk defa karşılaşan kullanıcılar genellikle Delphi, Visual Basic gibi görsel programlama dillerine benzeyen uygulamalarla karşılaşmayı umarlar. Oysa ki yukarıda da belirttiğimiz gibi Oracle bir ilişkisel veritabanı yönetim sistemidir. Yani bir programlama dili değildir. Fakat Oracle tarafından geliştirilen ve Oracle’ın kendi uygulama geliştirme araçları içerisinde kullanılan bir programlama dili vardır. Oracle ürünleri genellikle büyük çaplı veri kontrolünü gerektiren uygulamalarda kullanılır. Öncelikle bir ağda Oracle veritabanı sadece sunucu olarak adlandırılan bilgisayara yüklenir. Bu sunucu Oracle’ın desteklediği herhangi bir işletim sistemiyle çalışıyor olabilir. Yani Oracle’ın faklı işletim sistemleri için farklı sürümleri vardır. Bu sunucu bilgisayara kurulan veritabanı üzerinde tablolar, indeksler, eşanlamlar,tablo uzayları ve ihtiyaç duyulan kayıtlı prosedürler oluşturulur. Bunlar raporun sonraki bölümlerinde anlatılmaktadır. Oracle’ın bu veritabanına erişerek uygulama programı geliştirmeye yarayan diğer ürünleri de istemci bilgisayarlara kurulur. Tabi sunucu bilgisayara da isteğe bağlı olarak bu ürünler kurulabilir.

Oracle Ürünleri

                Aşağıda şu an kullanımı en güncel olan değişik Oracle ürünleri tanıtılımıştır.

Oracle RDBMS

 

 

Oracle ilişkisel veritabanı yönetim sistemi Oracle şirketinin ana ürünüdür. Bu ürünün şu an en yeni sürümü Oracle9i RDBMS’dir. Biz bu çalışmada bir önceki sürüm olan Oracle8i’yi esas alacağız. Oracle 8i’den bir önceki sürüm Oracle 7 ve onun bir önceki sürümü de Oracle 6’dır.

 

 

 

 

Oracle Uygulama Geliştirme Araçları

 

 

                Oracle’ın veritabanı uygulamaları geliştirmek için görsel ürünleri bu grupta yer alır. Oracle’ın program geliştirmek için kullanılan bu ürünlerinin eski adı Oracle Power Objects idi. Daha sonra Oracle Developer 2000 ve sonra da Oracle Developer 6 ürünleri geliştirildi. Developer 2000 ve Developer 6 içerisinde Form Builder, Report Builder, Graphics Builder, Procedure Builder ve Schema Builder ürünlerini içerir. Form Builder kullanıcıya sunulacak arayüzlerin geliştirildiği programdır. İşte bu uygulama görsel bir programlama dilinin uygulama geliştirme ortamına benzer. Report Builder ürünü veritabanından elde edilen bilgiler ile raporlar hazırlamaya yarar. Özellikle banka ve kamu kuruluşlarının ihtiyacı olan fatura, evrak gibi belgelerin hazırlanıp, çıktı alınması için geliştirilmiş bir programdır. Procedure Builder sürekli kullanılacak kodların prosedürler halinde oluşturulup, kütüphaneler olarak kaydedilmesi işlemine yarayan bir programdır. Schema Builder ise veritabanı nesnelerinin görsel olarak oluşturulabilmesi için geliştirilmiş bir uygulamadır. Burada tablo, görüntü, eşanlam oluşturma, tablolar arası ilişki kurma,tablo kısıtlamaları oluşturma işlemleri görsel olarak yapılabilir.

 

 

 

 

SQL*Plus

 

 

                SQL*Plus, Oracle veritabanında sorgulama yapmak ve SQL komutlarını çalıştırmak için kullanılan bir araçtır. SQL*Plus’da SQL komutlarının yanısıra PL/SQL komutları da kullanılabilmektedir. Bu çalışmanın diğer bölümlerinde anlatılan SQL komutları SQL*Plus kullanılarak hazırlanmıştır.

 

 

 

 

PL/SQL

 

 

                PL/SQL (Procedural Language/SQL), yapısal dillere ait özelliklerin standart SQL’e eklenmesiyle ortaya çıkan Oracle’a has bir dildir. PL/SQL Oracle firmasının piyasaya sürdüğü her üründe önemli bir yere sahiptir. Kullanıcılar PL/SQL’i kullanarak programlarına bir çok yeni özellikler katmaktadırlar. Bunlar arasında;

 

 

 

  • PL/SQL tabanlı kaydedilmiş yordamlar(stored procedures) ve veritabanı tetiklemeleri(triggers) ile önemli iş kurallarını programlamak

 

  • Oracle Developer ürünleri ile güçlü ve kolay kullanılabilir görsel ortamlarla programları detaylandırmak ve daha rahat kontrol etmek
  • Oracle tabanlı uygulamalarda nesne-tabanlı(object-oriented) tasarımlar yapma Web sayfalarından Oracle veritabanlarına link yapma

PL/SQL’in belki de en önemli özelliği istemci-sunucu ortamları tasarlama ile ağ üzerinde dağıtık işlemler yapma ve bir çok sorguyu çalıştırma imkanı sunmasıdır. PL/SQL dili Ada dilinden sonra tasarlanmıştır. PL/SQL’de en gelişmiş yordamsal dillerde olan veri tipleri, blok yapısı, şartlara bağlı ve bağlı olmayan kontrol cümleleri, bir çok döngü tipi, hata durumlarında kullanılacak yordamlar ve kullanıcı tarafından tanımlanabilecek nesneler yer almaktadır.

Net8

 

 

                Net8 Oracle’ın bir ağ ürünüdür. Farklı bilgisayarların veritabanına bağlantı kurması ve ve istemci-sunucu arasında veri alışverişinin sağlanabilmesi Net8’in ana görevidir. Net8 ağdaki her bilgisayara kurulur. Ağ bağlantısı sağlandığında NET8 istemci ile sunucu arasında bir veri taşıyıcısı gibi işlem görür.

 

 

 

 

 

 

 

 

 

           

Ağ üzerinde bir istemcinin sunucudaki veritabanına erişebilmesi için, sunucuda bir ağ servis adının(Net Service Name) ve bir dinleyicinin(LISTENER) oluşturulması gerekir. Oracle Enterprise Edition ile birlikte gelen Net8 Assistant ile bu gerçekleştirilebilir. Ağ servis adları, veritabanı gibi bir servisi ağda tanımlamak amacıyla basit bir yöntem olarak kullanılır.

Aşağıda Ne8 Assistant görüntüsü verilmiştir. Verilen şekilde ağ erişimi oluşturmak için gereken işlemler oldukça basittir.

 

 

 

 

 

 

 

 

 

 

SQL*Net

 

            SQL*Net Net8’in yardımcı programıdır. Bir istemci bilgisayara Oracle Forms ürününün yüklendiğini düşünelim. Bunun için istemci bilgisayar SQL*Net ile oluşturulan veritabanı takma adını(alias) kullanır. Yukarıda Net8 konfigürasyonunun istemci bilgisayarlarda da yapılması gerektiğini söylemiştik. İşte bu konfigürasyon istemci bilgisayarlarda SQL*Net sayesinde yapılır. Burada veritabanına verilecek takma isim, protokol adı, ana bilgisayar adı (veritabanının bulunduğu) ve veritabanının SID olarak girilen ismi bilgileri girilerek düzenleme yapılır.

 

 

 

 

 

 

 

 

Oracle8i Enterprise Edition ve Gerekli Donanım

 

 

 

Bu rapor Oracle8i Enterprise Edition for Windows NT Release 8.1.5 sürümü üzerine düzenlenmiştir. Oracle8i Enterprise Edition CD’sinde üç farklı ürün yer almaktadır:

  • Oracle8i Enterprise Edition (Server)
  • Oracle8i Client
  • Oracle Programmer

 

 

Oracle8i

 

 

 

 

Enterprise

 

Edition(Windows NT)

 

 

 

                Yükleme Türü

Açıklama

Typical 

Tam anlamıyla bir veritabanı kullanmak isteyenler için tavsiye edilen yükleme türüdür. Bir başlangıç veritabanı, ağ servisleri, Oracle yardımcı ürünleri ve yardım dokümanları yüklenir.720 MB yer kaplar. Pentium 133 ya da Pentium 166 işlemci ile kurulabilir. Önerilen işlemci Pentium 200 dür. 96 MB RAM ile çalışabilir. Tavsiye edilen bellek ise 128 MB ‘tır.

Minimal 

Minimum veritabanı paketi kullanmak isteyenler için önerilir. Bir başlangıç veritabanı, ağ servisleri ve bazı yardımcı ürünleri içerir. 520 MB yer kaplar. Pentium 133 ya da Pentium 166 işlemci ile kurulabilir. Önerilen işlemci Pentium 200 dür. 64 MB RAM ile çalışabilir. Tavsiye edilen bellek ise 96 MB ‘tır.

 

Oracle8i Client(Windows NT ve Windows 95/98)

 

 

 

 

Yükleme Türü

Açıklama

Typical 

Veritabanı yöneticileri için veritabanına bağlanma ve veritabanı yönetim işlerini gerçekleştirme araçlarını yükler. 299 MB yer kaplar. Intel 80486 işlemci ile çalıştırılabilir. Tavsiye edilen Pentium 133 ya da Pentium 166 dır. En az 32 MB RAM ile çalıştırılabilir. Önerilen 64 MB’tır.

 

 

 

Oracle Programmer(Windows NT ve Windows 95/98)

 

 

 

 

Yükleme Türü

 

Açıklama

Typical 

Veritabanına erişebilen geliştirme araçları ve ara yüzlerini yükler. Bu paket, ön derleyicileri(precompilers), ağ servislerini ve yardım dokümanlarını içerir. 267 MB yer kaplar. Intel 80486 işlemci ile çalıştırılabilir. Tavsiye edilen Pentium 133 ya da Pentium 166 dır. En az 32 MB RAM ile çalıştırılabilir. Önerilen 64 MB’tır.

 

 

 

 

 

 

 

 

Oracle Veritabanı Yapısı

 

 

 

Oracle veritabanının, işletim sistemi tarafından bakıldığında, biri fiziksel diğeri mantıksal olmak üzere iki bölümü vardır. Fiziksel bölüm, işletim sisteminden görünen kısımdır. Bunlar Data File(Veri Dosyası), Control File(Kontrol Dosyası) ve Log File(Log Dosyası) ‘dan oluşmaktadır. Mantıksal Bölüm, bir ya da daha fazla tablo uzayı(Tablespace) ve tablolar(table), görüntüler(view), sıralar(sequence), eşanlamlar(synonym), indeksler(index), kümeler(cluster), veritabanı bağlantıları (database link), prosedürler(procedure), fonksiyonlar(function), ve paketlerden(package) oluşan şema nesnelerinden oluşmaktadır. Fiziksel bölüm işletim sistemi tarafından görülebilmesine rağmen, mantıksal bölüm ancak Oracle’a bağlanıp, SQL komutları çalıştırılarak görülebilmektedir. Yani, Oracle kurulu herhangi bir makinede, SQL bilgisi olmayan bir insan, Oracle’ın sadece fiziksel bölümünü görebilmektedir.

                Oracle veritabanındaki her nesnenin bir sahibi(kullanıcı olarak bahsedilir) vardır. Her kullanıcı bir veya daha fazla tablo uzayına sahip olabilir. Her nesne, ait olduğu kullanıcının herhangi bir tablo uzayında (mantıksal olarak) bulunur. Her tablo uzayı da, kendisine sahip olan kullanıcının nesnelerini tutmak için işletim sisteminde bir veya daha fazla veri dosyasına sahip olabilmektedir.

                Sonuç itibariyle, veritabanındaki her nesnenin bir kullanıcısı vardır ve bu nesneler mantıksal olarak o kullanıcının sahip olduğu tablo uzaylarının herhangi birinin (hangisi olduğu komutlarla öğrenilebilir) içerisinde, fiziksel olarak da o kullanıcının sahip olduğu tablo uzayının herhangi bir veri dosyasında bulunur. Fakat, o veri dosyasının içerisine işletim sisteminden bu nesneyi bulmak için bakılamaz. Bu nesnenin sahibi ve mantıksal yeri “DML”(veri işleme dili) komutları ile bulunabilmektedir.

 

 

Fiziksel Bölüm

            Fiziksel bölüm veritabanını oluşturan işletim sistemi dosyalarıdır. Bir Oracle veritabanı fiziksel olarak bir ya da daha fazla veri dosyası, iki ya da daha fazla log dosyası, bir ya da daha fazla kontrol dosyasından oluşur.

 

Veri Dosyaları(Data Files)

 

 

 

            Veri dosyaları veri tabanındaki tüm verileri tutan dosyalardır. Tablo, indeks gibi mantıksal veritabanı yapılarının içerisindeki veriler fiziksel olarak veri dosyalarında tutulurlar. Bir veri dosyası kendisi için ayrılan alan dolduğunda,  kendi sahip olduğu alanı artırabilecek özelliklere sahiptir. Bir ya da daha fazla veri dosyası mantıksal bir veritabanı depolama ünitesi olan bir tablo uzayını oluşturular.

            Normal veritabanı işlemleri boyunca bir veri dosyası içerisindeki veriler okunur ve Oracle için ayrılan belleğe getirilirler. Örneğin bir kullanıcının veritabanındaki bir tablonun verilerine erişmek istediğini varsayalım. Eğer istenilen veriler bellekte yer almıyorsa, ancak o zaman uygun veri dosyasından okunur ve belleğe getirilirler.

            Değişikliğe uğrayan veriler ya da yeni eklenen veriler veri dosyalarına hemen yazılmazlar. Sabit diske erişimi azaltmak ve böylece sistemin performansını artırmak için veriler bellek havuzunda tutulur ve gerektiğinde hepsi birden uygun veri dosyalarına kaydedilirler. Bunu Oracle artalan işlemleri belirler.

 

Kontrol Dosyaları(Control Files)

 

 

 

            Tüm Oracle veritabanları kontrol dosyasına sahiptir.  Bir kontrol dosyası veritabanı adı, veri dosyaları ve log dosyalarının adı ve diskteki yeri, veritabanının oluşturulma tarihi vb. veritabanı ile ilgili bilgileri tutar.

            Her veritabanı oturumu açıldığında Oracle bu dosyayı kontrol ederek gerekli bilgileri alır. Eğer veritabanında fiziksel bir değişme olursa(yeni bir log dosyası ya da veri dosyası oluşturulması gibi), yapılan değişiklikler Oracle tarafından otomatik olarak kontrol dosyalarına yansıtılır.

 

Log Dosyaları(Log Files)

 

 

 

            Redo Log dosyaları olarak bilinen bu dosyaların amacı veriler üzerinde yapılan tüm değişiklikleri kaydetmektir. Eğer veri dosyalarına kalıcı olarak kaydedilmiş olan, değişikliğe uğramış kayıtlarda bir bozukluk olursa yapılan değişiklikler redo log dosyalarından sağlanabilir ve işlemler kaybolmaz. Birden fazla tekrarlanan bozukluk durumlarında redo log dosyalarının da bozulmasını engellemek için Oracle farklı diskler üzerinde redo log dosyalarının birden fazla kopyasının alınmasına olanak sağlar.

            Bir veritabanı işlemi sırasında elektrik kesilirse, bellekteki veriler veri dosyalarına kaydedilmeyecek ve verilerin kaybolması durumuyla karşılaşılacaktır. Oracle veritabanı tekrar açıldığında redo log dosyalarında yapılan son değişiklikler veri dosyalarına yansıtılarak verilerin kaybolması engellenir.

Mantıksal Bölüm

 

 

            Oracle veritabanının mantıksal yapısı tablo uzaylarını(tablespaces), şema nesnelerini(schema objects), veri bloklarını(data blocks), genişlemeleri(extents) ve parçaları(segments) içerir.

 

 

 

Tablo Uzayı(TableSpace)

 

 

 

                Bir veritabanı, ilişkili mantıksal yapıların gruplanmasını sağlayan ve tablo uzayı olarak bilinen mantıksal depolama ünitelerine bölünmüştür.

 

 

 

 

 

            Yukarıdaki şekil veritabanı, tablo uzayı ve veri dosyaları arasındaki ilişkiyi açıklamaktadır. Buna göre:

·         Bir veritabanı bir ya da daha fazla tablo uzayına bölünmüştür.

·         Tablo uzayı içerisindeki tüm mantıksal yapıları fiziksel olarak depolayabilmek için, her tablo uzayı bir ya da daha fazla veri dosyasına sahip olabilir.

·         Tablo uzaylarının toplam kapasitesi, sahip oldukları veri dosyalarının toplam kapasitesine eşittir.(Yukarıdaki şekil için SYSTEM tablo uzayı 2MB, USERS tablo uzayı 4MB).

·         Tablo uzaylarının toplam kapasitesi veritabanının toplam kapasitesini belirler.(6 MB)

            Bir tablo uzayı açık ya da kapalı olabilir. Tablo uzayı kapalı olduğunda bu tablo uzayının içerisindeki nesnelere erişilemez. Bir tablo uzayı yönetim amaçlı olarak kapalı duruma alınabilir.

 

Veri Tabanı Şema Nesneleri

 

 

 

            Şema nesneleri mantıksal veri depolama yapıları olarak bilinir. Veritabanı üzerinde kullanıcının belirli işleri yapabilmesi için tanımlanan bu yapılar tablolar, görüntüler, sıralar, eşanlamlar, indeksler, kümeler, veritabanı bağlantıları, prosedürler, fonksiyonlar, ve paketlerdir. Bir şema ise bu nesnelerin oluşturduğu gruptur.

 

 

 

Küme(CLUSTER)

 

 

 

                Aynı anda sorgulanan birden fazla tablonun bir arada kaydedilmesine “cluster” denir. Bu yapı, beraber sorgulanan tablolarda hız kazanmak için çok önemlidir. Örneğin “isci” tablosu ile “bolum” tablosunun(bu tabloların yapısı için SQL bölümüne bkz.) her ikisi de ortak olarak “bolum” ve “bolumno” alanlarını içermekte. Yani “isci” tablosundaki “bolum”, “bolum” tablosundaki “bolumno” alanına karşılık geliyor. Burada oluşturulacak bir cluster’da her iki tablo veritabanında yan yana getirilerek aynı veri bloğu içerisine kaydedilir.Böylece daha hızlı erişim sağlanır.               

 

İndeks(INDEX)

 

 

 

İndeksler tablo ve cluster’lar için kullanılan veri tabanı nesneleridir. Burada amaç aranılan bir kayda daha hızlı erişimdir. Özellikle üzerinde çok arama yapılan alan veya alanlar üzerinde indeks oluşturmak çok etkilidir.  İndeks oluşturulduğunda ilgili tablonun kayıtları yer değiştirmez. Sadece ilgili kayıtların kayıt numaraları olarak adlandırılan “rowid” ‘ler alınarak sıralama yapılır.

            Bir tablo üzerinde oluşturulabilecek indeks sayısı sütunların kombinasyonları farklı olduğu müddetçe sınırsızdır. Bir sütun diğer sütunlarla değişik kombinasyonlarda kullanıldığı müddetçe birden fazla indeks içerisinde yer alabilir.  Aynı sütun kombinasyonlarının indeksi, faklı indeks ismi kullanarak oluşturulmaya çalışılsa bile gerçekleştirilemez.

            İndeksleme işleminin gerçekleştirilmesinde Oracle çoğunlukla B-tree indeksleme metodunu kullanır. Bunun yanında “hash cluster indexes”, “reverse key indexes”, ve “bitmap indexes” yöntemlerini de kullandığı bilinmektedir.

            İndeksler mantıksal ve fiziksel olarak oluşturuldukları tablodan bağımsızdırlar. Eğer bir indeks silinirse, ilgili tablo zarar görmez, çalışmaya devam eder. Fakat indeks olmadığı için veri erişim süresi artacaktır.

            Oracle bir indeks oluşturulduğunda onu otomatik olarak kullanmaya başlar ve  indeksin oluşturulduğu tablodaki silme, güncelleme ve ekleme işlemleri indekse otomatik olarak yansıtılır.

 

Rol(ROLE)

 

 

 

            Oracle veritabanında her nesnenin ait olduğu bir kullanıcı vardır. Bir kullanıcı bir başka kullanıcının nesneleri üzerinde işlem yapmak isterse buna hakkı olması gerekir. Bir nesne üzerinde işlem yapabilme yetkisine hak denir. Örneğin veritabanına bağlanma, tablo oluşturma, bir başkasına ait tablodan kayıt listeleme, bir başkasının prosedürünü çalıştırma birer haktır. Bu haklar kullanıcılara atanmak suretiyle kullanıcıların bu işlemeleri gerçekleştirmeleri sağlanır. Hakların kullanıcılara atanması iki şekilde olabilir. Birinci olarak  bir tabloya kayıt ekleme, kayıt silme vb. haklar bir kullanıcıya ya da kullanıcılara ayrı ayrı atanır. İkinci şekilde ise verilmek istenen haklar bir rol altında birleştirilir ve bu rol istenen kullanıcılara aktarılır.

            Haklar “sistem hakları” ve “nesne hakları” olmak üzere ikiye ayrılır. Sistem hakları veritabanı ile ilgili olarak önceden tanımlanmış rollerdir. Oracle’da 60’tan fazla sistem hakkı tanımlanmıştır. Nesne hakları ise veri tabanı nesneleri üzerinde işlem yapma haklarıdır. “Create Table”, “Create TableSpace”, “Drop Any Index” gibi haklar sistem haklarına örnek olarak verilebilir.  Nesne hakları ise 8 çeşittir. “Select”, “Insert”, “Update”, “Delete”, “Alter”, “Index”, “Execute”, “References”, “All” çeşittir. “All” ayrı bir hak olarak adlandırılmaz. Diğer tüm hakları kapsar. Bu haklar sırayla kayıt seçme, kayıt güncelleme, kayıt silme, nesnelerin yapısını değiştirme, indeks oluşturma, alt program çalıştırma, yabancı anahtar tanımlayabilme işlemlerini içerirler. Rol tanımlama ve hak verme komutları ileride ayrıntılı olarak işlenecektir.

 

Geri Alma Parçası(ROLLBACK SEGMENT)

 

 

 

            Oracle veritabanının güvenliği açısından “Select”, “Insert”, “Update”, “Delete” gibi işlemlerin yedeğini almaktadır. Alınan bu yedeklerin konulduğu yerlere geri alma parçası denir. Kullanıcı bu tip işlemleri yaptıktan sonra            “Rollback” komutunu uygularsa, yaptığı değişiklikler geri alma parçalarından getirilir ve böylece kayıtlar eski haline dönmüş olur. Kullanıcı “Commit” komutunu verirse yaptığı değişiklikler geri alma parçalarından geri getirilemez. Her veritabanında bir ya da birkaç tane geri alma parçası olabilir.

 

Sıra(SEQUENCE)

 

 

 

            Tablolardaki kayıtlar için otomatik sıra numarası verilmesi isteniyorsa sıra nesnesi kullanılabilir. Bu sıra numarası veritabanı tarafından otomatik olarak üretilir.  Özellikle çok kullanıcılı ortamlarda tekil olarak numara üretilmek istendiğinde çok kullanışlıdır.  Birden fazla kullanıcı aynı anda böyle bir sayı üretmek isterse bunun program koduyla yapılması işlem hızını yavaşlatır. Çünkü bir kullanıcı diğeri işini bitirene kadar beklemek zorundadır. Sıra nesnesi bu işi otomatik olarak ve çok seri bir şekilde başarır.

            Sıra numaraları Oracle’da tanımlı 38 rakama kadar tamsayılardan oluşur. Bir sıra tanımlaması sıranın adını, artan ya da azalan olacağını, iki sayı arasındaki fark miktarını içerir. Oracle tüm sıra numarası tanımlarını SYSTEM tablo uzayının içerisindeki bir veri sözlüğü tablosuna kaydeder. SYSTEM tablo uzayı sürekli çalışır durumda olduğu için tüm sıra numaraları da aktiftir. Sıra numaraları tablolardan bağımsız olarak üretilir. Yani bir sıra numarası bir ya da daha çok tablo için kullanılabilir.

 

 

Kayıtlı Fonksiyonlar(STORED FUNCTION) ve Kayıtlı Prosedürler(STORED PROCEDURE)

 

 

 

            Bir grup SQL ya da PL/SQL komutunun belli bir işi gerçekleştirmek için bir araya getirilip veritabanına kaydedilmesi kayıtlı prosedürler ve fonksiyonlar sayesinde olur. Birden fazla uygulama programı içerisinde aynı işi yapan kodları sürekli yazmak yerine kayıtlı prosedür ve fonksiyonlar bir kere yazılır ve tüm uygulamalar tarafından kullanılır. SQL*Plus, Oracle Forms ya da Oracle Reports içerisinden bu prosedürler çağrılabilir. Prosedürler geriye birden fazla değer döndürebilirken, fonksiyonlar  sadece bir değer döndürürler.

 

Eşanlam(SYNONYM)

 

 

 

            Eşanlam bir tablo, görüntü, sıra, prosedür, fonksiyon ya da paket için “alias” olarak adlandırılan bir takma isimdir. Eşanlam bir takma isim olduğu için veri sözlüğü içerisindeki tanımının kapladığı yer haricinde, veritabanında yer kaplamaz. Eşanlamlar güvenlik ve daha rahat kod yazma amacıyla kullanılırlar. Bir eşanlam kullanıldığında ilgili nesnenin adı ve sahibi gizlenir ve SQL komutu içerisinde kullanımı kolaylaşır.

            Eşanlamlar genel(Public) ve özel(Private) olarak tanımlanabilirler. “Genel” olarak tanımlanan eşanlamlara tüm veritabanı kullanıcıları erişebilir. “Özel” olarak tanımlanan eşanlamlara sadece ilgili nesnenin sahibi ve sahibi tarafından hak verilmiş bir başka kullanıcı erişebilir.

            Bir nesnenin adı değiştirilmek istendiğinde ya da silinmek istendiğinde, bu nesneyi kullanan tüm uygulama programları değiştirilmek zorundadır. Oysa ki bu nesnenin bir eşanlamı oluşturulursa ve uygulama programları bu eşanlamı kullanırsa, eşanlam üzerinde yapılacak değişikliklerle bu silme vb. işlemlerden uygulama programlarının etkilenmesi önlenebilir.

            Bir kullanıcı bir başka kullanıcının nesnesini kullanmak istediğinde “kullanıcı_adı.nesne_adı” şeklinde bir yazım kuralına uymak zorundadır. Eğer bir “genel” olarak bir eşanlam tanımı yapılırsa tüm kullanıcılar direk eşanlam ismini kullanarak işlemlerini gerçekleştirebilirler.

 

Tablo(TABLE)

 

 

 

            İlişkisel Veri Tabanı Yönetim Sistemleri’nde veriler tablolar içerisinde yer alır. Her tablo bir isimle tanımlanır ve her biri  bir “kayıt” olarak adlandırılan satırlar ile bu kayıtlardaki verilerin özelliklerini belirleyen sütunlardan oluşur. Her tablo bir ya da daha fazla sütuna sahip olabilir. Her sütunun bir adı ve veri tipi vardır.

            Bir tablo oluşturulduğunda Oracle verileri depolamak için bir tablo uzayı içerisinde bir veri segmenti ayırır. Veri segmentinin değerleri değiştirilerek bir tablo için ayrılacak yer miktarı da değiştirilebilir.

 

Görüntü(VIEW)

 

 

 

            Görüntü bir ya da birkaç tablodan istenilen alanların alınmasıyla oluşturulan sanal bir tablodur. Görüntü bu tablolar üzerinde gerçekleştirilen bir sorgu sonucu oluşturulur. Bir görüntü üzerinde silme, güncelleme gibi işlemler yapılamaz. Çünkü görüntü oluşturulduğu tabloların sadece o anlık görüntüsüdür ve veritabanında kendi tanımının kapladığı yer haricinde yer kaplamaz.

 

 

 

 

 

 

 

 

 

 

 

 

Oracle8  : Veri Tabanı Yönetim Sistemi, günümüzün dinamik çalışma grubu çevrelerinden yüksek hacimli  ‘ online transaction’ ve sorgulama bazlı veri ambarı sistemlerine kadar uzanan geniş bir yelpazede en uygun, en iyi performansa ulaşmak için esnek, açık, ölçeklenebilir, bağımsız, güvenli bir ortam yaratan, Web-enabled uygulama yaratımını destekleyen ve kolay kullanılabilir yönetim araçları içeren güçlü bir veri tabanı yönetim sistemine sahiptir. Oracle VTYS, 130’dan fazla donanım üzerinde (UNISYS, IBM, DEC, HP, SUN, MAC, Sequent, PC, Mainframe…..) ve tüm işletim sistemlerinde çalışmakta, değişik  performans ihtiyaçları için tek işlemcili donanımlar’dan, Simetrik Çoklu İşlemcili sistemler üzerinde çalışabilmektedir

 

 

 

 

Oracle’ın Kominikasyon Aracı, SQL*Net ürünü, client/server ve server/server Oracle veri iletişimini gerçekleştir.  SQL*Net, yagın Kullanılan Tüm İletişim Protokollerini  Destekler : TCP/IP, OS, APPLETALK, XODIAC,ve diğerleri

 

Oracle8 VTYS’nin mimarisi yüksek performans sağlayacak bütün teknolojileri kullanmaktadır:


Contention-Free Queries: Oracle8 VTYS’de sorgulamalar güncelleştirmeleri ve güncelleştirmeler sorgulamaları bloke etmediği için işlemler birbirlerini beklemek zorunda kalmazlar.

Paylaşımlı Derlenmiş SQL: Oracle VTYS, OLTP ortamlarda olduğu gibi çok sayıda kullanıcının aynı grup SQL cümlelerini kullandığı durumlarda bu kullanıcıların SQL cümlelerinin derlenmiş ve ortak bellekte tutulan tek bir kopyasını paylaşmalarına olanak verir. Bu shared compiled SQL yapısı sayesinde hem bellek kullanımı azalır hemde performans artar.
On-line Backup/On-line Recovery: Oracle VTYS, OLTP aktivitenin en yüksek olduğu zamanlarda bile kullanıcıları etkilemeyecek şekilde on-line backup (yedekleme) ve on-line recovery (kurtarma) işlemlerini gerçekleştirebilmektedir.

Otomatik Sıra Numarası Üretimi: Oracle VTYS, veri tabanında sıra numaraları üretilirken herhangi bir tablonun kilitlenmesine gerek olmadığından bu açıdan bir performans darboğazına girmemektedir.

 

 

Oracle, veri tabanı kaynaklarına, tablolarına ve verilerine yetkisiz ve kaçak erişimi engellemek ve denetleyebilmek ayrıca DDL komutlarının (create, select, delete vb) kullanım haklarının denetlenmesi için rol bazında güvenlik yöntemini kullanmaktadır. Bu yöntem her kullanıcının her tablo için erişim hakkının sisteme girilmesini gerekli kılan klasik yaklaşıma göre çok daha düşük maliyet getirmektedir. Oracle8 VTYS, güvenlik ve gizlilik nedeniyle erişim ve güncelleştirme için değişik şifrelerle korunma sağlamaktadır. Veri tabanı objelerine erişim yetkileri roller bazında tanımlanabilir (role-based security). Oracle8 VTYS, ANSI/ISO SQL3 güvenlik standardını desteklemektedir.

 

 

 

 


Rol, bir iş grubunu temsil eder. Veri tabanı kullanıcılarına daha önce tanımlanmış roller verilir. Böylece kullanıcının bulunduğu iş grupları kendisine verilen rollere bağlı olarak tanımlanmış olur. Bir role verilebilecek veri tabanı objelerine değişik erişim yetkileri verilebilir.

 

Oracle VTYS veri tabanı bütünlüğüne (Integrity) sahiptir. Bir alan üzerinde verilebilecek kısıtlama sayısında herhangi bir limit yoktur. Oracle VTYS veri tabanı bütünlüğüne ilişkin bilgiler aşağıda verilmiştir

 

Oracle Veri Bütünlüğü Uygulatımı

Oracle VTYS, veri bütünlüğü kurallarının herbirini tanımlamaya ve uygulamaya olanak sağlar. Bu kuralların büyük bir kısmı, bütünlük kısıtlamaları kullanılarak tanımlanır. Bütünlük kısıtlamaları aşağıda sunulmuştur;

 

Bütünlük Kısıtlamaları (Integrity Constraints)

Bir bütünlük kısıtlaması, bir tablonun bir kolonu için bir kural tanımlamanın bildirimsel (declarative) bir yöntemidir. Bir bütünlük kısıtlaması, Oracle VTYS tarafından veri tabanının temel tablolarına geçersiz veri girişini engellemekte kullanılan bir mekanizmadır. Bütünlük kısıtlamaları, bir veri tabanındaki bilgiler ile ilgili iş kurallarını uygulatmak amacıyla tanımlanabilir. Eğer bir ifade, yürütümünün sonuçlarından herhangi biri bir bütünlük kısıtlamasını ihlal ederse, ifadeye ilişkin değişiklikler ortadan kaldırılır (rollback) ve bir hata kodu döndürülür.

Veri tabanı idarecisinin ya da uygulama geliştiricisinin kolon değerlerinin girdisi üzerinde sınırlamalar koymak için kullanabileceği çeşitli veri bütünlüğü kısıtlamaları vardır.

Oracle VTYS tarafından desteklenen bütünlük kısıtlamaları şunları içerir:

NOT NULL Default olarak, bir tablodaki kolonların tümü “null” değere olanak verir. Yani o kolonlara veri girilmesi zorunlu değildir. Bir NOT NULL kısıtlaması, bir tablonun bir kolonundaki null değere izin verilmemesi anlamına gelir. Örneğin, A tablosundaki her kayıt için, B kolonuna, mutlaka bir değerin girilmesini gerektiren bir NOT NULL kısıtlaması tanımlanabilir.

UNIQUE Anahtar Bir UNIQUE anahtar kısıtlaması, bir tablo içinde belirlenen bir kolon ya da kolon seti içinde yinelenen değerlerin olmamasını sağlar. UNIQUE anahtar kısıtlamasının tanımına dahil edilen kolon ya da kolon seti UNIQUE anahtar olarak adlandırılır. Eğer söz konusu UNIQUE anahtar kısıtlaması birden fazla kolondan oluşuyorsa, kısıtlama karma unique anahtar (composite unique key) olarak adlandırılır.

BİRİNCİL (PRIMARY) Anahtar Bir veri tabanı içindeki her tablo, tek bir BİRİNCİL ANAHTAR kısıtlamasına sahip olabilir. Bir tablonun kayıtları, BİRİNCİL ANAHTAR bütünlük kısıtlaması ile yönetilen değerleri kullanarak tanımlanabilir ya da referans edilebilir. BİRİNCİL ANAHTAR’ın bütünlük kısıtlaması, Oracle VTYS uygulamalarına şunları garanti eder:

Bir kolonun hiçbir iki kaydı belirlenen kolon ya da kolon seti içinde yinelenen değer içermeyecektir. Birincil anahtar kolonu/kolonları null değerlere izin vermeyecektir (yani, her kayıtta birincil anahtar kolonları için bir değer olmalıdır).

YABANCI (FOREIGN) Anahtar Oracle, aşağıdakiler dahil olmak üzere referans bütünlüğü işlemleri tanımlama amacına yönelik YABANCI ANAHTAR bütünlük kısıtlaması kullanımını desteklemektedir:

 

Referans Bütünlüğü Kısıtlamaları Tarafından Tanımlanan İşlemler

Referans bütünlüğü kısıtlamaları, referans verilen ana anahtar değerinin değiştirilmesi durumunda, bir alt tablo içindeki bağımlı kayıtlar üzerinde gerçekleştirilen özel işlemleri de belirler. Oracle VTYS’in YABANCI ANAHTAR bütünlük kısıtlamaları ile desteklenen referans işlemleri şunları içerir: GÜNCELLEŞTİR (UPDATE), SİLMEYİ KISITLA (DELETE RESTRICT) ve BASAMAKLI SİL (DELETE CASCADE)  

Basamaklı Silme (Cascading Deletes) Basamaklı silme işlemi, referans edilen ana anahtar değerlerini içeren kayıtlar silindiğinde, bağımlı yabancı anahtar değerlerine sahip alt tablolardaki tüm değerlerin de silineceğini belirtir. Örneğin, eğer ana tablodaki bir kayıt silinirse, bu kaydın ana anahtar değeri alt tablo içindeki bir ya da birden çok yabancı anahtar değeri tarafından referans alınmışsa, alt tablo içinde ana anahtar değerini referans alan kayıtlar da alt tablodan silinir.

 

 

Oracle8 VTYS, bir tablonun veri dağılımı ve saklama indekslere ve istatistiklere dayanarak SQL ifadeleri için otomatik olarak bir yürütme planı seçmektedir. Bu özellik, otomatik maliyet-esaslı eniyileyici (Cost-based optimizer) olarak adlandırılmaktadır. Kullanılan istatistikler arasında tablo ebatı, kolonların seçiciliği, verilerin indekslenen değerlerin etrafında fiziksel olarak kümelenme derecesi, vb. yer almaktadır. En etkin erişim yolunu seçerek, sorgulamanın performansını, sorgulama cümlesinin yazılım şeklinden (sözdiziminden) bağımsız hale getirmektedir. Tabloları birleştirme (join) ya da tablo erişim yolu gibi noktalarda eniyileyicinin kararlarını yönlendirmek için, SQL ifadeleri içinde bulunan ve kullanıcı tarafından verilen ipuçları kullanılmaktadır. Oracle8 VTYS’nin cost-based optimizer’ı istatistik oluştururken verinin uniform olduğunu farz etmemektedir.

 

 

 

 

Oracle veri tabanı ailesi ilişkisel mimarinin yanı sıra, nesne yönetimli teknolojiyi de  tamamen destekleyen bir mimariye sahiptir. Endüstri eğilimi ve beklentileri sonucunda Oracle hem ilişkisel hem nesnesel mimariyi; paralellik, devamlılık güvenlik, ölçeklenebilirlik, kolay yönetilebilirlik, yüksek performans ve yeni veri tipleri ile birleştirerek bilgi çağında yarattığı devrimin yanı sıra evrensel bir yaklaşım sunmaktadır

 

Oracle8 ORDBMS, standart veri tipleri dışında kullanıcı tarafından tanımlanmış veri tipleri kullanımına imkan vermektedir. Kullanıcı tarafından tanımlanan veri tipleri ile gerçek nesnelerin modellenmesi mümkün olmaktadır. Bu amaçla Oracle, SQL3 standartları çerçevesinde SQL diline ekler getirmektedir

 

 

Kompleks veri nesnelerinin modellenmesi amacıyla, Oracle8 yeni veri tipleri ile veritabanını genişletmek (user-defined veri tipleri) imkanı sunmaktadır. Bu yapı altında; Harici prosedürlerde Object veritipleri tanımlanması, Index-only tablolar, Nested tablolar, Array veri tipleri tanımlanabilmektedir.  

 

 

 

 

Oracle8, mevcut ilişkisel veriler üzerinde Object View’ler yaratarak, ilişkisel ve object (nesne) verilerin bir arada kullanılmasına olanak verir

 

Hükümet ve ticari güvenlik ihtiyaçlarını karşılamak amacıyla çok seviyeli güvenlik yaklaşımını destekleyen Oracle veri tabanı ailesinin kişisel bilgisayar ihtiyaçlarına da karşılık veren aynı kernel’e sahip versiyonu mevcuttur.

Ne

twork Computing Architecture (NCA)’ın anahtar bileşeni olan Oracle8 Enterprise Edition, network-merkezli bilgisayım ve nesne geliştirim yöntemlerinin peformansını, güvenilirliğini ve  ölçeklenebilirliğini karşılamak üzere tasarlanmıştır. İster geleneksel şirket uygulamaları ister Web üzerinde elektronik ticaret olsun Oracle8 Enterprise Edition ve NCA; en çok gereksinim duyulan uygulamalara destek vermek üzere performans, güç, network bütünleşmesi ve esneklik sağlar.


Veri depolama uygulamaları, yüklü miktarda veri ile çalışan karmaşık, anlık  sorgulamalara bağlı olarak OLTP uygulamalarından daha farklı işleme tekniklerine gereksinim duyarlar. Bu özel gereksinimleri karşılamak üzere Oracle8 çok çeşitli sorgu işleme teknikleri, veri erişim yolunu seçmek üzere incelikli sorgu optimizasyonu ve paralel donanım konfigürasyonundan tam anlamıyla yararlanan ölçeklenebilir bir mimari sunmaktadır.

 

 

Oracle8 ile geliştiriciler ve son kullanıcılar fiziksel olarak dağıtımlı veritabanını tek bir mantıksal veritabanı olarak ele alırlar ve dağıtımlı ağ ortamındaki her türlü veriye tek bir lokal makina üzerindeymişçesine erişim sağlarlar ve verinin güncellemesini aynı kolaylıkla yerine getirirler. Üretim uygulamaları da çoklu sistemler üzerine dağıtılabilir.

 

 

 

 

Personal Oracle8, Oracle8 veritabanının masaüstü sürümü olup yeni sezgisel kullanıcı arabiriminin yanı sıra ileri veri kopyalama özellikleri sunmaktadır.

Personal Oracle8 üzerinde geliştirilen uygulamalar yeni yapılandırmaya gerek kalmadan diğer Oracle8 platformlarında da çalışmaktadır. Personal Oracle8 istemci/sunucu uygulamalarında ideal geliştirim platformudur. P O 8  sayesinde ;

 

Veritabanı nesnelerini yönetebilirisiniz. Tablo verisi izleyebilir ve düzenleyebilirsiniz. Uzaktaki çoklu bağlantıları yönetebilirsiniz. Otomatik veri uyumu konfigürasyonu yapabilirsiniz. 

 

 

Personal Oracle Lite bir megabyte bellekten daha azına sığabilen tek kullanıcılı nesne-ilişkisel veritabanıdır.. Personal Oracle Lite az yer kaplayan aygıtlarda tek kullanıcılı, küçük çaplı uygulamalar geliştirmek isteyenler için ideal bir yazılımdır.

 

 

 

 

Personal Oracle Lite çalışma grupları ve şirketler için kullanılan Oracle veritabanıyla veri kopyalanmasını desteklemektedir. İstemci veritabanı altında kullabılmak üzere geliştirilmiş mükemmel bir gömülü veritabanıdır (embedded database) 1MBtan az bellekten daha azına gereksinim duyan Oracle Personal Lite hem hafif hem de çok güçlüdür. Bu sayede uygulamalar çok az bellek kaynağı gerektirirken istemci veritabanı kullanmanın avantajlarına da sahip olurlar. Personal Oracle Lite SQL nin set-tabanlı ilişkisel özelliklerinin gücünü karmaşık veri temsili birleştirir ve C++ gibi nesne-yönelimli programlama dillerinden doğrudan dolaşma (navigation) erişimine izin verir. Personal Oracle Liteın sahip olduğu bu nesne teknolojisi yeni kuşak Oracle nesne yönelimli araçların, bağlanırlığın ve sunucu ürünlerinin tamamlayacaktır.

 

 Oracle ConText option, Oracle8 ilişkisel veritabanınızın bütün  gücünü kullanarak, metin bilgi kaynaklarını yapısal  verilerde olduğu kadar kolay ve hızlı kullanımına olanak veren metin yönetimidir. Haber arşivlerinden önemli Web içeriklerine kadar her tür bilgi kaynağına ulaşım ve yönetim için idealdir

 

 

The Oracle Video Option, kullanıcıların firma ağı üzerinden istemcilere gerçek zamanlı, tam ekran video ve yüksek kaliteli seslerin saklanması, yönetimi ve kullanımına çözüm sağlayan yazılımdır. Oracle8 Server’a opsiyon olarak Oracle Video Option geleneksel veri modelini yüksek kalitede ses ve video kullanarak geliştirir.

 

 

 

 

 

 

Oracle Advanced Networked Option, firma dizin hizmetleri, tek oturumla açılan hizmetler, network şifreleme, jeton ve kullanıcının biyometrik doğrulanması sayesinde tek kaynaklı bütünleşme ve Oracle8nin OSF Distributed Environmet (DCE) ile birleşimine olanak verir

Oracle değişik bireysel teknolojiler kullanılarak bu tür hizmetler sağlamanın bir çok yolu olduğunun bilincindedir. Advanced Networking Option her bir hizmetin yürütülmesinde bir çok yol sunan “tabii teknoloji”dir.  Bunun sonucunda,  ağ ortamlarına ve güvenlik yazılımlarına yaptığınız yatırımları korurken, yeni teknolojileri de çıktıkça sisteminize katabilirsiniz.

ORACLE UYGULAMA GELİŞTİRME ARAÇLARI

Oracle’ın ölçeklenir uygulama geliştirim çözümü içerisinde iki ürün grubu yer almaktadır: Oracle Designer/2000 ve Oracle Developer/2000™. designer/2000™ iş süreci yeniden yapılandırması (BPR), analiz ve tasarım diyagramcıları ile karmaşık sistemlerin modellenmesine destek verir.
Developer/2000 organizasyonların iş gruplarından şirketlere, çeşitli ölçeklerde, hızlı ve üretken bir biçimde incelikli sistemler üretmelerini sağlar. Ortak bir depo, esnek modelleme ve yöntembilim desteği ve portatif açık mimari sayesinde Designer/2000 ve Developer/2000 endüstrinin tek ikinci kuşak istemci/sunucu ve geliştirim araçlarıdır.    

 

Üretkenlik

Developer/2000in güçlü bildiri yeteneği kullanılarak veritabanı tanımlamalarından, tek bir kod satırı yazmadan, uygulama yaratımı gerçekleştirilebilir.

İstemci/Sunucu Ölçeklenirliği

Ölçkelenirlik Developer/2000 geliştiricileri için oldukça basit bir işlemdir, çünkü ürünün mimarisi içerisinde bu özellik içsel olarak  mevcuttur. Dizi getirme, veritabanı imleçleri, bağ değişkenleri, kayıt noktaları ve sıralar olarak  sunucu işlevselliği  paralel olamayan desteğinde belirtilmiştir

Taşınabilir Olma

Taşınabilir olma ve küresel yaygınlaştırım  Oracle ürünlerinin ticari markalarıdır.

Birleşik İstemci/Sunucu Düzenleme ve Hata Ayıklama

Developer/2000 uygulamalarınızın özgün hale getirilmesi sunucu nesnelerinizin değiştirilmesi kadar kolaylaşmıştır.

Tam Bir GUI Desteği

Developer/2000, Windows, Macintosh ve Motif üzerinde doğal bir biçimde taşınanbilir uygulamalar ve character mode sağlar.

Model Yöneltimli Geliştirim

Geliştiriciler depo tanımlamalarından tam bir Developer/2000 uygulamasını gerçekleştririken Designer/2000 kullanmayı seçebilirler. Herhangi bir başka ürünle bu kadar karmaşık, belgelenmiş, standart hale getirilmiş, serbest kullanımlı uygulamalar yaratmanıza olanak yoktur.

Kolay Bütünleşme

Uygulamalarınızın becerilerini genişleten açık mimari sayesinde Developer/2000 esneklik garantisi vermektedir.

Takım Geliştirimi

Developer/2000 uygulamalarınız, uygulama mantığı ve kullanıcı arabirim nesnelerini paylaşabilmekte, bu sayede size takım geliştirim standartlarını tanımlama ve güçlendirme ve uygulama nesnelerini ya da kodunu bir anda yeniden kullanma olanağı vermektedir.

Türdeş Olmayan Veri Erişimi

Developer/2000 yalnızca güçlü  Oracle8 veritabanı becerilerini kullanmak üzere değil aynı zamanda formatı ve konumu ne olursa olsun organizasyonunuz içerisindeki tüm veriye erişim sağlamak üzere tasarlanmıştır.  DB/2, SQL Server, DB2/400, Access ve RDB dahil olmak üzere seçiminizin gerektirdiği veri kaynakları ile iletişim kurmak üzere Open Client Adapter™, Oracle Open Gateway™ teknoloji ya da uygulama programlama arabirimler (API’ler) kullanır.  

Bunun yanısıra;
İlişkendirilmiş veritabalarındaki verileri yönetilen bilgilere dönüştürmeyi mümkün kılıyor. Oracle Express in güçlü olanaklarıyla doğan Discoverer, kullanıcıların tek kaynaktan tüm olası iş araçlarına ulaşmasını sağlıyor. Discoverer ın predictive query governer (tahmini sorgulama yönetimi) özelliği, bir sorgulamanın sonuçlanmasının ne kadar süreceğini bildiriyor ve sorgulamanın tamamlanması kararını kullanıcıya bırakıyor. Bu özellik, sistemi yavaşlatan çok uzun süreli taramalardan tasarruf sağlıyor.

Web yayınlama özelliği sayesinde  kullanıcılar Oracle discoverer dan son raporları Web üzerinde yayınlama olanağı buluyor. Bu sayede organizasyon içinde çok fazla kişinin standart Web tarayıcısı kullanarak sonuçlara ulaşmasını sağlıyor.

 

 

 

 

 

 

OpenGL

Bölüm 1: Sistem Altyapısı

A- SIMD mimarisi hakkında ön bilgi

Bu yazı grafik programlama ile ilgili olmasına rağmen, ilk önce elimizdeki sistemi tanıyarak ve bazı kurallar koyarak başlayacağız.

Bilgisayarlar 1983’den bu yana oldukça fazla gelişmelerine rağmen aynı taban üzerinde ayakta kalmaktalar. Süreklilik gerektiren işlerde oldukça yetenekliler, fakat düzensiz işlemlerde, örneğin değişken bir üç boyutlu sahneyi işlemekte, oldukça yavaşlar. Oyunlarda sıkça yapılan şeylerden birisi bu şekildeki verinin işlenmesi oldugu için, bu seride ilk yapacağımız şey, bilgisayarların ne olduğunu (ve olmadığını) öğrenmek ve bu kısıtlamanın üstesinden nasıl gelineceğini öğrenmek olacak.

Bir günümüz bilgisayarı:

1- Doğrusal ve uzun bloklar halindeki işlemleri daha hızlı yapabilir.

2- Ne kadar az hafıza erişimi yaparsa o kadar hızlı çalışır.

3- Elimizdeki “düzensiz” veri miktarı arttıkça adresleme hataları da o denli artar.

Tüm bunlar, Intel’in ve diğer firmaların şu anda kullandığı SIMD (Single Instruction Multiple Data = Tek komutta birden çok veri) tarzı işletim ile neredeyse tamamen örtüşen bir durum oluşturuyor. İlk kısıtlamamiz, bize uzun blokların tek seferde daha hızlı işlendiğini söylüyor, bu da tam olarak SIMD’nin yaptığı şey, uzun blokları tek seferde işlemek. Diğer iki kısıtlama bize adres çözme işleminin problemlerini, yani “cache miss” ve “misalign” sorunlarını anlatıyor. “Cache miss” ile kastedilen, bir adres çözme işlemi sonucu erişilecek verinin kaşe bellekte bulunmadığının anlaşılıp yeniden bir adres çözme işlemine yol açması. “Misalign” ise çözülen adresin 8 (ya da şimdilerde 16 byte)’ın katlarına denk gelmemesi, örneğin hafızanın 3. byte’ında bulunması sonucu gereksiz miktarda verinin birden çok kez okunmasına yol açmasına verilen isim.

Şimdi bu ufak tablodaki kısıtlamalardan kurtulmak için bu seri boyunca uyacağımız kurallara bir göz atalım:

1- SIMD ve/veya SIMD2 işlemlerine ağırlık vermek ya da bunlara dönüşebilir şekilde kod yazmak.

2- Veriyi daima “hizalanmış” hafıza adreslerinden başlatmak.

3- Veriyi daima 16 byte’ın katları olarak tutmaya çalışmak, mümkünse {X,Y,Z} gibi sırasız veri akışını {X[],Y[],Z[]} haline getirmek.

Üçüncü madde biraz karışık gelebilir. Tipik bir programda sakladığımız veri eğer

class nokta

{

      float x, y, z;

};

nokta benimNoktalarım[1024];

ise, bu SIMD için daha uygun olan:

class yogunNokta

{

      float x[1024], y[1024], z[1024];

};

yogunNokta benimNoktalarim;  

şeklinde yeniden düzenlenmelidir. Tabii bu şekilde statik veri ayrılması pek önerilen birşey olmadığı için bunu sadece konuyu açıklamak için verdiğimiz bir örnek olarak yorumlamanız gerekiyor, pratikte:

class yogunNokta

{

      float *x,* y, *z;

};

yogunNokta benimNoktalarim;

x=(float*) aligned_malloc( 1024 * sizeof(float), 16);

y=(float*) aligned_malloc( 1024 * sizeof(float), 16);

z=(float*) aligned_malloc( 1024 * sizeof(float), 16);

daha doğru bir yaklaşım. Buradaki aligned_malloc komutu 16 byte’ın katı olan bir adresten başlayacak şekilde bellek ayırmamızı sağlıyor.

B- Optimizasyon

Kullandığımız sistem, herşeyden önce, saf C/C++ kodunun daima en basit hedef işlemciye göre (zorlanmadıkça) derlendiği bir sistemdir. Yani yazdığımız aşağıdakine benzer bir satır, eğer biz derleyiciyi buna zorlamazsak, 80386’da hızlı çalışacak şekilde derlenir:

float fArray[16] = {1.0f, 4.6f, 12.0f, 43.0f, 61.0f, 52.0f, 2.0f, 1.0f, 3.0f, 4.0f, 6.0f, 13.0f, 421.0f, 54.0f, 654.0f, 1.0f};

for(unsigned long i=0; i<16; i++)

{

      fArray[i] *= 2.49f;

}

 

Bunun assembly karşılığı, standart derleyici çıktısı olarak:

xor   eax, eax

$loop1:

fld   DWORD PTR _fArray$[esp+eax*4+64]

fmul  DWORD PTR __real@401f5c29

inc   eax

cmp   eax, 16

fstp  DWORD PTR _fArray$[esp+eax*4+60]

jb    SHORT $loop1

olacaktır. Birinci kuralı ihlal ettik. Burada işlemcinin FPU kısmı kullanılarak aynı anda sadece bir sayı ile çarpma yapılmaktadır. Bunun yerine eğer bir P3/P4 derleyicisi ve el ile optimizasyon yöntemleri kullanırsak yukarıdaki kod şu şekli alır:

float fArray[16] = {1.0f, 4.6f, 12.0f, 43.0f, 61.0f, 52.0f, 2.0f, 1.0f, 3.0f, 4.0f, 6.0f, 13.0f, 421.0f, 54.0f, 654.0f, 1.0f};

float fPack[4] = {2.49f, 2.49f, 2.49f, 2.49f}; // 4 adet çarpan

float *p1,*p2;

p1 = &(fArray[0]);

p2 = &(fPack[0]);

_asm{

      mov ecx,4

      mov eax, p2

      movups xmm1, [eax]

      mov eax, p1

mLoop1:

      movups xmm0, [eax]

      mulps xmm0, xmm1

      movups [eax], xmm0

      add eax, 0x10 // 16, 4 tane 4 byte(float)

      loop mLoop1

};

Görüldüğü gibi artık tek komutta aynı anda dört çarpma yaparak daha uzun fakat daha hızlı bir kod elde ettik. Buradan da şu yeni kural çıkıyor:

Uzun kod daha hızlı çalışabilir.

Tabii bu kullanılan işlemciye göre değişeceği için OpenGL ya da DirectX gibi kütüphanelerde aynı rutin birden fazla işlemciye göre yeniden yazılmış şekillerde bulunurlar.

Bölüm 2: OpenGL  

A- OpenGL mi DirectX mi?  

Yeni programlamaya başlayanlar için çok daha az zahmetli olacağına inandığım OpenGL ile seriye başlamak istiyorum. DirectX her ne kadar daha “metale yakın” bir tarza sahip olsa da, burada okuyucunun derleyici ile yüksek bir ihtimalle beraber kurmuş olacağı OpenGL kütüphanelerini kullanacağız. Bu arada çoğu kullanıcının bir çeşit nVidia ya da ATI görüntü kartına sahip olduğunu ve en son OpenGL destekli (beta olmayan) sürücüleri yüklemiş olduğunu da varsayıyoruz.

OpenGL, DirectX’in aksine sürekli genişletilen (ve genişletilebilen) bir altyapıya sahip. Örneğin eğer bir firma bir kartı bu gün piyasaya çıkartır ve “raytrace destekliyor” olduğunu söylerse, bunun için (SGI ile konuşup eklentiyi kayıt ettirmenin yanında) tek yapmaları gereken bir adet “eklenti” yazmak ve bunu sürücülerine dahil etmek olacaktır. DirectX bu şekilde genişletilemez, sadece “yazılım ile render” eklentilerini kabul eder ve bunlar da donanınm ile çalışmazlar, sadece yazılımsal eklerdir ve “yeterince hızlı” değillerdir.  

OpenGL desteğimiz tam olduğuna göre, ilk OpenGL testimiz ile işe başlayabiliriz…  

B- Önce biraz ön bilgi  

OpenGL, bir “state machine” dir, yani her an verilen bir konumdadır ve sonraki komutlar bu konumda olunduğu göz önüne alınarak çalışır. Örneğin “ışıklandırma açık” ya da “kapalı” gibi. OpenGL aynı zamanda “batch” komut işletebilir, yani ardışık komutları saklayıp “bitir” sözcüğü ile birtilkte işletmeye alabilir.

Bu yapısı yüzünden OpenGL ile çalışırken her an hangi durumda olduğumuzu kesinleştirmek için uzun işlemler öncesi yeniden durumlarımızı ayarlarız. Örneğin ekrana yazı yazarken ışıklandırma gereksiz olduğu için kapatırken, sahne çizimini yapan kod parçası ışıkları tekrar açmalıdır. Her durum değişikliği bir çok hesaplama ve/ya da donanıma erişim gerektirdiği için çok iyi bir dizayn yaparak bunları minimum seviyede tutmakta yarar vardır.

Örneğin, her üçgeni çizmeden önce bir doku seçmek son derece yavaş olacaktır, bunun yerine aynı dokuyu paylaşan üçgenleri bir araya toplayıp tek seferde çizmek en iyi metodlardan biridir. Bu yüzdendir ki bazı basit BSP uygulamaları modern kartlarda yavaştır, çünkü sırasız ve düzensiz durum değişikliklerine yol açarlar.

Sıkça kullanılan bir yöntem de bir çok dokuyu tek bir büyük dokunun içerisine toplamaktır, böylece sadece bir kez doku seçilir.

Fakat bu iki probleme yol açar:

1- Doku gereğinden fazla büyük olur ve ya video belleğe sığmaz ya da yavaş erişime yol açar.

2- Doku ufak tutulur, fakat bu sefer ortalama kalite yarıya ya da daha kötü bir orantıya iner.  

Bir başka çare de büyük ve kalitesiz bir dokunun üzerine birden fazla ufak ve detaylı doku konumlandırmaktır. Bu tip dokulara “detay dokusu” adını verebiliriz. En hızlı yöntemlerden biri olmakla birlikte kendine has problemleri (detay dokusunun tekrarladığının belli olması gibi) vardır.  

İşte bu tip problemler varken, dokuları ufak tutup bunları bir “lightmap” (ışık dokusu) arkasına saklamak en basit ve hızlı çaredir. Böylece normal doku tekrarlasa bile, yüzeyin her noktasında farkı bir ışık değeri alacağı için tekrarsızmış gibi görünecektir.  

C- Henüz FPS söz konusu değilken…  

İlk yapacağımız şey, Windows alt sisteminden arınmış bir şekilde çalışmak olacak. GLUT kullanarak (openGL Utility Library = OpenGL yardımcı fonksiyon kütphanesi) oluşturduğumuz ilk örnek programımız iki adet üçgen ile bir kare çiziyor ve bunu ışıklandırıp renklendiriyor, fakat henüz doku içermiyor. Programımızın kodunu burada verip sizi yazma zahmetinden kurtarıyoruz:

Örnek1.zip

Bu kodu Visual C++ 6 ile derleyebilir ve ilk iki üçgenimize bakabilirsiniz. Fakat bundan fazlası için okumaya devam etmeniz gerekiyor…

D- Adım adım inceleme

Kodun bir kısmı (GLUT fonksiyonları) gözlerimizden uzakta OpenGL’i bir pencerede başlatıyor ve işin basit kısmı ile bizi başbaşa bırakıyor. Aşağıdaki satırlara bir göz atalım:

void display(void)

{

      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

      glColor4f(.2,.4,.2,1.0);

      glNormal3f(0.0, 1.0, 0.0);

      glBegin(GL_TRIANGLES);

      glVertex3f(-20.0,-15,20.0);

      glVertex3f(20.0,-15,20.0);

      glVertex3f(-20.0,-15,-20.0);

      glVertex3f(20.0,-15,-20.0);

      glVertex3f(-20.0,-15,-20.0);

      glVertex3f(20.0,-15,20.0);

      glEnd();

      glutSwapBuffers();

}

Burada sırayla şu işlemleri uyguluyoruz:

1- glClear: ekran dışı belleği sil (renk ve derinlik kanallarının ikisini de)

2- glColor4f: bundan sonraki noktalar için renk seç (yaklaşık yeşil, %100 opak)

3- glNormal3f: bundan sonraki noktaların işaret ettiği yönü belirt (tam yukarıya)

4- glBegin: buradan sonra verilen her üç nokta bir üçgene denk gelecektir (GL_TRIANGLES)

5- her 6 nokta için: glVertex3f: noktanın uzaydaki konumu

6- glEnd: bitir (burada OpenGL iki adet üçgeni “gerçekten” çizer)

7- glutSwapBuffers: GLUT ekran dışı belleği ekrana taşır (böylece çizdiğimizi görebiliriz)

Buradaki kod, tamamen “inline” (kod içerisinde) bulunan veri ile iki adet yeşil üçgen çiziyor. Dışarıdan dosya okuma gibi işleri sonraki yazılara bırakacağız o yüzden şimdilik böyle olması gerekiyor.  

E- Her noktaya farklı renk  

Yukarıdaki örnekte sadece bir adet glColor komutu yer alıyor. OpenGL bir “durum saklayan makina” (yukarıyı okuyun) olduğu için bu “durum” tüm çizim işlemleri boyunca geçerliliğini koruyor. Eğer iki adet farklı renkte üçgen çizmek istersek kodu şu şekilde değiştirmemiz gerekiyor:

glBegin(GL_TRIANGLES);

      glColor4f(.2,.4,.2,1.0);

      glVertex3f(-20.0,-15,20.0);

      glVertex3f(20.0,-15,20.0);

      glVertex3f(-20.0,-15,-20.0);

      glColor4f(.2,.2,.4,1.0);

      glVertex3f(20.0,-15,-20.0);

      glVertex3f(-20.0,-15,-20.0);

      glVertex3f(20.0,-15,20.0);

glEnd();  

Böylece bir yeşil bir mavi üçgenimiz oldu. Aslında bir adım daha ileriye giderek her noktaya bir renk verebiliriz:

glBegin(GL_TRIANGLES);

      glColor4f(.2,.4,.2,1.0);

      glVertex3f(-20.0,-15,20.0);

      glColor4f(.4,.4,.2,1.0);

      glVertex3f(20.0,-15,20.0);

      glColor4f(.4,.4,.4,1.0);

      glVertex3f(-20.0,-15,-20.0);  

      glColor4f(.2,.2,.4,1.0);

      glVertex3f(20.0,-15,-20.0);

      glColor4f(.2,.4,.4,1.0);

      glVertex3f(-20.0,-15,-20.0);

      glColor4f(.4,.2,.4,1.0);

      glVertex3f(20.0,-15,20.0);

glEnd();

Değişikliğe dikkat edin, üçgenlerimiz yine bir durum değişkenine uyarak “Gouraud” ışıklandırıldılar, yani kenar noktaları arasında renk değerleri doğrusal olarak dolduruldu.

Bu durumu kontrol eden komut:

glShadeModel(GL_SMOOTH)

satırı. İsterseniz şimdi diğer bölüme geçip, daha önceden ihmal ettiğimiz “durum” ayarlarına bir göz atalım.

F- Sahnenin çizim için ayarlanması

Programımızın yukarıdaki kısmına gelmeden önce kısa bir rutin ile bir takım ayarlar yapmıştık. Bu ayarlar, OpenGL’in aktardığımız veriyi nasıl yorumlayacağını düzenlemek üzere bir ihtiyaç doğdukça yapılan türden, örneğin kameranın konumu değiştiği zaman tekrar bir kamera transformasyonu ayarlamamız gerekiyor. Aşağıdaki kod sırası ile anlatılan işlemleri yapmakta:

// derinlik testi açık

glEnable(GL_DEPTH_TEST);

// ışığı renklendir

glLightfv(GL_LIGHT0, GL_SPECULAR, isik_renk);

// ışığı konumlandır

glLightfv(GL_LIGHT0, GL_POSITION, isik_konum);

// ışığı aç

glEnable(GL_LIGHT0);

// OpenGL ışıklandırma açık

glEnable(GL_LIGHTING);

// yüzey saklama açık

glEnable(GL_CULL_FACE);

// arka yüzeyleri sakla

glCullFace(GL_BACK);

// ışık ve rengin çalışması için gerekli

glEnable(GL_COLOR_MATERIAL);  

// gouraud tipi ışıklandırma

glShadeModel(GL_SMOOTH);

// projeksiyon

glMatrixMode(GL_PROJECTION);

gluPerspective(

      60.0, // 60 derece bakış açısı

      1.0,  // pixel deformasyon orantısı (y/x)

      1.0,  // yakın düzlem

      10000.0); // uzak düzlem  

// kamera transformasyonu

glMatrixMode(GL_MODELVIEW);

gluLookAt(

      10.0, 20.0, 30.0, // göz noktası

      0.0, -20.0, 0.0,  // hedef

      0.0, 1.0, 0.);      // yukarı  

Burada en önemli durum değişkenimiz GL_LIGHTING. Eğer bu durumu “enable” ile açık duruma getirmezsek pek birşey görmemiz mümkün değil. Sahnede en az bir adet ışık kaynağı bulunması gerekiyor ki cisimlerin derinlik ve konumlarını algılamamız kolay olsun. Tabii ışıkları aktif hale getirmeden önce glLight() ile konum ve renk bilgisini vermemiz gerekiyor. Göreceğimiz üzere glLight‘ın ikinci parametresi pozisyon ya da renk bilgisini vermekte olduğumuzu belirtiyor.  

gluLookAt, kamerayı konumlandırmak için kullanabileceğimiz en kolay rutin ve çok basit 3 parametre alıyor:  

gluLookAt( kamera_pozisyonu, hedef_pozisyonu, yukarı_vektörü);  

Burada “yukarı_vektörü”, o anki projeksiyon düzleminin “yukarısı” için kabul ettiği yönü tarif etmek için kullanılıyor. Bunun ile oynayarak, örneğin bir oyunda karakterin adımları ile oluşan sağa-sola yaylanma hareketini (ve bu nedenle oluşan kamera sarsıntısını) vermek mümkün.  

Bütün bunları bir araya koyarsak, temel bir OpenGL programının yapısı şu şekilde olmakta:

1- Sahneyi (ışık ve kamera) hazırla

2- Her ekran tazeleme işlemi için, sahneyi sil ve baştan çiz

Bu şekilde özetlediğimiz kadarıyla, OpenGL dünyanın en kolay grafik arabirimlerinden biri gibi görünmekte. Aslında gücünü de bu basit yapısından alıyor, söz ile anlatabileceğimiz her grafik problemini OpenGL kullanarak ekrana dökmek mümkün.  

G- OpenGL komutlarının sözdizimi  

Şu ana kadarki komutların bazıları, eğer fark ettiyseniz, sonlarında 2f, 3f gibi ekler içermekte. Bunun amacı, o komuta verilecek olan parametrelerin türünün kullanıcı tarafindan belirtilebilmesini sağlamak. Örneğin bir glColor4f komutu, aşağıdaki şekilleri alabilir:

void glColor3b(GLbyte red, GLbyte green, GLbyte blue);

void glColor3d(GLdouble red, GLdouble green, GLdouble blue);

void glColor3f(GLfloat red, GLfloat green, GLfloat blue);

void glColor3i(GLint red, GLint green, GLint blue);

void glColor3s(GLshort red, GLshort green, GLshort blue);

void glColor3ub(GLubyte red, GLubyte green, GLubyte blue);

void glColor3ui(GLuint red, GLuint green, GLuint blue);

void glColor3us(GLushort red, GLushort green, GLushort blue);

void glColor4b(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha);

void glColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha);

void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);

void glColor4i(GLint red, GLint green, GLint blue, GLint alpha);

void glColor4s(GLshort red, GLshort green, GLshort blue, GLshort alpha);

void glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);

void glColor4ui(GLuint red, GLuint green, GLuint blue, GLuint alpha);

void glColor4us(GLushort red, GLushort green, GLushort blue, GLushort alpha);  

Kural gereği kullanılan ekleri atarak komutun adını glColor() olarak telaffuz ederiz. Anlaşılacağı üzere eklenen kısaltmalar bize parametrelerin 8, 16, 32 ya da 80(ya da 96) byte uzunluğunda olduğunu belirtiyor. Bu kullanılan renk aralığının hassasiyetini artırmaz, sadece kullanıcıya bir kolaylık sağlar. Dahili olarak tüm renkler ekran kartlarında tamsayı ya da “32 bit float” olarak işlenir.  

Bütün parametre alan komutlar bu şekilde isimlendirilirer ve benzer kurallara uyarlar. Diğer komutların yazılışı için Visual C++ içerisinde yer alan yardım dokümanına ve gl.h dosyasına göz atmanızı tavsiye ederiz.  

OpenGL, eklerle sürekli genişlemektedir. Bu yüzden yeni komutların yazılışı, parametreleri vb vb için <a href=”http://www.opengl.org/”>www.opengl.org</a> ya da SGI’daki dokümanlardan faydalanmamız gerekiyor.

H- Sonuç  

Buraya kadar temel bilgileri edindik. Elimizdeki örnek kodun çizim kısmını değiştirerek, örneğin diskten veri okuyarak bir çok cismi çizmek mümkün. Fakat bu şekilde çok hızlı görüntü elde etmek olanaksız olduğu için, bir sonraki yazımızda öncelikle sistem belleğinde bulunan üçgen listelerinin çizimine başlayacağız. Ardından, “strip” yapısını anlatıp bunun avantaj / dezavantajlarına değinecek ve ilk doku kaplı yüzeyimizi çizeceğiz.  

Tüm sorularınız için email adresim : engin@vividimage.co.uk