Controller ve View Çekirdek Sınıflarını Oluşturmak

Controller çekirdek sınıfı, controllers dizininde oluşturduğumuz her controller sınıfını genişletmek (extend) için kullanacağımız sınıftır. Bu sayede view dosyalarını çağırıp, model sınıflarını kullanabileceğiz.

View Katmanının Çekirdek Sınıfı

/app/core/view.php:

class view
{
    /**
     * Görünüm dosyasını yorumlayan metod
     * @param string $view görünüm dosyası
     * @param array $params parametreler
     */
    public static function render($view, array $params = [])
    {
        /**
         * Eğer dosya varsa
         */
        if (file_exists($file = VDIR."/{$view}.php")) {
            /**
             * $params dizesindeki verileri extract fonksiyonu
             * ile değişken haline döndürüyoruz
             */
            extract($params);

            /**
             * Çıktı tamponlamasını başlatıyoruz
             */
            ob_start();

            /**
             * View dosyası içeriğini çağırıyoruz
             */
            require $file;

            /**
             * Çıktı tamponun içeriğini döndürüp siliyoruz
             */
            echo ob_get_clean();
        /**
         * Dosya yoksa programı sonlandır
         */
        } else {
            exit("Görünüm dosyası bulunamadı: $view");
        }
    }
}

Burada view sınıfı içerisine, statik bir render sınıfı oluşturuyoruz. Statik sınıflar, normal fonksiyonlar gibi ulaşılabilen sınıflardır. Burada bunu kullanmamızın özel bir sebebi yok.

Metod parametrelerinden aldığımız verilerle işlemlerimize devam edelim. View dosyasının varlığını kontrol ediyoruz ve varsa işlemlerimizi yapıyoruz. extract() fonksiyonu bir dizedeki değerleri alıp, değişkene çevirmemize yarıyor. Detaylarını, PHP’nin dökümantasyonunda bulabilirsiniz. ob_start() fonksiyonu ile çıktı tamponlamasını başlatıyoruz yani çıktıyı tampon belleğe alıyoruz. Akabinde view dosyamızı dahil edip ob_get_clean() fonksiyonu ile tamponladığımız çıktıyı temizleyerek yazdırıyoruz. Hepsi bu.

View katmanıyla olan işimiz yalnızca bu kadar. Şimdi gelelim Controller katmanının sınıfına. Bu katman, yaratacağımız bir Controller’a yardımcı olmak için işimize yarayacak. Yaratacağımız Controller’ı -sayfasını diyelim- genişleterek işlemlerimizi kolaylaştıracak. Haydi girişelim.

İlkin, render metodu ile view dosyası yorumlayacağız.

/app/core/controller.php:

class controller
{
	/**
	 * View dosyası çağırmamıza yarayan metod
	 * @param string $file dosyasını adını alır
	 * @param array $params parametreleri alır
	 * @return void view sınıfından render metodu döner
	 */
	public function render($file, array $params = [])
	{
		return view::render($file, $params);
	}
}

Yaptığımız şey çok basit, render metodu ile, view sınıfındaki render metodunu döndürdük. Yani kısacası view yorumlamak, view sınıfının işidir dedik. Şimdi, model işlemlerine bir göz atalım.

/app/core/controller.php (devamı):

class controller
{
	/**
	 * View dosyası çağırmamıza yarayan metod
	 * @param string $file dosyasını adını alır
	 * @param array $params parametreleri alır
	 * @return void view sınıfından render metodu döner
	 */
	public function render($file, array $params = [])
	{
		return view::render($file, $params);
	}

	/**
	 * Model dizininden model dosyası çağırır
	 * @param string $model model dosyası adı
	 * @return void model sınıfı
	 */
	public function model($model)
	{
		/**
		 * Eğer model dosyası varsa 
		 * çağırıp döndürelim
		 */
		if (file_exists($file = MDIR."/{$model}.php")) {
			require_once $file;
			/**
			 * Eğer model sınıfı tanımlıysa
			 * model sınıfını döndür
			 */
			if (class_exists($model)) {
				return new $model;
			/**
			 * Model sınıfı tanımlı değilse programı durdur
			 */
			} else {
				exit("Model dosyasında sınıf tanımlı değil: $model");
			}
		/**
		 * Eğer sınıf yoksa, hata döndürelim
		 */
		} else {
			exit("Model dosyası bulunamadı: {$model}.php");
		}
	}

	/**
	 * Yönlendirme yapar
	 * @param string $path yol
	 */
	public function redirect($path)
	{
		header("Location: {$path}");
	}

	/**
	 * URL oluşturur
	 * Bu sınıfı görünüm dosyası içinde rahat kullanmak için statik yaptık
	 * @return string URL
	 */
	public static function url()
	{
		return URL.'/?url='.implode('/', func_get_args());
	}
}

Sınıfa üç tane yeni metod ekledik. Bunlardan ilki olan model metoduna göz atalım. Bu metod, model dosyası çağırmak için işimize yarayacak olan metodumuz olacak. Böylelikle Controller ile model ilişkisini tamamlamış olacağız.

Evvela file_exists() fonksiyonu ile dosya varlığı kontrolü yapıyoruz ve varsa require_once() ile sayfaya dahil ediyoruz. require_once() kullanmamın sebebi, olası durumlarda sayfaya iki kere dahil edilmesini engellemek. Sonrasında sınıfın varlığını kontrol ediyoruz ve model metodunu bu sınıf olarak döndürüyoruz (new $model).

Gelelim redirect() metoduna, bu metod ihtiyaç halinde yönlendirmemizi yapıyor. URL’ye göre header’ı ayarlayıp, yönlendirmeye yardımcı oluyor. url() methodu ise URL dizgesi üretmemize yardımcı oluyor.

Olanlar bunlar. Dilersek eklemeleri kendi isteğimize göre yapabiliriz. Artık bir controller oluştururken, bu sınıfı genişleteceğiz (extend). Yani şöyle:

class blogController extends controller
{
	public function indexAction()
	{
		$blog_model = $this->model('blog'); // app/models/blog.php çağırır
		$this->render('blog/post.php'); // app/views/blog/post.php çağırır
	}
}

Kolay gelsin.

Adım adım:

  1. Yeni Başlayanlar İçin PHP’de MVC
  2. MVC Uygulaması İçin İlk Adımlar: App Sınıfı
  3. MVC’de Giriş Sayfası, Ayarlamalar ve İlk Controller
  4. Controller ve View Çekirdek Sınıflarını Oluşturmak (Şu an buradasınız)
  5. Model Katmanı ve Veritabanı İşlemlerini Kolaylaştırmak
  6. Proje/Uygulamanın Deposu
  7. Uygulamanın bitmiş halini indirin

MVC’de Giriş Sayfası, Ayarlamalar ve İlk Controller

PHP ile bir uygulama yapmaya başlarken öncelikle yapmamız gereken dizin veveritabanı gibi birçok etkenin hiyerarşisini kafamızda tahayyül etmektir. Ardından dosya ve dizinleri oluşturarak işe başlarız. İşte bunların yapısını, sistem içerisinde de rahatça kontrol edebilmek için bazı sabitlere ihtiyaç duyarız. Sabitlerin konusuna şu sayfadan ulaşabilirsiniz. Sabit tanımlamalar ile dizinlerdeki dosyaları rahatça sayfaya dahil edebilecek (require, include) ve işlemlerimizi yapabileceğiz. Basit bir MVC sistemi kodladığımız için bunu en basit haliyle, index.php içerisinde yapacağız. Başlayalım:

define('ROOT_DIR', __DIR__); // Kök dizin
define('APP_DIR', ROOT_DIR.'/app'); // Uygulama dizini
define('CORE_DIR', APP_DIR.'/core'); // Çekirdek dizini
define('MDIR', APP_DIR.'/models'); // Model dizini
define('VDIR', APP_DIR.'/views'); // View dizini
define('CDIR', APP_DIR.'/controllers'); // Controller dizini
define('URL', 'http://localhost'); // Sistemin çalışacağı URL

Bu tanımlamalar sırasıyla, kök dizini, uygulama dizinini, çekirdek dizinini, model/view/controller dizinlerini işaret ediyor. Bunları daha ileride işimizi kolaylaştırmaları açısından kullanacağız. Peki neden böyle bir şeye ihtiyaç duyuyoruz? Olası bir dizin değişikliği durumunda örneğin; uygulama dizininin yerini değiştirdiğimizde uygulama içindeki birçok kod satırından değiştirmek yerine, index.php içerisinde kontrol edebilmiş olacağız.

// Veritabanı ayarlamalarını yapıyoruz
// Eğer ki veritabanı işlemi yapmayacaksak ayarlamak şart değil
define('DB_DSN', 'mysql:host=localhost;dbname=blog;charset=utf8');
define('DB_USR', 'root');
define('DB_PWD', 'root');

Model dosyamızla haşır neşir olduğumda bu veritabanı bilgileri ile çalışacağız, bunlar da bir kenarda dursun.

Şimdi gelelim çekirdek dizinindeki dosyalara. /core dizininde app.php oluşturmuştuk, aynı zamanda üç tane daha dosya oluşturalım ve adları model.php, view.php, controller.php olsun.

// Çekirdek sınıflarımızı dahil ediyoruz
// Bu uygulamanın çalışması için mecburi
require CORE_DIR.'/app.php';
require CORE_DIR.'/model.php';
require CORE_DIR.'/view.php';
require CORE_DIR.'/controller.php';

Sistemi çalıştıran noktaya gelelim ve yazalım:

// Uygulamamızı oluşturuyoruz
$app = new app;

// Oluşturduğumuz uygulamayı çalıştırıyoruz
$app->run();

index.php içeriği şu şekilde olacak:

define('ROOT_DIR', __DIR__); // Kök dizin
define('APP_DIR', ROOT_DIR.'/app'); // Uygulama dizini
define('CORE_DIR', APP_DIR.'/core'); // Çekirdek dizini
define('MDIR', APP_DIR.'/models'); // Model dizini
define('VDIR', APP_DIR.'/views'); // View dizini
define('CDIR', APP_DIR.'/controllers'); // Controller dizini
define('URL', 'http://localhost'); // Sistemin çalışacağı URL

// Veritabanı ayarlamalarını yapıyoruz
// Eğer ki veritabanı işlemi yapmayacaksak ayarlamak şart değil
define('DB_DSN', 'mysql:host=localhost;dbname=blog;charset=utf8');
define('DB_USR', 'root');
define('DB_PWD', 'root');

// Çekirdek sınıflarımızı dahil ediyoruz
// Bu uygulamanın çalışması için mecburi
require CORE_DIR.'/app.php';
require CORE_DIR.'/model.php';
require CORE_DIR.'/view.php';
require CORE_DIR.'/controller.php';

// Uygulamamızı oluşturuyoruz
$app = new app;

// ve oluşturduğumuz uygulamayı çalıştırıyoruz
$app->run();

Geçerli Controller dosyamızı hazırlayalım. App sınıfı başlatıcısında geçerli controller’ı defaultController olarak tanımlamıştık. Şimdi bunu biraz daha somutlaştıralım:

/app/controllers/defaultController.php:


class defaultController
{
  /**
   * indexAction metodu, giriş aksiyonudur
   * eğer sorgu dizgesinde (/?url=sorgu/digesi) hiçbir şey
   * belirtilmemişse bu sınıf ve metod tetiklenir
   */
  public function indexAction()
  {
    echo 'Merhaba Dünya!';
  }

  public function fooAction()
  {
    echo 'Burası fooAction!';
  }
}

Gelin şimdi ilk denemelerimizi yapalım:

ES1 ES2

Buraya kadar her şey yolunda! Ama büyük eksiklikler var. Controller dosyamızda view ve model kullanabilmek/çağırabilmek için sınıfımızı genişletmemiz gerekiyor. Bunu da bir sonraki yazıda işleyeceğiz.

Kolay gelsin.

