Debugowanie to proces znajdowania i naprawiania błędów w kodzie. To umiejętność, która odróżnia początkującego od doświadczonego programisty.
Rodzaje błędów w PHP
1. Parse Errors (Błędy składni)
Błędy w składni kodu – PHP nie może nawet uruchomić skryptu.
<?php
// Błąd: brak średnika
echo "Hello World"
// Błąd: brak zamykającego nawiasu
if ($x > 5 {
echo "OK";
}
// Błąd: brak zamykającego cudzysłowu
echo "Hello;
?>
Komunikat błędu:
Parse error: syntax error, unexpected end of file in script.php on line 3
2. Fatal Errors (Błędy krytyczne)
Błędy krytyczne przerywające wykonanie skryptu.
<?php
// Wywołanie nieistniejącej funkcji
nieistniejacaFunkcja();
// Przekroczenie limitu pamięci
$huge_array = array_fill(0, 10000000, 'data');
// Błąd require/include
require 'nieistniejacy_plik.php';
?>
Komunikat błędu:
Fatal error: Uncaught Error: Call to undefined function nieistniejacaFunkcja()
3. Warning (Ostrzeżenia)
Ostrzeżenia nie przerywają wykonania skryptu, ale wskazują na problemy.
<?php
// Otwarcie nieistniejącego pliku
$file = fopen('nieistniejacy.txt', 'r');
// Dzielenie przez zero
$result = 10 / 0;
// Użycie niezdefiniowanej zmiennej
echo $niezdefiniowana;
?>
Komunikat błędu:
Warning: fopen(nieistniejacy.txt): failed to open stream: No such file or directory
Warning: Division by zero
4. Notice (Notki)
Najmniej poważne komunikaty – sugestie ulepszeń.
<?php
// Użycie niezdefiniowanego klucza tablicy
$tab = ['a' => 1];
echo $tab['b'];
// Użycie niezdefiniowanej zmiennej
echo $x;
// Użycie niezdefiniowanej stałej
echo NIEISTNIEJACA_STALA;
?>
Komunikat błędu:
Notice: Undefined index: b
Notice: Undefined variable: x
Notice: Use of undefined constant NIEISTNIEJACA_STALA
5. Deprecated (Przestarzałe)
Informacje o przestarzałych funkcjach.
<?php
// Przestarzała funkcja
mysql_connect('localhost', 'root', ''); // Deprecated w PHP 5.5, usunięte w PHP 7.0
// Przestarzały sposób tworzenia obiektu
$date = new DateTime;
$date->setDate(2024, 13, 32); // Deprecated warning
?>
1. error_reporting() – Poziomy błędów
Konfiguracja raportowania błędów
<?php
// Wyświetl WSZYSTKIE błędy (rozwój)
error_reporting(E_ALL);
// Wyświetl wszystkie oprócz Notice
error_reporting(E_ALL & ~E_NOTICE);
// Wyświetl tylko błędy krytyczne
error_reporting(E_ERROR | E_WARNING | E_PARSE);
// Wyłącz wyświetlanie błędów (produkcja)
error_reporting(0);
// Sprawdź aktualny poziom
echo error_reporting(); // Zwraca liczbę (np. 32767 dla E_ALL)
?>
Poziomy błędów – kompletna lista
<?php
// Błędy krytyczne
E_ERROR // Błędy krytyczne (fatal errors)
E_PARSE // Błędy składni
E_CORE_ERROR // Błędy w jądrze PHP
E_COMPILE_ERROR // Błędy kompilacji
// Ostrzeżenia
E_WARNING // Ostrzeżenia runtime
E_CORE_WARNING // Ostrzeżenia jądra PHP
E_COMPILE_WARNING // Ostrzeżenia kompilacji
E_USER_WARNING // Własne ostrzeżenia (trigger_error)
// Notki i informacje
E_NOTICE // Notki runtime
E_USER_NOTICE // Własne notki
E_STRICT // Sugestie najlepszych praktyk
E_DEPRECATED // Przestarzałe funkcje
E_USER_DEPRECATED // Własne deprecation
// Wszystkie
E_ALL // Wszystkie błędy i ostrzeżenia
?>
Przykład – Różne konfiguracje dla środowisk
<?php
// config.php
// Wykryj środowisko
$environment = getenv('APP_ENV') ?: 'development';
if ($environment === 'development') {
// ROZWÓJ - pokaż wszystkie błędy
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
} elseif ($environment === 'staging') {
// STAGING - pokaż błędy, ale loguj je
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php/staging_errors.log');
} else {
// PRODUKCJA - ukryj błędy, tylko loguj
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', '/var/log/php/production_errors.log');
}
?>
2. ini_set() – Konfiguracja PHP w runtime
Podstawowe ustawienia
<?php
// Wyświetlanie błędów
ini_set('display_errors', 1); // Wyświetl błędy (0 = wyłącz)
ini_set('display_startup_errors', 1); // Błędy przy starcie PHP
// Logowanie błędów
ini_set('log_errors', 1); // Loguj błędy do pliku
ini_set('error_log', 'errors.log'); // Ścieżka do pliku logów
// Limity
ini_set('memory_limit', '256M'); // Limit pamięci
ini_set('max_execution_time', 60); // Czas wykonania (sekundy)
ini_set('upload_max_filesize', '10M'); // Max rozmiar uploadu
// Inne
ini_set('default_charset', 'UTF-8');
ini_set('date.timezone', 'Europe/Warsaw');
// Sprawdź wartość ustawienia
echo ini_get('memory_limit'); // 256M
?>
Przykład – Kompleksowa konfiguracja rozwojowa
<?php
// dev_config.php - Konfiguracja dla rozwoju
// Błędy
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// Logowanie
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/logs/php_errors.log');
// Limity (luźne dla rozwoju)
ini_set('memory_limit', '512M');
ini_set('max_execution_time', 300);
ini_set('max_input_time', 300);
ini_set('post_max_size', '50M');
ini_set('upload_max_filesize', '50M');
// Sesje
ini_set('session.cookie_httponly', 1);
ini_set('session.use_strict_mode', 1);
// Output buffering (przydatne przy debugowaniu)
ini_set('output_buffering', 'Off');
ini_set('implicit_flush', 1);
// Pokaż szczegóły SQL (tylko dla developmentu!)
ini_set('mysqli.allow_local_infile', 1);
echo "Konfiguracja deweloperska załadowana<br>";
echo "Memory limit: " . ini_get('memory_limit') . "<br>";
echo "Max execution time: " . ini_get('max_execution_time') . "s<br>";
?>
3. trigger_error() – Własne błędy
Wywoływanie własnych błędów
<?php
function divide($a, $b) {
if ($b == 0) {
// Wywołaj własny błąd
trigger_error("Dzielenie przez zero!", E_USER_WARNING);
return false;
}
return $a / $b;
}
$result = divide(10, 0);
// Bardziej szczegółowe błędy
function processUser($user_id) {
if (!is_int($user_id)) {
trigger_error("User ID musi być liczbą całkowitą, podano: " . gettype($user_id), E_USER_ERROR);
}
if ($user_id < 1) {
trigger_error("User ID musi być dodatni, podano: $user_id", E_USER_WARNING);
return false;
}
// Przestarzałe użycie
if (func_num_args() > 1) {
trigger_error("Funkcja processUser() przyjmuje tylko jeden argument. Wiele argumentów jest przestarzałe.", E_USER_DEPRECATED);
}
return "Processing user $user_id";
}
processUser(-5); // Warning
processUser("abc"); // Fatal Error
processUser(1, 2); // Deprecated
?>
Przykład – Walidacja z trigger_error()
<?php
class Validator {
public static function validateEmail($email) {
if (empty($email)) {
trigger_error("Email nie może być pusty", E_USER_NOTICE);
return false;
}
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
trigger_error("Nieprawidłowy format email: $email", E_USER_WARNING);
return false;
}
return true;
}
public static function validateAge($age) {
if (!is_numeric($age)) {
trigger_error("Wiek musi być liczbą, podano: " . gettype($age), E_USER_ERROR);
}
if ($age < 0) {
trigger_error("Wiek nie może być ujemny: $age", E_USER_WARNING);
return false;
}
if ($age > 150) {
trigger_error("Nieprawdopodobny wiek: $age", E_USER_WARNING);
return false;
}
return true;
}
}
// Testy
Validator::validateEmail(''); // Notice
Validator::validateEmail('invalid-email'); // Warning
Validator::validateAge('abc'); // Fatal Error
Validator::validateAge(-5); // Warning
Validator::validateAge(200); // Warning
?>
4. error_log() – Logowanie błędów
Podstawowe użycie
<?php
// Loguj do domyślnego pliku error_log
error_log("To jest testowa wiadomość w logu");
// Loguj zmienną
$user_id = 123;
error_log("User ID: $user_id");
// Loguj tablicę (trzeba skonwertować do stringa)
$data = ['name' => 'Jan', 'age' => 25];
error_log("User data: " . print_r($data, true));
// Loguj z kontekstem
error_log("[" . date('Y-m-d H:i:s') . "] User logged in: $user_id");
?>
Logowanie do konkretnego pliku
<?php
// Loguj do konkretnego pliku
error_log("Custom log message", 3, "/var/log/myapp/custom.log");
// Funkcja pomocnicza do logowania
function logMessage($message, $level = 'INFO') {
$timestamp = date('Y-m-d H:i:s');
$log_file = __DIR__ . '/logs/app.log';
$formatted_message = "[$timestamp] [$level] $message" . PHP_EOL;
error_log($formatted_message, 3, $log_file);
}
// Użycie
logMessage("Aplikacja uruchomiona", "INFO");
logMessage("Użytkownik zalogowany: ID 123", "INFO");
logMessage("Błąd połączenia z bazą", "ERROR");
logMessage("Podejrzana aktywność z IP: 192.168.1.100", "WARNING");
?>
Przykład – Klasa Logger
<?php
class Logger {
private $log_file;
private $levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'];
public function __construct($log_file = null) {
$this->log_file = $log_file ?? __DIR__ . '/logs/app.log';
// Utwórz katalog jeśli nie istnieje
$log_dir = dirname($this->log_file);
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
}
private function write($level, $message, $context = []) {
$timestamp = date('Y-m-d H:i:s');
// Format: [2024-01-15 14:30:45] [ERROR] Message
$log_line = "[$timestamp] [$level] $message";
// Dodaj kontekst jeśli istnieje
if (!empty($context)) {
$log_line .= " | Context: " . json_encode($context);
}
$log_line .= PHP_EOL;
// Zapisz do pliku
error_log($log_line, 3, $this->log_file);
}
public function debug($message, $context = []) {
$this->write('DEBUG', $message, $context);
}
public function info($message, $context = []) {
$this->write('INFO', $message, $context);
}
public function warning($message, $context = []) {
$this->write('WARNING', $message, $context);
}
public function error($message, $context = []) {
$this->write('ERROR', $message, $context);
}
public function critical($message, $context = []) {
$this->write('CRITICAL', $message, $context);
}
public function exception(Exception $e) {
$context = [
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString()
];
$this->error($e->getMessage(), $context);
}
}
// Użycie
$logger = new Logger();
$logger->info("Aplikacja uruchomiona");
$logger->debug("Zmienna \$x = 5", ['x' => 5]);
$logger->warning("Niska pamięć", ['available' => '50MB']);
$logger->error("Błąd połączenia z bazą", ['host' => 'localhost', 'error' => 'timeout']);
try {
throw new Exception("Testowy wyjątek");
} catch (Exception $e) {
$logger->exception($e);
}
?>
5. var_dump(), print_r(), debug_backtrace()
var_dump() – Pełne informacje o zmiennej
<?php
$string = "Hello World";
$number = 42;
$float = 3.14;
$bool = true;
$null = null;
$array = ['a' => 1, 'b' => 2, 'c' => 3];
$object = new stdClass();
$object->name = "Test";
$object->value = 100;
// var_dump() pokazuje typ i wartość
var_dump($string); // string(11) "Hello World"
var_dump($number); // int(42)
var_dump($float); // float(3.14)
var_dump($bool); // bool(true)
var_dump($null); // NULL
var_dump($array); // array(3) { ["a"]=> int(1) ...}
var_dump($object); // object(stdClass)#1 (2) { ...}
// Wiele zmiennych naraz
var_dump($string, $number, $array);
?>
print_r() – Czytelniejszy output
<?php
$array = [
'user' => [
'id' => 123,
'name' => 'Jan Kowalski',
'email' => 'jan@example.com',
'roles' => ['admin', 'editor']
],
'settings' => [
'theme' => 'dark',
'language' => 'pl'
]
];
// print_r() - czytelniejsze formatowanie
print_r($array);
// Zwróć jako string zamiast wyświetlać
$output = print_r($array, true);
error_log("Array content: $output");
// Porównanie
echo "<pre>";
echo "var_dump():\n";
var_dump($array);
echo "\nprint_r():\n";
print_r($array);
echo "</pre>";
?>
debug_backtrace() – Śledzenie wywołań
<?php
function levelOne() {
levelTwo();
}
function levelTwo() {
levelThree();
}
function levelThree() {
// Pokaż stos wywołań
$backtrace = debug_backtrace();
echo "<pre>";
print_r($backtrace);
echo "</pre>";
// Bardziej czytelne
echo "<h3>Call Stack:</h3>";
foreach ($backtrace as $index => $call) {
echo "#{$index} ";
if (isset($call['file'])) {
echo "{$call['file']}:{$call['line']} - ";
}
if (isset($call['class'])) {
echo "{$call['class']}{$call['type']}";
}
echo "{$call['function']}()<br>";
}
}
levelOne();
?>
Funkcja debug() – Ulepszony var_dump()
<?php
function debug($var, $label = null, $die = false) {
echo '<pre style="background:#f4f4f4; padding:15px; border:2px solid #333; border-radius:5px; margin:10px 0;">';
if ($label) {
echo "<strong>DEBUG: $label</strong>\n";
echo str_repeat('-', 50) . "\n";
}
// Informacje o wywołaniu
$backtrace = debug_backtrace();
$caller = $backtrace[0];
echo "File: {$caller['file']}\n";
echo "Line: {$caller['line']}\n";
echo str_repeat('-', 50) . "\n\n";
// Typ zmiennej
echo "Type: " . gettype($var) . "\n\n";
// Wartość
if (is_array($var) || is_object($var)) {
print_r($var);
} else {
var_dump($var);
}
echo '</pre>';
if ($die) {
die("\n<strong>Script terminated by debug()</strong>");
}
}
// Użycie
$user = [
'id' => 123,
'name' => 'Jan Kowalski',
'active' => true
];
debug($user, "User Data");
debug($_SERVER, "Server Variables");
debug($user, "Critical Error - User Data", true); // Zatrzyma skrypt
?>
6. Try-Catch – Obsługa wyjątków
Materiał dostępny w temacie https://kamakaczmarek.net/12-php-wyjatki-try-catch/
7. Xdebug – Profesjonalne debugowanie
Xdebug to popularne rozszerzenie (moduł) dla języka PHP, które służy do debugowania (szukania błędów), profilowania oraz analizy wydajności aplikacji.
Zamiast polegać na tradycyjnym, często uciążliwym wypisywaniu wartości zmiennych w oknie przeglądarki za pomocą funkcji var_dump() czy print_r(),
Xdebug pozwala na zaawansowaną, interaktywną pracę z kodem.
W tym miejscu odsyłam Was do zewnętrznych źródeł celem zgłębienia tematu – jest ich mnóstwo w sieci.