PHP ile Nesne Yönelimli Yapıda Dinamik Site İçi Arama Sayfalama Nasıl Yapılır?
Modern web projelerinde kullanıcı deneyimini iyileştiren en önemli unsurlardan biri, verilerin yönetilebilir parçalar halinde sunulmasıdır. PHP ile nesne yönelimli yapıda dinamik site içi arama sayfalama yapmak, hem performanslı veritabanı sorguları oluşturmanızı sağlar hem de kodunuzun sürdürülebilirliğini artırır. Bu rehberde, 2026 standartlarına uygun, güvenli ve ölçeklenebilir bir arama ve sayfalama mimarisini adım adım inşa edeceğiz.
Bu makale, PHP'nin nesne yönelimli programlama (OOP) prensiplerini kullanarak arama sonuçlarını nasıl filtreleyeceğinizi ve bu sonuçları nasıl sayfalara böleceğinizi öğretmeyi amaçlar. Orta seviye PHP bilgisine sahip geliştiriciler için hazırlanan bu içerik, veritabanı güvenliğinden arayüz mantığına kadar uçtan uca bir çözüm sunar.
Gereksinimler ve Ön Hazırlık
Uygulamaya başlamadan önce geliştirme ortamınızın güncel olduğundan emin olmalısınız. 2026 yılı itibarıyla PHP 8.3 veya üzeri sürümlerin kullanılması, performans ve güvenlik açısından zorunludur.
- PHP 8.3+ sürümü.
- PDO (PHP Data Objects) eklentisi aktif bir veritabanı bağlantısı.
- MySQL veya MariaDB veritabanı yönetim sistemi.
- Temel düzeyde SQL bilgisi (SELECT, WHERE, LIKE, LIMIT, OFFSET komutları).
Veritabanı bağlantınızı yönetmek için bir Database sınıfı oluşturmak, nesne yönelimli yapının ilk adımıdır.
class Database {
private $host = "localhost";
private $db_name = "proje_db";
private $username = "root";
private $password = "";
public $conn;
public function getConnection() {
$this->conn = null;
try {
$this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
$this->conn->exec("set names utf8");
} catch(PDOException $exception) {
echo "Bağlantı hatası: " . $exception->getMessage();
}
return $this->conn;
}
}
Arama ve Sayfalama Mantığını Kurma
Dinamik bir arama sayfalama sisteminde iki temel değişken vardır: arama_terimi ve sayfa_numarası. Kullanıcı bir arama yaptığında, veritabanından toplam kayıt sayısını çekerek kaç sayfa oluşacağını hesaplamamız gerekir.
Aşağıdaki SearchHandler sınıfı, arama sorgularını ve sayfalama hesaplamalarını tek bir çatı altında toplar.
class SearchHandler {
private $db;
public function __construct($db) {
$this->db = $db;
}
public function getResults($query, $limit, $offset) {
$stmt = $this->db->prepare("SELECT * FROM urunler WHERE isim LIKE :query LIMIT :limit OFFSET :offset");
$stmt->bindValue(':query', '%' . $query . '%', PDO::PARAM_STR);
$stmt->bindValue(':limit', (int)$limit, PDO::PARAM_INT);
$stmt->bindValue(':offset', (int)$offset, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
Veritabanı Sorgularında Güvenlik: SQL Injection Koruması
Kritik Güvenlik Uyarısı: Kullanıcıdan gelen verileri asla doğrudan SQL sorgusuna dahil etmeyin. Yukarıdaki örnekte olduğu gibi, her zaman
preparevebindValueyöntemlerini kullanarak "Prepared Statements" (Hazırlanmış İfadeler) kullanın. Bu, SQL Injection saldırılarını önlemek için en temel savunma hattınızdır.
Arama terimini alırken htmlspecialchars() fonksiyonu ile XSS (Cross-Site Scripting) saldırılarına karşı da önlem almalısınız. Arama kutusuna girilen veriyi temizlemek, uygulamanızın güvenliğini artırır.
Sayfalama Algoritmasını Hesaplama
Sayfalama yaparken toplam kayıt sayısını bilmek, "Sonraki" ve "Önceki" butonlarının görünürlüğünü belirlemek için gereklidir. Toplam kayıt sayısını veren bir metot ekleyelim.
public function getTotalCount($query) {
$stmt = $this->db->prepare("SELECT COUNT(*) FROM urunler WHERE isim LIKE :query");
$stmt->bindValue(':query', '%' . $query . '%', PDO::PARAM_STR);
$stmt->execute();
return $stmt->fetchColumn();
}
Bu metot, arama sonucunda dönen toplam satır sayısını verir. Bu sayıyı sayfa başına düşen kayıt sayısına bölerek toplam sayfa sayısını elde edebilirsiniz.
Dinamik Arama Sayfalama İçin Karşılaştırmalı Yöntemler
Sayfalama yaparken veritabanı üzerindeki yükü optimize etmek önemlidir. Aşağıdaki tablo, farklı yöntemlerin avantaj ve dezavantajlarını özetler.
| Yöntem | Avantaj | Dezavantaj |
|---|---|---|
| OFFSET/LIMIT | Basit, uygulanması kolay. | Büyük veritabanlarında yavaşlar. |
| Keyset Pagination | Çok hızlı, büyük veride ölçeklenir. | Sıralama mantığı daha karmaşıktır. |
Arayüzde Sayfalama Linklerini Oluşturma
Mantıksal hesaplamalar bittikten sonra, kullanıcıya arayüzde tıklanabilir sayfa numaraları sunmalısınız. Bu, URL parametreleri (örneğin: ?page=2&q=arama) üzerinden yönetilir.
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$limit = 10;
$offset = ($page - 1) * $limit;
// Arama terimi
$search = $_GET['q'] ?? '';
// Sonuçları çekme
$handler = new SearchHandler($db);
$results = $handler->getResults($search, $limit, $offset);
$total = $handler->getTotalCount($search);
$totalPages = ceil($total / $limit);
Bu kod bloğu, kullanıcının hangi sayfada olduğunu belirler ve veritabanından ilgili veri dilimini çeker. ceil() fonksiyonu, toplam sayfa sayısını yukarı yuvarlayarak doğru sayfa sayısını verir.
Sıkça Sorulan Sorular
Arama sonuçları çok yavaş geliyorsa ne yapmalıyım?
Veritabanı tablonuzdaki arama yapılan sütuna "INDEX" (indeks) eklediğinizden emin olun. İndeksleme, LIKE sorgularının performansını ciddi oranda artırır.
Neden LIMIT ve OFFSET kullanıyoruz?
LIMIT, sorgudan kaç satır döneceğini belirlerken, OFFSET ise kaç satırın atlanacağını belirler. Bu ikili, veritabanı seviyesinde sayfalama yapmanın standart yoludur.
Güvenlik için sadece Prepared Statements yeterli mi?
Prepared Statements, SQL Injection için yeterlidir ancak XSS için çıktı alırken htmlspecialchars() kullanmayı asla ihmal etmeyin.
Sayfa numaraları nasıl sınırlandırılır?
Döngü kullanarak mevcut sayfanın 2 öncesini ve 2 sonrasını gösterecek bir mantık kurarak arayüzde çok fazla sayfa numarası kalabalığını önleyebilirsiniz.
PHP 8.3 ile gelen yenilikler bu yapıyı etkiler mi?
PHP 8.3, tip güvenliği ve performans konusunda iyileştirmeler sunar. Sınıf özelliklerinde "readonly" kullanımı veya daha sıkı tip tanımlamaları, bu yapıyı daha güvenli hale getirir.
Kod Güvenliği Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanmadan önce mutlaka bir güvenlik denetiminden geçirin, hata ayıklama (debug) çıktılarını kapatın ve veritabanı yetkilendirmelerini en düşük seviyede tutun.
Performans Optimizasyonu İçin İndeksleme Stratejileri
Dinamik arama sistemlerinde veritabanı sorgularının hızı, veri setiniz büyüdükçe doğrudan etkilenir. LIMIT ve OFFSET kullanımı, özellikle milyonlarca satırlık tablolarda OFFSET değeri arttıkça performans kaybına yol açar. Bu sorunu aşmak için veritabanı seviyesinde doğru indeksleme stratejileri uygulamalısınız.
Arama yapılacak sütunlarda FULLTEXT indeksleri kullanmak, LIKE '%kelime%' sorgularına göre çok daha hızlı sonuç verir. Aşağıdaki SQL komutu ile arama performansını nasıl artırabileceğinizi görebilirsiniz:
-- Arama yapılacak sütunlara FULLTEXT indeksi ekleyin
ALTER TABLE makaleler ADD FULLTEXT(baslik, icerik);
-- Arama sorgusunu MATCH AGAINST kullanarak optimize edin
SELECT id, baslik FROM makaleler
WHERE MATCH(baslik, icerik) AGAINST(:kelime IN NATURAL LANGUAGE MODE)
LIMIT :limit OFFSET :offset;
Arama Sistemlerinde Hata Ayıklama ve Loglama
Geliştirdiğiniz arama yapısının beklenmedik hatalar vermesi durumunda, kullanıcıya teknik detayları göstermek yerine bir hata kayıt sistemi oluşturmalısınız. Özellikle PDOException hatalarını yakalamak, veritabanı bağlantı sorunlarını veya hatalı sorguları tespit etmenizi sağlar.
Aşağıdaki örnekte, arama sınıfınız içinde hata yakalama mekanizmasını nasıl kurabileceğinizi inceleyebilirsiniz:
public function aramaYap(string $terim, int $limit, int $offset): array {
try {
$stmt = $this->db->prepare("SELECT * FROM makaleler WHERE baslik LIKE ? LIMIT ? OFFSET ?");
$stmt->execute(["%$terim%", $limit, $offset]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
// Hata loglama dosyasına yaz
error_log("Arama hatası: " . $e->getMessage());
// Kullanıcıya dostane bir mesaj döndür
return [];
}
}
İleri Düzey İpuçları: Arama Sonuçlarını Önbelleğe Alma
Sık yapılan aramalar veritabanına sürekli yük bindirir. Eğer arama sonuçlarınız çok sık değişmiyorsa, sonuçları Redis veya Memcached gibi bir önbellekleme katmanında tutmak, sunucu yanıt süresini milisaniyelere indirebilir.
- Sorgu Normalizasyonu: Kullanıcının girdiği terimleri küçük harfe çevirip boşluklardan arındırarak (trim) önbellek anahtarı oluşturun.
- TTL (Time To Live): Önbellekteki verilerin güncelliğini korumak için 5-10 dakikalık kısa süreli yaşam süreleri belirleyin.
- Boş Sonuç Önbelleği: Hiç sonuç bulunamayan aramaları da önbelleğe alarak veritabanı üzerindeki gereksiz yükü engelleyin.
Bu yöntemler, özellikle yüksek trafikli e-ticaret sitelerinde veya içerik yönetim sistemlerinde arama motorunun çökmesini engellemek için kullanılan standart endüstri uygulamalarıdır.
Sonuç
PHP ile nesne yönelimli yapıda dinamik site içi arama sayfalama sistemi kurmak, projenizin ölçeklenebilirliği için kritik bir beceridir. Bu rehberde; veritabanı bağlantısı, güvenli sorgu oluşturma, sayfalama hesaplamaları ve arayüz entegrasyonu adımlarını tamamladık. Bir sonraki adım olarak, bu yapıyı AJAX ile birleştirerek sayfa yenilemeden sonuçları getiren bir "Sonsuz Kaydırma" (Infinite Scroll) özelliği eklemeyi deneyebilirsiniz.


Yorumlar (0)
Yorum Yaz