Adım adım:

  1. Yeni Başlayanlar İçin PHP’de MVC
  2. MVC Uygulaması İçin İlk Adımlar: App Sınıfı
  3. MVC’de Giriş Sayfası, Ayarlamalar ve İlk Controller (Şu an buradasınız)
  4. Controller ve View Çekirdek Sınıflarını Oluşturmak
  5. Model Katmanı ve Veritabanı İşlemlerini Kolaylaştırmak
  6. Proje/Uygulamanın Deposu
  7. Uygulamanın bitmiş halini indirin

MVC Uygulaması İçin İlk Adımlar: App Sınıfı

İkinci yazıdan merhaba arkadaşlar. Bu yazıda çalışmalara başlayıp ortaya güzel şeyler çıkaracağız. Evvela MVC uygulamasında kendimize uygun bir dizin yapısı belirlememiz gerekiyor. Bizim yapacağımız sistem şu şekilde olacak:

/app
  /controllers
    defaultController.php
    postController.php
  /core
    app.php
    controller.php
    model.php
    view.php
  /models
    post.php
  /views
    -görünüm dosyaları-
index.php

Evvela, /core dizinindeki app.php dosyası ile başlıyoruz. app sınıfı, bizim temel işlemlerimizi yapacak olan sınıftır. Kabaca anlatmak gerekirse bir kullanıcı siteye girdiği vakit ilk olarak app sınıfından geçecek ve kullanıcının ne istediğini app sınıfında yapacağımız işlemlerle anlayıp yönlendireceğiz. app sınıfı ile controller dosyalarını tetikleyecek, controller dosyaları ile model ve view katmanlarını kullanacağız.

/app/core/app.php:

class app
{
	/**
	 * Sınıf içerisinde tutulacak değerler
	 * __construct metodu ile belirleyip
	 * run metodu ile kullanacağız
	 */
	public $controller, $action, $params;

	/**
	 * Controller ve Action'ı belirleyen başlatıcı metod
	 */
	public function __construct()
	{
		/**
		 * Eğer url sorgusu varsa, başındaki ve
		 * sonundaki / işaretlerini siliyoruz
		 * yoksa geçerli olarak default/index
		 */
		$url = isset($_GET['url']) && !empty($_GET['url']) ? 
			trim($_GET['url'], '/') : 'default/index';

		/**
		 * URL dizgesini / karakterleriyle bölüyoruz
		 * Böylelikle her bölüme ulaşabileceğiz
		 */
		$url = explode('/', $url);

		/**
		 * Controller ve Action'ı belirliyoruz
		 * Eğer $url[0] varsa onu $url[0].'Controller' yani $url[0]'ın default olduğunu varsayalım
		 * indexController olacaktır, eğer yoksa defaultController olarak ayarla dedik
		 * Aynı işlemi action için de yapıyoruz. Action $url[1]'de yer alıyor
		 */
		$this->controller = isset($url[0]) ? $url[0].'Controller' : 'defaultController';
		$this->action = isset($url[1]) ? $url[1].'Action' : 'indexAction';

		/**
		 * array_shift fonksiyonu, dizedeki ilk elemanı siler/kaldırır
		 */
		array_shift($url);
		array_shift($url);

		/**
		 * $url[0] ve $url[1]'i aldık, gerisi parametre. 
		 * Yani default/index/1/2/3'ün 1/2/3 olan yeri. 
		 */
		$this->params = $url;
	}
}

Dikkat edilmesi gereken nokta $_GET['url'] kodunu kullanarak neler yaptığımız. Öncelikle varlığını sorguluyor varsa sağ ve solunda bulunan / karakterlerini trim fonksiyonu ile siliyoruz. Eğer yoksa, geçerli olarak hangi controller’ı alacağını belirliyoruz.

Uygulamada geçerli controller katmanı defaultController’dır. Geçerli aksiyon ise indexAction’dır. Aldığımız URL’i explode ile parçalara ayırıyoruz ve sınıf içerisinde bulunan değişkenlere veriyoruz. Çünkü daha sonrasında bunları run() metodunda kullanacağız.

Şimdi gelelim run() metoduna. Burada URL barından aldığımız değerlere göre hareket edip controller dosyalarını çağıracağız ve bunlara göre işlemler yapacağız. Haydi.

