Hata Yönetimi
Tek bir işleyici her şeyi yakalar ve çağıranın ne göreceğine karar verir. Hata yanıtı kurmak yerine fırlatmanızın sebebi budur; sessiz bir arıza da neredeyse her zaman yakalanmış bir arızadır.
Genel Bakış
Başlangıç; PHP hataları, yakalanmamış exception'lar ve ölümcül kapanışlar için işleyiciler kurar. O noktadan sonra hiçbir şey kendi başına düşmez. İşleyici kaydeder, sonra isteğin beklediği biçimde gösterir: bir HTML sayfası ya da bir JSON gövdesi.
Operation'ın içinde ikinci bir katman vardır. Dağıtıcı metodunuzu bir try bloğuna sarar; böylece fırlattığınız exception, metniniz mesajı olacak şekilde hata yanıtına dönüşür. Bir değişikliğin hata yolu bundan ibarettir: fırlat ve yazmayı bırak.
Referans
Hata Bildirme
$error özelliğine yazıp false döndüren eski bir modül, önceki ana sürümden kalma bir deseni taşıyordur. Taban sınıflar bunu hâlâ fırlatmaya çevirir, ama yeni kod böyle yazılmaz.
Kaydetme
public static function getInstance(): MioException;
public function initialize(): void;
public function logError(string $message, array $context = [], string $level = Logger::LEVEL_ERROR, string $type = Logger::TYPE_SYSTEM): string;
public function logDatabaseError(string $query, string $error, array $params = []): string;
public function sanitizeData(array $data, int $depth = 0): array; // $depth iç özyineleme; siz geçmezsiniz
public static function showErrors(): void;
public static function getInstance(): Logger;
public function log(string $level, string $message, array $context = [], string $type = self::TYPE_SYSTEM): string;
// Seviye başına bir statik, hepsi aynı biçimde.
public static function debug(string $message, array $context = [], string $type = self::TYPE_SYSTEM): string;
public static function info(string $message, array $context = [], string $type = self::TYPE_SYSTEM): string;
public static function warning(string $message, array $context = [], string $type = self::TYPE_SYSTEM): string;
public static function error(string $message, array $context = [], string $type = self::TYPE_SYSTEM): string;
public static function fatal(string $message, array $context = [], string $type = self::TYPE_SYSTEM): string;
public static function database(string $query, string $error, array $params = []): string;
// Geri çağrımı koşar, fırlattığı her şeyi kaydeder ve yeniden fırlatmak yerine null döner.
public static function safe(callable $callback, array $context = [], string $errorMessage = 'Operation failed');
initialize() ile kurulan bir singleton.
['query' => ..., 'parameters' => ...] biçimindedir.
null. Destek talebi o kimlikle gelir; müşterinin mesajından saklanan bağlama böyle ulaşırsınız.
Seviyeler ve Tipler
İkisi de düz dizedir ve güvenle yazılabilecek tek yazım sabitlerdir. Her kayıt çağrısı kimliği dize olarak döndürür. En az altı karaktere tamamlanmış büyük harfli onaltılık sayı, ardından üç rakam. Yani sabit genişlikte değil, 4F59C9BC644 gibi. Metin olarak saklayın, uzunluğuna göre doğrulama yapmayın.
| Sabit | Değer | Ne için |
|---|---|---|
Logger::LEVEL_DEBUG | DEBUG | Geliştirme izleri; yayına giden bir yolda kullanılmaz. |
Logger::LEVEL_INFO | INFO | Sonradan doğrulanmak istenebilecek bir şey oldu. |
Logger::LEVEL_WARNING | WARNING | Toparlandı, kalitesi düştü, yeniden denendi. |
Logger::LEVEL_ERROR | ERROR | Varsayılan. İşlem kendisinden isteneni yapmadı. |
Logger::LEVEL_FATAL | FATAL | İstek devam edemez. Kapanış işleyicisi yazar. |
Logger::LEVEL_DEPRECATED | DEPRECATED | Motorun kullanımdan kaldırma uyarıları; ayıklanabilsin diye ayrı tutulur. |
Logger::TYPE_SYSTEM | system | Varsayılan tip; sorgu olmayan her şey. |
Logger::TYPE_DATABASE | database | Sorgu hataları. Gürültülü tek bir sorgu diğerlerini gömmesin diye ayrı günlükte tutulur. |
Maskeleme Gerçekte Neyi Yakalar
Küçük harfe çevrilmiş anahtar adı şunlardan birini içeriyorsa değer maskelenir: password, pass, passwd, pwd, secret, token, key, auth, api_key, private_key. Alt dize testidir, iç içe dizilere özyinelemeli uygulanır ve yalnız anahtarlara bakar.
$in = [
'email' => '[email protected]',
'Password' => 's3cr3t', // büyük-küçük harf gözetmeden eşleşir
'api_token' => 'abc123', // "token" içeriyor
'keyword' => 'hosting', // "key" içeriyor - o da maskelenir
'server' => ['auth_user' => 'root', 'port' => 22],
];
$out = MioException::getInstance()->sanitizeData($in);
// [
// 'email' => '[email protected]',
// 'Password' => '***REDACTED***',
// 'api_token' => '***REDACTED***',
// 'keyword' => '***REDACTED***',
// 'server' => ['auth_user' => '***REDACTED***', 'port' => 22],
// ]
Çağıran Ne Görür
| Durum | Yanıt |
|---|---|
| Operation içinde fırlatılan exception | {"status":"error","message":"<mesajınız>"} |
| AJAX isteği sırasında işleyicinin yakaladığı hata | {"status":"error","message":"Error ID: <kimlik>: <metin>","error_id":"<kimlik>"}, teşhisler açıkken ayrıca bir debug alanı |
| Sayfa sırasında ölümcül hata | Hata sayfası; ayrıntı yalnız teşhisler açıkken |
| Ölümcül olmayan uyarı | Kaydedilir; sayfada yalnız teşhisler açıkken görünür |
| Komut satırında her şey | Kaydedilir; mesaj çıktı tamponu tarafından yutulabilir |
Örnek
// Operation'da: fırlatın, cevabı dağıtıcı versin.
public function delete_widget(Operation $operation): bool
{
$operation->demo();
$id = (int) Filter::init("POST/id", "rnumbers");
if (!$id) throw new Exception(Language::gc("widgets/error-id-required"));
if (!$this->model->delete($id)) throw new Exception(Language::gc("widgets/error-delete-failed"));
return $operation->output(['status' => "successful"]);
}
// Modülde: fırlatın. Çağıran yakalar ve mesajı yüzeye çıkarır.
public function create(): array|false
{
$response = $this->api->create($params);
if (!($response['success'] ?? false))
throw new Exception((string) ($response['message'] ?? $this->lang["err-provider"]));
return ['status' => 'SUCCESS'];
}
// Kendiniz ele aldığınız bir şeyi kaydetme. Önce maskeleyin; geri dönen kimlik,
// operatörün okuyacağı mesajda anılacak kimliktir.
$mio = MioException::getInstance();
$id = $mio->logError("Sağlayıcı transferi reddetti", $mio->sanitizeData($_POST), Logger::LEVEL_WARNING);
throw new Exception(Language::gc("services/error-transfer", ['{id}' => $id]));
// Tarayıcı bunun ardından operation dağıtıcısından şunu alır:
// {"status":"error","message":"Transfer başarısız. Referans: 4F59C9BC644"}
//
// Komut satırında geri okumak:
// php coremio/errlog.php list --limit=10
// php coremio/errlog.php show <imza>
Tuzaklar
logError() mesajla, logDatabaseError() sorguyla başlar ve mesajı ikinci sırada alır, Logger::log() ise seviyeyle başlar. Veritabanı çağrısında ilk ikisini yer değiştirmek sessizdir: mesajı bir SQL ifadesi, kayıtlı sorgusu bir hata metni olan bir günlük kaydı elde edersiniz.
İşleyici ölümcül olmayan uyarıları da kaydeder ve her kayıt bir yazımdır. Döngü içinde okunan eksik bir dizi anahtarı bu yüzden adım başına bir yazıma mal olur; değerlerin umutla değil varsayılanla okunmasının sebebi budur.
Günlük, isteği aşan ve etrafta kopyalanan bir dosyadır. Maskeleme anahtar adları üzerinde bir alt dize testidir, yani bir yönde cömert diğer yönde kördür. card ya da answer adlı bir alan hiç dokunulmadan geçer. Ham istek verisini geçip listenin sizin alanınızı kapsadığını varsaymayın.
Ekranda bir şey olmaması, işleyicinin onu göstermemeye karar verdiği anlamına gelir; hiçbir şey olmadığı anlamına değil. Bir kod yoluna hiç ulaşılmadığı sonucuna varmadan önce günlüğü okuyun.
İlgili Makaleler
Geri bildiriminiz için teşekkürler!
Yukarıda bulamadığınız her şey için destek ekibimiz her zaman yanınızda.