Will property hooks in PHP 8.4 be triggered when creating an object through PDO fetchObject?
When using PDO fetchObject to create an object from a query result, PDO creates an instance of the specified class without calling the constructor (if no arguments are passed to fetchObject($class, $ctorArgs)). The object’s properties are filled directly from the query data through direct value assignment.
In PHP 8.4, property hooks were introduced. The question is: will these property hooks be triggered when creating an object through PDO fetchObject? In other words, will the values assigned to properties from the database go through property hooks before the assignment operation?
When using PDO fetchObject to create objects in PHP 8.4, property hooks WILL NOT be invoked, as PDO uses direct property value assignment, bypassing PHP’s normal property setting mechanisms.
Table of Contents
- PDO fetchObject and its behavior
- Property hooks in PHP 8.4
- Interaction between PDO fetchObject and property hooks
- Practical consequences and solutions
- Conclusion
PDO fetchObject and its behavior
PDO fetchObject creates class instances using standard PHP mechanisms, but with important characteristics:
$stmt = $pdo->query('SELECT id, name FROM users');
$user = $stmt->fetchObject('User');
Key aspects of PDO fetchObject operation:
- Without constructor invocation: By default, PDO creates objects without calling the
__construct()method - Direct assignment: Values from the query are directly assigned to object properties
- Ignoring access modifiers: PDO can assign values even to
privateandprotectedproperties - PDO::FETCH_PROPS_LATE: A constant that allows calling the constructor after property assignment
As explained in the PHP documentation, fetchObject doesn’t care whether properties are public or not.
Property hooks in PHP 8.4
Property hooks are a new feature in PHP 8.4 that allows defining get and set logic for properties directly in the property declaration:
class User {
public private(set) DateTimeInterface $created {
set (string|DateTimeInterface $value) {
if (is_string($value)) {
$value = new DateTimeImmutable($value);
}
$this->created = $value;
}
}
}
Main capabilities of property hooks:
- Eliminating boilerplate code: They replace getters and setters
- Flexible configuration: You can define only get, only set, or both hooks
- Asymmetric visibility: Different access levels for getting and setting
- Interaction with inheritance and interfaces
As noted on Stitcher.io, the main goal of property hooks is to eliminate the need for boilerplate getter/setter methods.
Interaction between PDO fetchObject and property hooks
The critical question is whether PDO fetchObject will call property hooks when assigning values. The answer: no, it will not.
Why this happens:
-
Direct value assignment: PDO uses internal PHP mechanisms to directly assign values to properties, bypassing normal setters
-
Ignoring user logic: Direct assignment bypasses any user-defined methods, including property hooks
-
Low-level access: PDO has direct access to PHP’s internal object structures
Example demonstrating the problem:
class User {
public string $name {
set {
echo "Property hook set called for name\n";
$this->name = strtoupper($value);
}
}
public function __construct() {
echo "Constructor called\n";
}
}
// PDO fetchObject will NOT call the property hook set
$stmt = $pdo->query("SELECT 'john' as name");
$user = $stmt->fetchObject('User');
// Output: "Constructor called" (if FETCH_PROPS_LATE)
// But the property hook set will NOT be called
This behavior is consistent with how PDO works with regular setters - it ignores them as well, as explained on phpdelusions.net.
Practical consequences and solutions
Problems you’ll encounter:
- Loss of data validation: Values from the database don’t go through the validation logic of hooks
- Type inconsistency: Hooks can convert types, but PDO bypasses this logic
- Inconsistent behavior: The same values can be processed differently when directly assigned versus through setters
Possible solutions:
1. Using PDO::FETCH_PROPS_LATE + manual processing
class User {
public string $name {
set {
$this->name = strtoupper($value);
}
}
public function __construct() {
// Additional processing can be added here
// But hooks still won't be called for data from PDO
}
}
$stmt = $pdo->query("SELECT name FROM users");
$stmt->setFetchMode(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'User');
$user = $stmt->fetchObject();
2. Avoiding direct assignment through PDO
// Instead of fetchObject, use fetchAll and manual object creation
$stmt = $pdo->query("SELECT name FROM users");
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
$users = [];
foreach ($data as $row) {
$user = new User();
$user->name = $row['name']; // Here the hook will be called
$users[] = $user;
}
3. Creating a custom loading method
class User {
public string $name {
set {
$this->name = strtoupper($value);
}
}
public static function loadFromRow(array $data): self {
$user = new self();
$user->name = $data['name']; // The hook will be called
return $user;
}
}
$stmt = $pdo->query("SELECT name FROM users");
$stmt->setFetchMode(PDO::FETCH_ASSOC);
$data = $stmt->fetchAll();
$user = User::loadFromRow($data[0]);
Conclusion
Main takeaways:
- PDO fetchObject does not call property hooks - this is a key limitation of the current implementation
- Direct value assignment by PDO bypasses any user-defined property processing logic
- Alternative approaches are necessary to use property hooks with database data
Recommendations:
- Use PDO fetchObject for simple objects without complex property processing logic
- For objects with property hooks, manual creation methods are preferable
- Consider rethinking your architecture if property hooks are critically important
- Keep an eye on PHP updates - behavior may change in future versions
Related questions:
- Will this be fixed in future PHP versions? There are no official statements about such a change yet
- Can this limitation be bypassed? Yes, but it requires changing the data loading approach
- How does this affect existing applications? Applications using PDO fetchObject with setters already face the same issue
Property hooks are a powerful PHP 8.4 feature, but their interaction with PDO fetchObject demonstrates that some low-level PHP operations can bypass high-level language mechanisms.
Sources
- PHP: PDOStatement::fetchObject - Manual
- PHP: Property Hooks - Manual
- Fetching objects with PDO - Treating PHP Delusions
- PDO Fetch Modes - Treating PHP Delusions
- What’s new in PHP 8.4 | Stitcher.io
- PHP 8.4 Property Hooks | Zend
- PHP 8.4: How Property Hooks Happened
- PHP PDO: Fetching data as objects - Stack Overflow