Challenge 3 — Solution Task: Create two custom exceptions, FileNotFoundException and PermissionDeniedException, both extending Exception. Write a function openFile($filename, $hasPermission) that throws the first if $filename is an empty string, the second if $hasPermission is false, otherwise echoes "File opened successfully." Use a try block with TWO separate catch blocks (correctly ordered) to handle each case distinctly, with a generic Exception catch as a final fallback. getMessage(); } catch (PermissionDeniedException $e) { echo "Permission denied: " . $e->getMessage(); } catch (Exception $e) { echo "Unexpected error: " . $e->getMessage(); } ?> Output: Permission denied: You do not have permission to open 'secrets.txt'. Notes: - Both custom exception classes extend Exception directly with empty bodies, giving each a distinct, catchable type without needing any additional code beyond the class declaration itself. - The three catch blocks are ordered from most specific to least specific: FileNotFoundException first, PermissionDeniedException second, and the generic Exception last as a catch-all fallback - reversing this order would let the generic Exception catch block intercept both specific exception types before they ever reached their own dedicated blocks. - Since "secrets.txt" is a non-empty filename but $hasPermission is false, openFile() throws PermissionDeniedException specifically - execution skips the first catch block (which only matches FileNotFoundException) and lands in the second one instead.