🏠 Home / Hub
🐘 PHP Lesson 13 — Exceptions & Error Handling
← Back to PHP Menu | 🏠 Hub
1. try / catch / finally
<?php
// Basic exception handling
function divide(float $a, float $b): float {
if ($b === 0.0) {
throw new InvalidArgumentException("Cannot divide by zero");
}
return $a / $b;
}
try {
echo divide(10, 2); // 5.0
echo divide(10, 0); // throws!
} catch (InvalidArgumentException $e) {
echo "Invalid: " . $e->getMessage(); // getMessage()
} finally {
echo "This ALWAYS runs (cleanup)"; // connection close, etc.
}
// Exception properties
try {
throw new RuntimeException("Something went wrong", 500);
} catch (RuntimeException $e) {
echo $e->getMessage(); // "Something went wrong"
echo $e->getCode(); // 500
echo $e->getFile(); // /path/to/file.php
echo $e->getLine(); // line number
echo $e->getTraceAsString(); // stack trace
}
2. Multiple catch / Exception Hierarchy
<?php
// PHP built-in exception hierarchy
// Throwable
// ├── Error (PHP errors)
// │ ├── TypeError
// │ ├── ArithmeticError
// │ └── ParseError
// └── Exception
// ├── RuntimeException
// ├── LogicException
// │ ├── InvalidArgumentException
// │ ├── BadMethodCallException
// │ └── OutOfRangeException
// └── ...many more
function processUser(int $id): array {
if ($id <= 0) {
throw new InvalidArgumentException("ID must be positive, got: $id");
}
if ($id > 9999) {
throw new RuntimeException("User not found: $id");
}
return ['id' => $id, 'name' => 'Ko Ko'];
}
// Multiple catches — specific first, general last
try {
$user = processUser(-1);
} catch (InvalidArgumentException $e) {
echo "Validation: " . $e->getMessage();
} catch (RuntimeException $e) {
echo "Runtime: " . $e->getMessage();
} catch (Exception $e) {
echo "General: " . $e->getMessage();
} finally {
echo "Done";
}
// Catch multiple types (PHP 8+)
try {
processUser(0);
} catch (InvalidArgumentException | OutOfRangeException $e) {
echo "Input error: " . $e->getMessage();
}
3. Custom Exception Classes
<?php
namespace App\Exceptions;
// Base app exception
class AppException extends \RuntimeException {
public function __construct(
string $message,
private int $statusCode = 500,
?\Throwable $previous = null
) {
parent::__construct($message, $statusCode, $previous);
}
public function getStatusCode(): int { return $this->statusCode; }
public function toArray(): array {
return [
'error' => $this->getMessage(),
'code' => $this->statusCode,
'type' => get_class($this),
];
}
}
class ValidationException extends AppException {
private array $errors = [];
public function __construct(array $errors) {
parent::__construct("Validation failed", 422);
$this->errors = $errors;
}
public function getErrors(): array { return $this->errors; }
public function toArray(): array {
return array_merge(parent::toArray(), ['errors' => $this->errors]);
}
}
class NotFoundException extends AppException {
public function __construct(string $resource, int|string $id) {
parent::__construct("$resource with ID '$id' not found", 404);
}
}
class AuthException extends AppException {
public function __construct(string $message = "Unauthorized") {
parent::__construct($message, 401);
}
}
// Usage
try {
$errors = ['email' => 'Invalid email', 'name' => 'Required'];
throw new ValidationException($errors);
} catch (ValidationException $e) {
print_r($e->toArray());
// ['error' => 'Validation failed', 'code' => 422, 'errors' => [...]]
}
try {
throw new NotFoundException("User", 999);
} catch (NotFoundException $e) {
echo $e->getMessage(); // "User with ID '999' not found"
echo $e->getStatusCode(); // 404
}
4. Exception Chaining & Re-throwing
<?php
function connectToDatabase(): \PDO {
try {
return new \PDO("mysql:host=invalid_host", "user", "pass");
} catch (\PDOException $e) {
// Chain: preserve original exception
throw new \RuntimeException(
"Database connection failed: " . $e->getMessage(),
500,
$e // ← previous exception
);
}
}
try {
connectToDatabase();
} catch (\RuntimeException $e) {
echo $e->getMessage(); // "Database connection failed: ..."
echo $e->getPrevious()?->getMessage(); // original PDOException message
}
// Re-throwing — handle partially, let it bubble
function processRequest(array $data): array {
try {
// do work...
if (empty($data['id'])) throw new \InvalidArgumentException("Missing id");
return ['ok' => true];
} catch (\InvalidArgumentException $e) {
// log it
error_log("Request error: " . $e->getMessage());
throw $e; // re-throw to caller
}
}
5. Global Error Handler
<?php
// Global exception handler — unhandled exceptions ကို catch
set_exception_handler(function(\Throwable $e) {
$statusCode = method_exists($e, 'getStatusCode')
? $e->getStatusCode() : 500;
http_response_code($statusCode);
header('Content-Type: application/json');
echo json_encode([
'error' => $e->getMessage(),
'code' => $statusCode,
'type' => get_class($e),
]);
// log to file
error_log(date('Y-m-d H:i:s') . " [{$e->getCode()}] {$e->getMessage()}\n", 3, 'logs/error.log');
});
// Global error handler
set_error_handler(function(int $errno, string $errstr, string $file, int $line) {
if (!(error_reporting() & $errno)) return false;
throw new \ErrorException($errstr, 0, $errno, $file, $line);
});
// PHP.ini settings (development)
// error_reporting = E_ALL
// display_errors = On
// log_errors = On
// error_log = /path/to/php_error.log
// PHP.ini settings (production)
// display_errors = Off ← never show errors to users!
// log_errors = On
// error_log = /path/to/php_error.log
💡 Production: display_errors=Off ကို မမေ့ပါနဲ့! Error messages မှာ sensitive data ပါနိုင်တယ်
🎉 PHP Complete!
Syntax → Conditions → Loops → Functions → Arrays → Strings → Forms → OOP Classes → Inheritance → Interfaces → Traits → Namespaces → Exceptions
🏠 Hub
🐘 PHP Menu
← PHP 12 |
🏠 Back to Hub
📌 Study Checklist
- အပေါ်က concept ကို တစ်ကြောင်းချင်းဖတ်ပြီး example ကို ကိုယ်တိုင်ပြန်ရေးကြည့်ပါ။
- Code/command ပါတဲ့ lesson ဆိုရင် value/name/path တစ်ခုခု ပြောင်းပြီး result ဘာကွာလဲ စမ်းပါ။
- မမှတ်မိသေးတဲ့ keyword 3 ခုကို notebook ထဲရေးပြီး နောက် lesson မသွားခင် ပြန်ရှင်းကြည့်ပါ။
- ပြီးရင် Home / Hub ကိုပြန်သွားပြီး next lesson ဆက်သင်ပါ။