NeuroAgent

Property Hooks in PDO fetchObject PHP 8.4

Learn whether property hooks are called when creating objects via PDO fetchObject in PHP 8.4. Analysis of behavior and practical solutions for developers.

Question

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?

NeuroAgent

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

PDO fetchObject creates class instances using standard PHP mechanisms, but with important characteristics:

php
$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 private and protected properties
  • 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:

php
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:

  1. Direct value assignment: PDO uses internal PHP mechanisms to directly assign values to properties, bypassing normal setters

  2. Ignoring user logic: Direct assignment bypasses any user-defined methods, including property hooks

  3. Low-level access: PDO has direct access to PHP’s internal object structures

Example demonstrating the problem:

php
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:

  1. Loss of data validation: Values from the database don’t go through the validation logic of hooks
  2. Type inconsistency: Hooks can convert types, but PDO bypasses this logic
  3. 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

php
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

php
// 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

php
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:

  1. PDO fetchObject does not call property hooks - this is a key limitation of the current implementation
  2. Direct value assignment by PDO bypasses any user-defined property processing logic
  3. 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

  1. PHP: PDOStatement::fetchObject - Manual
  2. PHP: Property Hooks - Manual
  3. Fetching objects with PDO - Treating PHP Delusions
  4. PDO Fetch Modes - Treating PHP Delusions
  5. What’s new in PHP 8.4 | Stitcher.io
  6. PHP 8.4 Property Hooks | Zend
  7. PHP 8.4: How Property Hooks Happened
  8. PHP PDO: Fetching data as objects - Stack Overflow