echo
attığınızda else
bloğuna giriyorsanız -ki aldığınız hata da bunu destekliyor- şu anlama gelir:
'Admin' adlı class'ınızın içinde 'Listele' adlı bir fonksiyona ulaşılamıyor.
O zaman düzgün bir şekilde *Admin isimli sınıfta Listele methodu bulunamadı!* yazmasını bekliyorsunuz ama hata mesajı dönüyor.
Hata mesajı: Object of class Admin could not be converted string.
Yani: Admin class'ının objesi string'e dönüştürülemedi.
$ClassName
değişkeninizde Admin class'ından türetilen obje var.
'<b>' . $ClassName . '</b> isimli sınıfta <b>' . $Method . '</b> methodu bulunamadı!'
şeklinde bir string birleştirme işlemi yapıyorsunuz ama string'in içine object'i yerleştiremiyor.
Bu karışıklık, değişken adınızın yanıltıcı olmasından kaynaklanıyor. Değişken adınız $ClassName
sanki içinde bir string ifade barındırıyormuş gibi düşündürüyor.
Bu isim yerine yerine $ClassObject
ismi verilebilir. Böylece değişkenin adı bile yanlış kullandığınız yerde sorunu fark etmenize yardımcı olur.
Yani öncelikle $ClassName
değişkeninizin adını $ClassObject
olarak güncellemelisiniz.
Sorunu çözmek için de, $ClassObject
i tanımladığınız satırın hemen altına bir $ClassName
değişkeni tanımlayın ve sınıfın adını (string olarak) buraya atayın.
$ClassObject = new $Controller();
$ClassName = get_class($ClassObject); // Objenin türetildiği sınıfın adını string olarak verir.
if (method_exists($ClassObject, $Method)) {
call_user_func_array([$ClassObject, $Method], $Parameters);
} else {
exit("<b>$ClassName</b> isimli sınıfta <b>$Method</b> fonksiyonu bulunamadı!");
}
Gözüme çarptığı kadarıyla şu satırda da henüz karşılaşmadığınız bir sorun var:
exit('<b>' . $ControllerFile . '</b> isimli controller dosyasında <b>' . $ClassName . '</b> sınıfı bulunamadı!');
Burada kullandığınız $ClassName
değişkeni hiç oluşturulmamış bir değişken. Yani bu değişken yalnızca if
bloğunda oluşturuluyor. Bu yüzden else
bloğunda bu değişkene erişemezsiniz. Yani PHP belki bir esneklik sunuyordur ama en iyi ihtimalle hata almak yerine boş string elde edersiniz.
Bu satırı da şu şekilde düzeltebilirsiniz:
exit("<b>$ControllerFile</b> isimli controller dosyasında <b>$Controller</b> sınıfı bulunamadı!");
/lib/view.class.php dosyasındaki render()
fonksiyonu:
public function render(){
$data = $this->data;
ob_start();
include($this->path);
$content = ob_get_clean();
return $content;
}
ob_start();
ile tamponlama işlemlerinin başlayacağı belirtiliyor.include($this->path);
ile ilgili view dosyasının içeriği buraya yazılıyor. Yani aslında html dosyası olsa da, dosyada yazan veriler bu php dosyasına alınmış oluyor. Bu php dosyası, içindeki php komutlarını işleyebilir.$content = ob_get_clean();
ile tamponlama işlemi sonlanıyor ve işlenmiş içerik$content
değişkenine aktarılıyor.return $content;
ile bu fonksiyon, içeriğin işlenmiş halini (yani php kodlarının işlenip html içine yazılmış, yani php kodları barındırmayan halini) döndürüyor.
Yani regex ile arayıp bulup işlem yapmasına gerek kalmadan ob_get_clean()
ile php kodunu işlemiş.
Sanırım şu site tam istediğiniz işi yapıyor:
https://mocki.io/fake-json-api
- Nasıl bir json çıktısı almak istediğinizi yazıyorsunuz.
- Create API diyorsunuz.
- Size bir endpoint veriyor.
- Endpoint'e istek attığınızda, oluşturduğunuz json'u response olarak alabiliyorsunuz.
Kayıt olunduğunda daha detaylı özellikler sunuyordur muhtemelen. Ücretsiz deneme için kayıt olmadım.
Bu tip size özel endpoint'lere çokça ihtiyacınız oluyorsa aylık 10$ uygun bir fiyat gibi.
Özellikle username
, avatar
ve email
key'lerine ihtiyacınız varsa şurası da iş görür sanıyorum:
https://fakeapi.platzi.com
Burada ücretle ilgili bi'şey belirtmemişler.
Normalde çalışmaz. Sonradan html uzantısını değiştirip php'ye çeviriyorlardır. Videonun ilerleyen zamanlarında hatayı fark edip düzeltirler.
Veya "Bakın html sayfasına PHP kodu yazdım ama çalışmadı. Çünkü html sayfada php kodu çalışmaz." demek için yazdıkları bir an da olabilir bu.
Yok eğer bile isteye bu şekilde yazıyorlarsa bambaşka bir mantık kurmuşlardır.
Diğer açık sekmelerden anladığım kadarıyla burada bir framework geliştiriliyor.
Bu framework'ün çalışma mantığında bu kullanımın bir anlamı olabilir ama bunu bilemeyiz.
Örneğin bir php sayfası, bu default.html sayfasını okuyordur ve regex ile içinde php'ye ait bir kısım varsa bunu replace ediyordur.
Yani aslında php kodunu yine bir php sayfası çalıştırıyordur. Bu html, yalnızca başka bir php sayfasından okunmak ve değiştirilmek üzere yazılıyordur.
Burada ne yapılmak istendiği eğitim programında anlatılıyor olsa gerek.
1) Sunucuya Sahte GET İsteği Atmak
Stackoverflow'da 2012 yılından şöyle bir bilgiye rastladım:
Android uygulamam sunucuya POST istekleri gönderdi ve beklendiği gibi çalışıyordu ancak yaklaşık 30 dakika sonra 408 İstek zaman aşımı hataları yaşamaya başladım.
Ayrıca bir PC'den veya Android cihazdan bir tarayıcı açıp ana sayfamı (PHP Wordpress sitesi) açtığımda sorunun ortadan kalktığını fark ettim.
Web sitesi testte olduğundan web trafiği minimum düzeydeydi ve bu davranışı sunucu günlüklerinde oldukça kolay bir şekilde doğrulayabildim.
POST isteğimden önce sahte bir GET isteği yürüterek bu soruna geçici bir çözüm bulmayı başardım ve bu, web sunucusunu 'uyandırdı' ve sonraki tüm POST isteklerine yanıt verdi.
Buna 2015'te gelen bir yanıtta da şu bilgi veriliyor:
Bağlantıları sıfırlayarak müdahale eden bazı trafik izleme aracıları için tüm POST'lar ve otuz dakika boyunca hiçbir GET'in olmaması şüpheli görünüyor.
Trafiğin kötü niyetli olduğunu düşündükleri takdirde her iki uca da sahte sıfırlamalar gönderen ürünler var.
Bu daha sonra bağlantıyı keserek zaman aşımına neden olur.
2016'da da aynı yanıta söyle bir yorum eklenmiş:
Bana öyle geliyor ki, en azından bazı durumlarda bu sorunlar oturum zaman aşımlarından da kaynaklanıyor olabilir.
Oturum yenilemeleri GET istekleri için gerçekleştiriliyor ancak POST istekleri için gerçekleştirilmiyor olabilir; bu da 'uyanma' davranışını açıklayabilir.
Buna göre, siz de arada bir sunucuya sahte GET istekleri atarak sunucuyu 'uyandırmayı' deneyebilirsiniz.
Kaynak: https://stackoverflow.com/questions/1667720/http-408-request-timeout
2) response.end()
Kullanılmamış Olabilir
Postman'dan yanıt alabiliyorsanız sorun bu değildir muhtemelen.
Ama endpoint'inizde veya bir middleware'ınızda response.end()
(veya .send()
gibi bir istek sonlandırıcı sonlandırıcı fonksiyon) komutuna ulaşılmasını önleyen bir koşul oluşuyor olabilir.
Mesela header'ları kontrol ettiğiniz bir aşamada bir return
ifadesi kullanmışsınızdır ve response.end()
komutuna ulaşılmasını önlemişsinizdir veya bir if-else
yapınız response.end()
komutunu atlamanıza neden oluyor olabilir.
Sunucunuza bir console.log()
ekleyip gelen header'ı terminale basın.
Sonra siteden ve Postman'dan ayrı ayrı istek atın ve header'lar arasındaki farklara bakın.
Fark yoksa, bir isteğin geçtiği tüm aşamaları takip edip response.end()
komutunun çalışmadan işlemlerin bittiği bir durum var mı diye inceleyin.
Kaynak: https://stackoverflow.com/questions/22773927/408-timeout-in-nodejs-app-requesting-github-api
3) İstemci, İsteği Yarıda Kesmiş Olabilir
İsteği gönderiyorsunuzdur ama hemen sonra (belki bir state değişimi yüzünden) isteği iptal ediyorsunuzdur.
Aslında yukarıdaki gibi bir sorun ama bu sefer istemci tarafında...
Çözüm olarak yine sunucuya console.log()
atıp gelen isteğin body ve header'larını terminale basın. Sonra postman ve site isteklerinin arasındaki farkları bulmaya çalışın.
Kaynak: https://docs.aws.amazon.com/en_en/elasticloadbalancing/latest/classic/ts-elb-error-message.html#ts-elb-errorcodes-http408
Daha farklı nedenler de olabilir tabi sunucunun zaman aşımı süresini uzatmak gerekiyor olabilir vs. ama sorun orada olsa Postman da yanıt alamazdı.
Burada nesne yönelimli bir çözüm kullanabilirsiniz.
Modelleriniz birer class olmalı. Verdiğiniz örnek üzerinden ilerlersek...
blog.php sayfanızın adı, içereceği class adıyla aynı olsun. Class adları büyük harfle başlayacağı için dosya adı da büyük harfle başlasın.
Blog.php
class Blog {
function vericek(){
global $db;
$bul = $db->prepare("SELECT * FROM blog");
$bul->execute();
$yaz = $bul->fetchAll(PDO::FETCH_ASSOC);
return $yaz;
}
}
Model fonksiyonunuz da bir class olsun:
class Model {
public $model;
public $error;
public function __construct($name) {
// MODELS_DIR klasöründe $name adında bir dosya varsa:
if(file_exists(MODELS_DIR.$name.".php")){
// Model dosyasını çağır
require_once(MODELS_DIR.$name.".php");
// Model dosyasında aynı isimle bir class yer alıyorsa:
if(class_exists($name)) {
// $model olarak bu sınıftan oluşturulan nesneyi belirle.
$this->model = new $name();
$this->error = null;
}
// Model dosyasında aynı isimle bir class yer almıyorsa:
else {
$this->error = "Model dosyasında $name adlı class bulunamadı.";
$this->model = null;
}
}
// MODELS_DIR klasöründe $name adında bir dosya yoksa:
else {
$this->error = "$name adlı model dosyası bulunamadı.";
$this->model = null;
}
}
}
Artık Model class'ınız sayesinde istediğiniz model class'ından bir nesne türetip kullanabilirsiniz:
$blogModel = new Model('Blog');
if($blogModel->error) exit($blogModel->error);
$result = $blogModel->model->vericek();
echo "<pre>";
var_dump($result);
echo "</pre>";
Burada Blog.php dosyasını yeniden include etmeye gerek yok. Çünkü sınıfın bütün özelliklerini taşıyan bir nesnesi $blogModel->model içinde mevcut.
Passing null to parameter #2 ($replace) of type array|string is deprecated.
Yani, 2. parametreye null gelmesi PHP 8 ile artık kaldırıldı. Önceki sürümlerde null verilirse boş string olarak kabul ediliyordu muhtemelen.
Hatayı aslında şu satırda alıyorsunuz:
$request_uri = str_replace([$dirname, $basename], null, $_SERVER['REQUEST_URI']);
Burada null
olan parametre array veya string olmalı. Şu şekilde düzeltilebilir:
$request_uri = str_replace([$dirname, $basename], '', $_SERVER['REQUEST_URI']);
Bunu yaptığınızda $_SERVER['REQUEST_URI']
içinde geçen $dirname
veya $basename
ifadelerininin silinmiş halini $request_uri
değişkenine atayacaktır.
Evet, orada da eksik yazmışım.
ana_yorum Düzeltmeler doğru.
// Bu kısmı
<a href="#" class="mt-2" data-ust-yorum-id="<?= $data['yorum_id'] ?>">Cevapla</a>
// Bu şekilde değiştirdim.
<a href="#" class="mt-2" data-ust-yorum-id="<?= $data['yorum']['yorum_id'] ?>">Cevapla</a>
cevap_yorum burada da cevapla kısmı üsttekiyle aynı olmalı ki hep ana yoruma bağlı kalsın.
// Bu kısmı
<a href="#" class="mt-2" data-ust-yorum-id="<?= $data['yorum_id'] ?>">Cevapla</a>
// Bu şekilde değiştirdim.
<a href="#" class="mt-2" data-ust-yorum-id="<?= $altYorum['yorum_id'] ?>">Cevapla</a>
// yerine şöyle olmalı
<a href="#" class="mt-2" data-ust-yorum-id="<?= $data['yorum']['yorum_id'] ?>">Cevapla</a>
İlk fonksiyonda eksik yazmışım gibi görünüyor.
Bu yüzden hiyerarşi düzgün oluşamamış.
else içindeki 'yorum_id' kısmını 'ust_yorum_id' olarak düzelttim:
$yorumlar = tumYorumlar($mak_id);
$duzenlenmisYorumlar = [];
foreach($yorumlar as $yorum) {
// Baktığımız yorumun üst yorumu yoksa, ana yorum olarak eklensin.
if($yorum['ust_yorum_id'] === 0) {
$duzenlenmisYorumlar[ 'yorum_'.$yorum['yorum_id'] ] = ['yorum'=>$yorum, 'alt_yorumlar'=>[]];
}
// Baktığımız yorumun üst yorumu varsa, o yorumun alt yorumu olarak eklensin
else {
$duzenlenmisYorumlar[ 'yorum_'.$yorum['ust_yorum_id'] ]['alt_yorumlar'][] = $yorum;
}
}
Ayrıca ikinci foreach içinde de patlama ihtimalini engellemek gerek.
<?php foreach($duzenlenmisYorumlar as $key=>$data) { ?>
<?php if(!isset($data['yorum'])) continue; ?>
<div class="ana_yorum" data-key="<?= $key ?>">
<div><?= $data['yorum']['yorum_adi'] ?></div>
<div><?= $data['yorum']['yorum_icerik'] ?></div>
<a href="#" class="mt-2" data-ust-yorum-id="<?= $data['yorum_id'] ?>">Cevapla</a>
<?php foreach($data['alt_yorumlar'] as $altYorum) { ?>
<div class="cevap_yorum">
<div><?= $altYorum['yorum_adi'] ?></div>
<div><?= $altYorum['yorum_icerik'] ?></div>
<a href="#" class="mt-2" data-ust-yorum-id="<?= $data['yorum_id'] ?>">Cevapla</a>
</div>
<?php } ?>
</div>
<?php } ?>
Not: Bu sistem, yazılan bir ana yorum altına cevaplar eklenmesini sağlar.
Ama yoruma verilen cevaba verilen cevap şeklinde düzen oluşturmaz.
Bu nedenle verilen cevaplar her zaman ust_yorum_id
'ye bakılarak yapılmalı.
O yüzden belki değiştirip kullanabilmeniz için <a>
taglarınıza, üst yorum id'lerini bir attribute olarak ekledim.
Eğer çalışmazsa, showVar()
fonksiyonu ile yeniden $duzenlenmisYorumlar
dizisine bakabiliriz.
Bu hata, 24.satırda array'in "yorum" diye bir key'ine ulaşılmaya çalışıldığını ama öyle bir key olmadığını söylüyor.
$yorumlar
değişkeni içinde nasıl bir veri geliyor?
$duzenlenmisYorumlar
değişkeni içinde nasıl bir veri oluşuyor?
Bunları görüp ona göre bir yaklaşım üretebiliriz.
Bu değişkenlerin değerlerini paylaşabilir misiniz?
function showVar($var) {
echo '<pre>';
var_dump($var);
echo '</pre>';
}
Bu şekilde bir fonksiyon oluşturup, bu fonksiyon ile değişkenlerin değerini alabilirsiniz:
$yorumlar = tumYorumlar($mak_id);
$duzenlenmisYorumlar = [];
foreach($yorumlar as $yorum) {
// Baktığımız yorumun üst yorumu yoksa, ana yorum olarak eklensin.
if($yorum['ust_yorum_id'] === 0) {
$duzenlenmisYorumlar[ 'yorum_'.$yorum['yorum_id'] ] = ['yorum'=>$yorum, 'alt_yorumlar'=>[]];
}
// Baktığımız yorumun üst yorumu varsa, o yorumun alt yorumu olarak eklensin
else {
$duzenlenmisYorumlar[ 'yorum_'.$yorum['yorum_id'] ]['alt_yorumlar'][] = $yorum;
}
}
showVar($yorumlar);
showVar($duzenlenmisYorumlar);