Exceptions

KPHP supports most exception-related features, but doesn't support finally keyword.

// Exception is a builtin class that can be extended
function loadUser(int $user_id): User {
  if ($user_id <= 0)
    throw new Exception("Invalid user_id = $user_id");
  /* ... */
}

try {
  $user = loadUser($id);
} catch (Exception $ex) {
  echo $ex->getMessage();
}

Traces are not identical to PHP, but more or less readable.

How exceptions are implemented

Internally, KPHP doesn't translate this code to C++ exceptions for several reasons.
Instead, KPHP builds exception propagation graphs and detects what functions and statements can throw. When an exception is thrown, an internal global variable is set. Potentially throwing statements are wrapped with a macro, that checks this global and returns if true. This approach in fact works faster than C++ exceptions.

If an exception has been thrown inside an async call, it is suppressed and would be re-thrown when waiting for the async result. This is described in coroutines.

To be sure, that a function never throws an exception, use @kphp-should-not-throw annotation above it.

Prefer error codes to exceptions

You are sure, that external code handles an error — otherwise, it would not compile.

A well-known pattern is to return tuple(error, result). An error can be int/string/some class. Typically checked with if(!$error) — you return 0 for int, empty for string, null for an object or nullable type, etc.

/** @return tuple(int, string) [error_code, server_name] */ 
function chooseUploadServer() { /* ... */ }

/** @return tuple(?string, ?User) */
function loadUser() { /* ... */ }

[$err, $user] = loadUser();
if ($err) {
  // handle
  return;
}
$user->id;

Exception inheritance and standard exceptions

Since 2021, you can derive your classes from Exception and throw them as expected, identically to PHP.

Error and Throwable interfaces are also supported, as well as standard SPL classes.

There is a PHPDoc annotation @kphp-throws that implements checked exceptions: KPHP would ensure that a function actually throws the same list as you expect.