/app/core/app.php (devamı):

class app
{
	/**
	 * Sınıf içerisinde tutulacak değerler
	 * __construct metodu ile belirleyip
	 * run metodu ile kullanacağız
	 */
	public $controller, $action, $params;

	/**
	 * Controller ve Action'ı belirleyen başlatıcı metod
	 */
	public function __construct()
	{
		/**
		 * Eğer url sorgusu varsa, başındaki ve
		 * sonundaki / işaretlerini siliyoruz
		 * yoksa geçerli olarak default/index
		 */
		$url = isset($_GET['url']) && !empty($_GET['url']) ? 
			trim($_GET['url'], '/') : 'default/index';

		/**
		 * URL dizgesini / karakterleriyle bölüyoruz
		 * Böylelikle her bölüme ulaşabileceğiz
		 */
		$url = explode('/', $url);

		/**
		 * Controller ve Action'ı belirliyoruz
		 * Eğer $url[0] varsa onu $url[0].'Controller' yani $url[0]'ın default olduğunu varsayalım
		 * indexController olacaktır, eğer yoksa defaultController olarak ayarla dedik
		 * Aynı işlemi action için de yapıyoruz. Action $url[1]'de yer alıyor
		 */
		$this->controller = isset($url[0]) ? $url[0].'Controller' : 'defaultController';
		$this->action = isset($url[1]) ? $url[1].'Action' : 'indexAction';

		/**
		 * array_shift fonksiyonu, dizedeki ilk elemanı siler/kaldırır
		 */
		array_shift($url);
		array_shift($url);

		/**
		 * $url[0] ve $url[1]'i aldık, gerisi parametre. 
		 * Yani default/index/1/2/3'ün 1/2/3 olan yeri. 
		 */
		$this->params = $url;
	}

	/**
	 * Uygulamayı başlatır
	 */
	public function run()
	{
		// Eğer Controller dosyası varsa $file değişkenini yol olarak belirle
		if (file_exists($file = CDIR."/{$this->controller}.php")) {
			// Dosyayı sistemimize dahil edelim
			require_once $file;
			// Eğer sınıf yaratılmışsa/varsa controller'ımızı çağıralım
			if (class_exists($this->controller)) {
				// controller'ı çağıralım:
				$controller = new $this->controller;
				// Eğer metod varsa ve yaratılmışsa
				if (method_exists($controller, $this->action)) {
					// call_user_func ile controller ve metodu çağırıyoruz
					call_user_func_array([$controller, $this->action], $this->params);
				// Eğer method yoksa programdan çık
				} else {
					exit("Metod mevcut değil: {$this->action}");
				}
			// Sınıf yoksa ve yaratılmamışsa programdan çık
			} else {
				exit("Sınıf mevcut değil: $this->controller");
			}
		// Controller dosyası yoksa programdan çık
		} else {
			exit("Controller dosyası mevcut değil: {$this->controller}.php");
		}
	}
}

__construct() metodunda topladığımız bilgilerle birkaç kontrol sağlayarak işe başlıyoruz. file_exists fonksiyonu ile dosyanın var olup olmadığını soruyoruz. Burada CDIR isimli bir sabit var, bunu daha sonra index.php’de Controller dizinini işaret eden sabit olarak ayarlayacağız. Controller varsa sayfayı dahil ediyoruz, sonra sınıf ve sonrasında ise metod kontrolü yapıyoruz. Eğer her şey yolundaysa temel noktaya geliyoruz. call_user_func_array() fonksiyonu ile daha önceden belirlenmiş olan controller, action ve parametreleri çağırıyoruz. Sonucunda sistemin yapı taşını oturtmuş oluyoruz.

Örnek call_user_func_array() Fonksiyonu Kullanımı

Bu fonksiyon oldukça iş gören bir fonksiyondur. Basit bir örnekle açıklayayım:

function printMessage($name)
{
  echo "Merhaba {$name}!";
}

call_user_func_array('printMessage', ['Durruti']);

