PHP’de gelen istekleri (request) cevaplamak (response) için en kullanışlı yöntemlerden birisi router kullanmaktır. Popüler PHP ve PHP olmayan web çatılarının (framework) olmazsa olmazıdır router/yönlendirici/rotacı.
Rotalar, belli özelliklere sahiptir. Bunlardan en önemli üçü şunlardır:
- Rota yolu (
/sayfa/5,/gonderi/3gibi) - İstek metdodları (
GET,POST,PUT,PATCH,DELETEvs. gibi) - Geri çağırım işlevleri (en basit tabiriyle fonksiyonlar veya sınıf metodları)
 
Eğer tüm bunları sağlarsak, sağlıklı bir rotacı yaratabilir ve rahatlıkla kullanabiliriz. Bunların dışında middleware(lar) (ara katmanlar olarak çevrilebilir), rota isimlendirmesi gibi birçok özellik/parametreye sahip olabilirler.
Şimdi vereceğim örnekte yalnızca GET ve POST istek metodlarını karşılayacak olan basit bir rotacı yazacağız.
Başlayalım.
Evvela bir Router sınıfımızı yaratıp gerekli metodları yaratalım.
Router.php
class Router
{
  /**
   * Mevcut yolu tutar
   * @var string
   */
  protected $actualPath;
  /**
   * Mevcut istek metodunu tutar
   * @var string
   */
  protected $actualMethod;
  /**
   * Tanımlanmış rotaları tutar
   * @var array
   */
  protected $routes = [];
  /**
   * 404 Sayfasını tutar
   * @var Closure|string
   */
  protected $notFound;
  /**
   * Rotacıyı başlatır
   * @param string $currentPath Mevcut yol
   * @param string $currentMethod Mevcut istek metodu
   */
  public function __construct($currentPath, $currentMethod)
  {
    $this->actualPath = $currentPath;
    $this->actualMethod = $currentMethod;
    // Sayfa bulunamadı rotasını ayarlayalım
    $this->notFound = function(){
      http_response_code(404);
      echo '404 Not Found';
    };
  }
  /**
   * Yeni bir GET rotası yaratır
   * @param string $path İstek yolu
   * @param Closure|string $callback Geri çağırım işlevi
   * @return void 
   */
  public function get($path, $callback)
  {
    $this->routes[] = ['GET', $path, $callback];
  }
  /**
   * Yeni bir POST rotası yaratır
   * @param string $path İstek yolu
   * @param Closure|string $callback Geri çağırım işlevi
   * @return void
   */
  public function post($path, $callback)
  {
    $this->routes[] = ['POST', $path, $callback];
  }
  /**
   * Rotalar tanımlandıktan sonra eşleşen rotayı bulup çalıştırır
   * @return mixed
   */
  public function run()
  {
    foreach ($this->routes as $route) {
      list($method, $path, $callback) = $route;
      $checkMethod = $this->actualMethod == $method;
      $checkPath = preg_match("~^{$path}$~ixs", $this->actualPath, $params);
      if ($checkMethod && $checkPath) {
        array_shift($params);
        return call_user_func_array($callback, $params);
      }
    }
    return call_user_func($this->notFound);
  }
}
Yukarıdaki yazdığım sınıfta her metodun üstündeki açıklama bölümlerinde alacağı parametreleri ve metodların ne iş yaptığını yazdım. Ama biz yine de metodların ne işe yaradığını detaylandıralım:
__constructmetodundaRoutersınıfı oluşturulurken iki parametre aldık. Bunlardan$currentPathparametresi kullanıcının sayfaya girmek istediğinde oluşacak olan URL barındaki yol değeridir. Yanihttps://yilmazdemir.com.tr/herhangi/bir/seydizgesindeki/herhangi/bir/sey.$_SERVER['REQUEST_URI']ile elde edebiliyoruz. Bir sonraki adımda yapacağız.- İkinci parametre 
$currentMethodparametresi. Kullanıcıdan gelen mevcut istek metoduna işaret eder. GET, POST, PUT, PATCH, DELETE gibi değerlerdir. Ama biz detaya inmeden yalnızca GET ve POST tiplerini işleyeceğiz. Daha detaylı bilgi için HTTP Protokolü’nü araştırabilirsiniz. İstek metodunu$_SERVER['REQUEST_METHOD']ile elde edeceğiz. - Metodun içinde ayrıca belirttiğimiz bir anonim fonksiyon var. Bu herhangi bir rota eşleşmediğinde döndürmek için kullanacağımız fonksiyon. Ben doğrudan kodlu (hard-coded) biçimde yazdım ama bir notFound metodu yazılarak dinamikleştirilebilir.
 getvepostmetodlarında ise rota tanımlaması yaptırıyoruz. Sınıf içerisinde$routessınıf değişkenine yeni bir değer ekleyerek aldığımız$pathve$callbackparametreleriyle rotamızı oluşturuyoruz.- Son olarak rotayı çalıştırabilmek için bir metoda ihtiyacımız var. Bu metod 
runmetodu. Örneğimizde bu metod sınıf değişkeni olan$routesdeğişkeniyle bir döngü oluşturuyor ve işlemlerimizi burada yapıyoruz.list()fonksiyonu ile her bir rota tanımlamamız için dize değerlerini değişken yapıyoruz.$checkMethodve$checkPathdeğişkenleriyle de bir doğrulama yapıyoruz. Bu doğrulamada bizim rotaları oluştururken tanımladığımız değerlerle kullanıcıdan gelen değerler eşleşiyor mu bunu arıyoruz. Eğer doğru (true) dönerse$callback‘i çalıştırıp döndürüyoruz. Eğer hiçbir uyuşma yoksa döngüden sonra 404 döndürüyoruz. 
index.php
require 'Router.php';
$path = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$router = new Router($path, $method);
$router->get('/', function(){
  echo 'Ana Sayfa';
});
$router->get('/haber/([d]+)', function($id){
  echo "Haber ID'si: {$id}";
});
$router->post('/foo', function(){
  echo 'Diğer işlemler';
});
$router->run();
Router hazır. Rota parametresi için düzenli ifadeler (Regular Expressions) kullanıyoruz. Bunlar daha da basitleştirilebilir. Ayrıca bazı buglar da mevcut. Bunları kullandıkça fark edersiniz elbette. Yeni özellikler katmak sizin hayal gücünüze bağlı. Örneğin /haberler rotası oluşturduğunuz ve sayfalamayı QueryString ile yapacaksınız. Yani /haberler?sayfa=5 şeklinde bir ifade maalesef ki eşleşmeyecektir. Bu durumda istek yolunu düzenledikten sonra sınıf içine tanımlamanız gerekiyor.
Apache için htaccess şu şekilde:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
Kolay gelsin.