As Movahhedi suggested you could use PDO::FETCH_FUNC, but the json_decode() should take place in the passed function, not in the constructor. My suggestion would be to create a UserFactory class with a method like createFromDbRow(), although just defining it as a bare function would work just as well too, of course:
class User {
public string $first_name;
public string $last_name;
public object $contact;
}
class UserFactory {
public function createFromDbRow(string $first_name, string $last_name, string $contact) : User {
$user = new User();
$user->first_name = $first_name;
$user->last_name = $last_name;
$user->contact = json_decode( $contact );
return $user;
}
}
$db = new PDO('sqlite::memory:');
$db->exec('CREATE TABLE "users" ( "id" INTEGER, "first_name" TEXT, "last_name" TExT, "contact" TEXT )');
$db->exec('INSERT INTO "users" VALUES( 1, \'John\', \'Doe\', \'{"email":"johndoe@example.com"}\')');
$db->exec('INSERT INTO "users" VALUES( 2, \'Jane\', \'Doe\', \'{"email":"janedoe@example.com"}\')');
$userFactory = new UserFactory();
$stmt = $db->prepare("SELECT first_name, last_name, contact FROM users");
$stmt->execute();
$users = $stmt->fetchAll(PDO::FETCH_FUNC, [$userFactory, 'createFromDbRow' ]);
var_dump( $users );
Since the User properties are all public I left out a constructor, but you could of course define a constructor as well:
class User {
public string $first_name;
public string $last_name;
public object $contact;
public function __construct(string $first_name, string $last_name, object $contact) {
$this->first_name = $first_name;
$this->last_name = $last_name;
$this->contact = $contact;
}
}
...and then create the Users in UserFactory::createFromDbRow() by utilizing the constructor:
class UserFactory {
public function createFromDbRow(string $first_name, string $last_name, string $contact) : User {
return new User(
$first_name,
$last_name,
json_decode( $contact )
);
}
}