Buradaki fonksiyonu printMessage('Durruti') şeklinde de yazdırabilirdik yalnız bazı spesifik durumlarda bunu kullanamıyoruz o yüzden bu fonksiyona ihtiyaç duyabiliyoruz. Sınıflarla ise, şu şekilde çalışıyor:

class Alert
{
  public function name($name)
  {
    return "Dikkat et {$name}!";
  }
}

echo call_user_func_array([new Alert, 'name'], ['Onur']);

Son örneğimizde ise, daha kolay anlaşılabilmesi adına uygulamada kullandığımıza yakın bir örnek vereceğim. Yalnız bu sadece ufak bir senaryo, bu şekilde kullanmıyoruz:

class postController
{
 public function getAction($id)
 {
 echo 'Gösterilecek gönderi ID: ' . $id;
 }
}

if ($_GET['controller'] === 'post' && $_GET['action'] === 'get') {
 call_user_func_array([new postController, 'getAction'], [5]);
}

Umarım aklınızda yer etmiştir. Bu konuyu biraz daha internette araştırarak yeni şeyler katabilirsiniz kendinize. Bu bölüm şimdilik bu kadar. Önümüzdeki yazıda, kullanıcının ilk karşılaşacağı index.php sayfasını işleyeceğiz.

Görüşmek üzere.

Adım adım:

  1. Yeni Başlayanlar İçin PHP’de MVC
  2. MVC Uygulaması İçin İlk Adımlar: App Sınıfı (Şu an buradasınız)
  3. MVC’de Giriş Sayfası, Ayarlamalar ve İlk Controller
  4. Controller ve View Çekirdek Sınıflarını Oluşturmak
  5. Model Katmanı ve Veritabanı İşlemlerini Kolaylaştırmak
  6. Proje/Uygulamanın Deposu
  7. Uygulamanın bitmiş halini indirin

Yeni Başlayanlar İçin PHP’de MVC

Nedir bu MVC? Neden ihtiyaç duyulur? Nasıl ve nerelerde kullanılır? gibi birçok soru var kafada. Hele ki yeni bir PHP meraklısıysanız, bu sorular daha çok ve derinden gelir.

Ben, programlamayı vakit geçirmek için kullanan, ortaya bir şeyler çıkarmaya çalışan birisi olarak PHP ile makarna kod yazdığım zamanların ardından MVC ile tanıştım. Tanıştıktan sonra, bir daha görüşmedim çünkü yeterli türkçe kaynak yoktu/bulamamıştım ve tam manasıyla kavrayamamıştım. Buna istinaden şimdi aynı şekilde, bildiğim kadarıyla MVC’yi tarif edeceğim ve birkaç örnek vereceğim. Tariflerim hakkında bilgi alabilmek için, PHP’de biraz olsun OOP yani nesne yönelimli programlama bilginizin olması gerekiyor. Olmasa bile biraz zorlamanızı öneririm.

MVC, Model-View-Controller üçlüsünün baş harfleridir ve bunlar birer katmandır. Katman başka yerlere götürmesin sizi. Üç tane PHP dosyasının birleşimi gibi düşünebilirsiniz. Bu üç PHP dosyası ayrı işlemler yaparak, bizim işimizi kolaylaştırır. Model katmanı, veritabanından verileri çekmemizde bize yardımcı olur. Böylelikle verileri tek bir yerden kontrol etmiş oluruz. View katmanı, görünüm katmanıdır. Yani HTML, CSS, JavaScript gibi kodlarımızı tuttuğumuz katmandır. Controller katmanı ise sistemi kontrol ettiğimiz katmandır. Model katmanından verileri alır, View dosyasına göndeririz, View katmanında verileri listeledikten sonra kullanıcıya View dosyasını sunarız.

Bu yazı ve sonraki yazılarda basit bir MVC sistemi yazacağız. Bu sistemi kodlarken, üzerine basit bir blog sistemi de ekleyeceğiz. Her şeyi en basitinden vurgulayarak anlatacağım bu basit uygulamada, her satırın açıklamasını da yapmaya çalışacağım. Böylelikle ne yapmış olduğumuzu anlayabileceğiz. Sınıf ve metod isimlendirmelerinde Türkçe yerine İngilizce kullanacağım. Böyle yapmamın sebebi, MVC’yi anlamlandırırken İngilizce olarak anlamlandırmamızın daha sonrası için yararlı olacağı.

Yapacaklarımız:

  1. Çekirdek dizininde app sınıfının oluşturulması
    Yani, sistemin bel kemiğini ana klasörde yazacağız.
  2. Çekirdek dizininde model, view ve controller sınıflarının oluşturulması
    Yani, ana klasörde, veri, görünüm ve kontrol işlemlerini yapan kodları yazacağız.
  3. Models dizininde yeni bir model üzerinde çalışmak
    Yani, verileri yöneteceğimiz PHP kodlarında, örnek bir dosya oluşturacağız.
  4. Controllers dizininde yeni bir controller dosyası
    Yani, yeni bir kontrol dosyası oluşturup, adres barındaki URL’ye göre cevap vereceğiz.
  5. Views dizininde görünüm dosyaları yaratmak ve kullanmak
    Yani, kullanıcıların ne göreceğini, CSS ve JavaScript ayarlamalarını yapacağız.

Kabaca bu şekilde.

Projenin/uygulamanın bitmiş ve çalışır halinin deposuna buradan
İndirmek içinse buradan alalım sizi.

Önümüzdeki yazılarda görüşmek üzere.

Yazı dizisi:

  1. Yeni Başlayanlar İçin PHP’de MVC (Şu an buradasınız)
  2. MVC Uygulaması İçin İlk Adımlar: App Sınıfı
  3. MVC’de Giriş Sayfası, Ayarlamalar ve İlk Controller
  4. Controller ve View Çekirdek Sınıflarını Oluşturmak
  5. Model Katmanı ve Veritabanı İşlemlerini Kolaylaştırmak
  6. Proje/Uygulamanın Deposu
  7. Uygulamanın bitmiş halini indirin

İşimizi Kolaylaştıran 10 PHP Kodlama Yöntemi

Birçok kod yazıyoruz ve bunları ortaya koyarken herkes farklı yöntemler kullanılıyor. Bu yazıda bazı PHP ipuçlarından bahsedeceğim. Tüm bunlar hem kod kalitemizi arttıracak, hem de bize zaman kazandıracak şeyler olacak.

1. Üçlü (Ternary) Operatör

Üçlü operatör, if/else işlemlerimizi kolaylaştırmamızı sağlayan soru işareti (?) ve iki nokta üst üste (:) işaretiyle oluşturduğumuz bir yöntemdir. Bu yöntem işimizi hem kolaylaştırır hem de hızlı bir hale getirir. Örneğini görelim:

$sayfa = isset($_GET['sayfa']) ? $_GET['sayfa'] : 1;
// veya
echo isset($degisken) ? $degisken : 'Değişken yok!';

2. Hata Yönetimi & İstisna Yakalama

Programlama ile uğraşıyorsak hatalar bu işin olmazsa olmazlarından. Hatasız kul olmadığı gibi, geliştirme sürecinde de uygulama olmuyor. Tüm programlama dillerinde olduğu gibi PHP’de de hata yönetimi oldukça önemli.

try {
  // herhangi bir şey
} catch (\Exception $e) {
  echo 'Hata var: ' . $e->getMessage();
}

3. list() Fonksiyonu

Dizi öğelerini değişkenlere atamak için list() fonksiyonu iyi bir araçtır.

$kisi = ['Yılmaz Demir', 'foo@bar.com'];
list($isim, $eposta) = $kisi;

şuna denk düşer:

$isim = $kisi[0];
$eposta = $kisi[1];

4. compact() Fonksiyonu

Ben MVC ile yazdığım uygulamalarımda görünüm dosyasına parametre gönderirken genelde compact() fonksiyonu kullanıyorum. Bu çok daha kolay oluyor ve kod yapısını iyileştiriyor. Örneğin:

$baslik = 'Ana Sayfa';
$gonderiler = $gonderi->hepsi();

$this->render('gonderiler.php', compact('baslik', 'gonderiler'));

compact('baslik', 'gonderiler') şuna denk düşer:

array('baslik' => $baslik, 'gonderiler' => $gonderiler);

5. Tek Satırda if

Metodlarda/fonksiyonlarda eğer olağandan farklı bir durum olursa, süslü parantez kullanmadan if yapısını şu şekilde kullanıyorum:

if (!is_numeric($_GET['id']) return false;

6. Bulunduğunuz Dizini İşaretleyin

Programa herhangi bir dosya dahil ederken (require, include) veya bir dosya çağırırken dosya yoluna bulunulan dizini eklemek oldukça yararlı bir kullanım.

define('CONFIG_DIR', __DIR__.'/config');
// veya
require __DIR__.'/config.php';

7. İsimleri Kısaltarak Anlamsızlaştırmayın

Bizler makine değiliz. Kodlama esnasında ‘zamandan kazanırım’ diyerek değişken, fonksiyon, metod, sınıf vs. isimlerini anlamsızlaştırmak veya kısaltmak hem bize, hem de daha sonra kodu okumak isteyen insanlara epey sıkıntı çıkaracaktır. Örneğin:

$syf = 5; // $sayfa = 5;
$pg = 5; // $pagination = 5;

8. Çift Tırnak ve Tek Tırnak Farkı

PHP’de çift tırnak ve tek tırnak farklı amaçlar için kullanılır. Bazı programlama dillerinde bu fark gözetildiği gibi PHP’de de gözetilir. Çift tırnak işareti arasında değişkenleri yazdırabiliyorken, tek tırnak işareti arasında yazdıramayız. Aynı zamanda tek tırnak işaretleri arasında ASCII kontrol karakterleri kullanılamıyor. Örneklendirelim:

$isim = 'Yılmaz';
echo "Merhaba $isim"; // doğru

// şu kullanım geçersizdir:
echo 'Merhaba $isim\n'; // veya echo 'merhaba\nisim';

// daha güvenli değişken kullanımı içinse:
echo "Merhaba sevgili {$isim}!";

9. strlen() alternatifi

Birazdan göstereceğim kullanım strlen() fonksiyonu için ufak bir alternatif olabilir. Ama türkçe karakterler için kullandığımız mb_strlen() için bir alternatif olamıyor. Şöyle ki:

$kullaniciAdi = 'demir';
echo isset($kullaniciAdi[14]) ? 'Kullanıcı adı 15 karakterden fazla olamaz' : null;
echo !isset($kullaniciAdi[2]) ? 'Kullanıcı adı 3 karakterden az olamaz' : null;

10. Fonksiyonları Tanımlarken Hatayı Önlemek

Genelde, düzenli kod yazımında ve ortak çalışma yapıldığında bu yöntem çokça kullanılır. Birçok geliştirici bunu alışkanlık haline getirmiştir, size de önerim bu şekilde kullanmanızdır. Fonksiyon tanımlamadan önce, o fonksiyonun tanımlanıp tanımlanmadığını kontrol etmek.

if (!function_exists('permalink')) {
  function permalink($string)
  {
     # kodlar...
  }
}

Umarım hepsi iş görür, iyi kodlamalar.

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

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

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

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

Connection.php


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

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

Haberler.php

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

Haber.php?id=5

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

HaberSayisi.php

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

Ekleme/Düzenleme/Silme

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

PHP’de Compact Fonksiyonu

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

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

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

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

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

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

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

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

PHP ve Sabit Tanımlamalar

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

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

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

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

Sabitlerin Kontrolü

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

define('TEST', 'foo');

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

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

Sabitlere Tanımlayabileceğimiz Türler

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

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

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

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

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

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

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

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

Sınıflardaki Sabitler

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

class Test
{
    const FOO = 'Sabit';

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

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

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

Sabitlerin Kullanım Yerleri

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


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

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

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

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

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

Sabitlerin Kullanımı ve Performans

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

Kolay gelsin.

jQuery ile Dinamik Olarak Oluşturulan Elemente Erişmek

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

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

Kolay gelsin.

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

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

DemirPHP Veritabanı Sınıfı

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

Basit bir kullanım örneği:


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

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