Skip to content

PHP 8.3: Use exceptions by default in SQLite3 extension #1994

@afilina

Description

@afilina

Related to #1589

Analysis

This RFC spans PHP 8.3, 9.0 and 10.0. The analysis focuses on the 8.3 changes only.

  • New class SQLite3Exception in the global namespace.
  • Throw SQLite3Exception instead of Exception. Since the new class is a subclass of Exception, no behavior difference will be observable.
  • Error code moved to the end of the error message string.
  • Calling SQLite3::enableExceptions(false) will trigger an E_DEPRECATED warning.
$db = new SQLite3(':memory:');
$db->enableExceptions(true); // No behavior change unless we enable exceptions
$db->exec('SELECT * FROM non_existent_table'); // Since PHP 8.3, throws SQLite3Exception instead of Exception

https://3v4l.org/NtkgB

$db = new SQLite3(':memory:');
$db->enableExceptions(false); // Explicitly calling it with `false` is deprecated since PHP 8.3

https://3v4l.org/KObOp

$db = new SQLite3(':memory:');
$result = $db->query("SELECT * FROM non_existent_table"); // Since PHP 8.3, when enableExceptions is not set, the warning no longer included the error code in the message string.

// In PHP 8.2: Unable to prepare statement: _1,_ no such table: non_existent_table
// In PHP 8.3: Unable to prepare statement: no such table: non_existent_table

https://3v4l.org/TTclW

Top 2000 Packages

It was impractical to analyze these changes because the behavior relies on use of enableExceptions. I did a basic search to at least see how frequently SQLite3 is used:

  • 4 x \SQLite3
  • 4 x use SQLite3
  • 6 x new SQLite3 (in global namespace)

Detection in PHP 8.2

  • Use of SQLite3Exception: ❌ Not yet available
  • Re-declare SQLite3Exception: ✅ Valid
  • Call to SQLite3::enableExceptions(false) ✅ Valid
  • Call to SQLite3::enableExceptions(true) ✅ Valid

Detection in PHP 8.3

  • Use of SQLite3Exception: ✅ Valid
  • Re-declare SQLite3Exception: ❌ Reserved classname
  • Call to SQLite3::enableExceptions(false) ⚠️ Deprecated, warning
  • Call to SQLite3::enableExceptions(true) ✅ Valid, no observable behavior change

Syntax Variations

Not sure if any of the utilities can easily check whether a token is a class reference. That would simplify the syntax variations we need to explicitly sniff for when checking for a method call on a specific class.

Detectability

Very limited ability to detect overall due to these changes affecting instance methods.

  • Use of SQLite3Exception: ✅ Detectable in most cases.
  • Distinguish namespaced vs global class: ✅ Detectable in most cases.
  • (new SQLite3(':memory:'))->enableExceptions(false): ⚠️ Limited ability if either instance or argument are variable.
  • Warning string message differences: ❌ Since we can't know whether exceptions are enabled in another file, we're subject to false positives.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions