Skip to content
Advertisement

PDO json_decode before fetch into class

Is there a way to json parse string before making it a class with PDO? I don’t like using union types.

In the example below contact is of type json in the database.

PDO

$stmt = $DB->prepare("SELECT first_name, last_name, contact FROM users");
$stmt->execute();
$stmt->fetchAll(PDO::FETCH_CLASS, 'User');

User class

<?php
class User {
   public string $first_name;
   public string $last_name;
   public string | object $contact;

   public function __construct() {
     $this->contact = json_decode($this->contact);
   }
}

Advertisement

Answer

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 )
    );
  }
}
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement