PHP interface – Arayüzler

Standard

Herkese merhaba,

Bugün size php interface den bahsetmek istiyorum. PHP5 ile birlikte hayatımıza giren bir yenilik olan interface i görsel olarak düşünmeyelim. Aslında Yapı yani modelleme arayüzü olarak düşünebiliriz.
Örnek vermek gerekirse; bir veritabanı altyapısı hazırlıyorsunuz ve mysql,pgsql, oracle gibi birden fazla adaptorünüz var. Bu adaptörlerdeki yapıların birbiri ile aynı olmasını istiyorsak burada interface devreye girecek. Veya Cache yapısı kuracaksınız; APC, memcache gibi cache yapıları kullanacaksınız ve yapılar aynı olacaksa interface kullanabilirsiniz. İnsan için interface tanımlayıp kadın erkek sınıflarını bu interfaceten türeterek cins ikisinde de cinsi iki sınıfada oldurmak istiyorsanı kullanabilirsiniz. Örnek çoğaltılabilir bankalar için sanal pos uygulamasında da kullanabilirsiniz vs.vs.

Özetle Bir projede birden fazla geliştiricinin olması gibi durumlarda standart yapının korunması amacı ile hazırlanır,bizim sınıfa bir standart getirmemizi sağlıyor. Yani o standartların dışına çıkamayacağımız bir sınıf yazmamızı sağlıyor. Ve  yapı dışında birşey yapılmak istenirse hata sistem hata verir.
Bu standartları koruma nasıl bir fayda sağlayacak derseniz, göz hatası olabilir, dalgınlık olabilir veya başkasının yazdığınız kodları değiştirmesini istemiyorsunuz, burada interface kullanmanız mantıklı olacaktır.
Büyük projelerde özellikle kullanılır.
Veya diyelim framework lerde DB sınıfı için hazırlanmış olan interface kullanılırki çekirdek kodlar bozulmadan kullanıcılar isterse kendi sınıflarını türetsinler, bu sayede sınıf sizi standartlarına uymaya zorlar.

Lafı daha fazla uzatmadan bir kaç örnek vermek istiyorum sizlere;

ilk örneğimde size mysql, mssql gibi farklı veritabanı yapıları ile bağlantı sağlayabileceğiniz bir örnek vereceğim..

interface DB 
{ 
    public function connect(); 
    public function error(); 
    public function errno(); 
    public static function escape_string($string); 
    public function query($query); 
    public function fetch_array($result); 
    public function fetch_row($result); 
    public function fetch_assoc($result); 
    public function fetch_object($result); 
    public function num_rows($result); 
    public function close(); 
}

Burada veritabanı için kullanılacak fonksiyonları tanımlıyoruz. Bu arayüzden türetilen tüm sınıflar bu fonksiyonları içermeli ve bu standartta olmalı aski halde hata verecektir sistem.

Burada statik olarak tanımladık escape_string() metodumuzu. Bu metod sınıf oluşturulmadan da çağrılmak istenebilir yani DB arayüzünü uygulayan herhangi bir yerde de kulanılabilmesi için..
Bence veritabanlarına veri yazarken dikkat edilmesi gereken en önemli noktalardan birisidir. Aksi halde savunmasız kalan sisteminize kötü niyetli insanlar SQL enjeksiyon yapabilir.

Şimdi mysql için bu arayüzü kullanan bir sınıf oluşturalım ve fonksiyon kodlarını yazalım;

Class MysqlDB implements DB 
    { 
        private  $link; 

        public function connect($server='', $username='', $password='', $new_link=true, $client_flags=0) 
        { 
            $this->link = mysql_connect($server, $username, $password, $new_link, $client_flags); 
        } 

        public function errno() 
        { 
            return mysql_errno($this->link); 
        } 

        public function error() 
        { 
            return mysql_error($this->link); 
        } 

        public static function escape_string($string) 
        { 
            return mysql_real_escape_string($string); 
        } 

        public function query($query) 
        { 
            return mysql_query($query, $this->link); 
        } 

        public function fetch_array($result, $array_type = MYSQL_BOTH) 
        { 
            return mysql_fetch_array($result, $array_type); 
        } 

        public function fetch_row($result) 
        { 
            return mysql_fetch_row($result); 
        } 

        public function fetch_assoc($result) 
        { 
            return mysql_fetch_assoc($result); 
        } 

        public function fetch_object($result) 
        { 
            return mysql_fetch_object($result); 
        } 

        public function num_rows($result) 
        { 
            return mysql_num_rows($result); 
        } 

        public function close() 
        { 
            return mysql_close($this->link); 
        }

DB arayüzünden implement ettik yani o standartları MysqlDB sınıfımıza yükledik. Geriye sadece sınıfımızı yaratmak var..

$db = new MysqlDB; 
$db->connect('host', 'onur', '12345'); 
$db->query('use users'); 
$result = $db->query("SELECT username FROM users"); 
while($row = $db->fetch_assoc($reuslt)) { 
    echo $row['username']; 
}

Burada $db->select_db gibi bir metod kullanmadık çünkü arayüz ile uyumlu değil. Anlamanız için böyle bir yol izledim, dilerseniz yaparken o şekilde tanımlayabilirsiniz..

Aynı mantıkla mssql ve oracle için sınıflarınıcı oluşturabilirsiniz ve sonrası;

$db = new MssqlDB;

İkinci örneğimizde apc ve memcache olmak üzere 2 alternatifi olan bir cache kütüphanesi yazmak istediğimizi düşünelim. Oluşturacağımız 2 sınıfında bir arayüzün özelliklerini almasını sağlayarak aynı metodları kullanmasını ama farklı işlemleri yapmasını sağlayabiliriz.

Interface Cache
{
	public function setCache($value);
	public function unsetCache($value);
	public function getCache();
}

Burada “Cache” isminde bir arayüz oluşturduk. Normalde sınıfları “Class Sinif_ismi” şeklinde oluşturuyorduk. Arayüzleri de “Interface ArayüzAdı” şeklinde oluşturuyoruz. Arayüzü oluşturduktan sonra setCache, unsetCache ve getCache isminde 3 tane public fonksiyon oluşturduk. Ancak dikkat ederseniz fonksiyonların kodlarını yazmadım. Fonksiyon parantezinden sonra noktalı virgül ile satırı sonlandırdık.
Artık bu arayüzün özelliklerini alarak oluşturulan tüm sınıflar bu kalıba uymak zorunda olacaktır.

Class apc implements Cache
{
	public function setCache($value)
	{
		// Önbelleğe Kaydedeceğiniz kodlar burada
	}

	public function unsetCache($value)
	{
		// Önbellekten Sileceğiniz kodlar
	}

	public function getCache()
	{
		// Önbellekten Veriyi Okuyacağınız kodlar
	}
}

Class memCache implements Cache
{
	public function setCache($value)
	{
		// Önbelleğe Kaydetme kodlarınız
	}

	public function unsetCache($value)
	{
		// Önbellekten Silme kodlarınız
	}

	public function getCache()
	{
		// Önbellekten Veriyi Okuma kodlarınız
	}
}

Gördüğünüz gibi cache arayüzünden türeyen apc ve memcache sınıflarını oluşturduk. Burada implements cache dediğimiz için bu sınıflar cache sınıfının standartlarına göre çalışacaktır ve aksi halde hata döndürecektir. Tabi araya ben comment ile önbellekten veriyi okuma kodlarınız vs. yazdım çünkü sadece mantığı anlamanız için yazıyorum.

Hata alınırsa nasıl bişey olur?

Ölümcül sinir hata sürüsü sizi korkutup kaçırmaması için olası karşılaşacağınız hataya bir iki örnek vermek isterim 🙂

Fatal error: Access level to xxx::yyy() must be public (as in class xxx) in /home/site_adresi/public_html/index.php on line zzz

Fatal error: Declaration of memCache::getCache() must be compatible with that of Cache::getCache() in ..

Interface içerisinde sadece public metod kullanabilirsiniz
Belki de arayüz kullanmanın en kötü yanı bu. Arayüz kullanırken, sadece public metotları kullanabiliyoruz. Bu public metotlar yerine private metod yazarsak alacağımız hata şöyle olur:

Fatal error: Access type for interface method xxx::yyy() must be omitted in /home/site_adresi/public_html/index.php on line zzz

Birden Fazla Ebeveyn

PHP5 aynı anda birden fazla interface yapısını miras alan yeni bir interface üretmeye imkan veriyor. Böylece üretilecek class aynı anda birden fazla ebeveyne sahip olabiliyor. Bu da size çok dallı yapılar oluşturmanıza imkan sunacaktır.

Manuel de bulunan bir örneği bu basit örneği paylaşmak isterim;

<?php
interface a
{
    public function foo();
}

interface b
{
    public function bar();
}

interface c extends a, b
{
    public function baz();
}

class d implements c
{
    public function foo()
    {
    }

    public function bar()
    {
    }

    public function baz()
    {
    }
}
?>

interface_exists – interface tanımlımı bakalım?..
Mantıken class_exists ile aynı mantıktadır. Uzatmadan örnek vermek istiyorum açıklayıcı olacaktır;

<?php
// Kullanmaya çalışmadan önce arayüz tanımlı mı diye bakalım
if (interface_exists('Arayuzum')) {
    class Sınıfım implements Arayuzum
    {
        // Yöntemler
    }
}
?>

Daha da uzatmaya gerek yok herhalde, umarım açıklayıcı olabilmişimdir. Herkese iyi yazılım dolu günler dilerim 🙂

5 thoughts on “PHP interface – Arayüzler

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir