phppdofetch

PHP PDO fetchObject returns duplicated properties, half of them null


I'm trying to learn PHP and MySQL. I've got a database and some retrieval happening, but when I used fetchObject() I get 2 instances returned. First tried:

class Food {
  // Properties
  public $id;
  public $version;
  public $name;
  public $solid;
  public $servingtext;
  public $servingmeasure;
  public $servingamount;

  private function __construct__() {}

  public static function get_with_id ($dbconn,$id, $version) {
      $stmt = $dbconn->prepare('SELECT * FROM Foods WHERE Id = :Id and Version = :Version;');
      $stmt->execute([':Id' => $id, ':Version' => $version]);
      return  $stmt->fetchObject(__CLASS__);
    //   return $answer;
   }

  // Methods
  function set_id($id){
    $this->id = $id;
  }
   etc. with sets and gets

Called with

require "./templates/header.php";

try 
{
    include __DIR__ . '../../connection.php';
    $conobj = new Connection();
    $dbconn = $conobj->get_connection();
} catch (Throwable $t) {
    error_log(__FILE__ . ':' . $t->getMessage());
    echo 'Connection Error ' . $t->getMessage();
}
require "./models/food.php";
$food = Food::get_with_id ($dbconn,2,0);
var_dump($food);

Result:

object(Food)#4 (14) { ["id"]=> NULL ["version"]=> NULL ["name"]=> NULL ["solid"]=> NULL ["servingtext"]=> NULL ["servingmeasure"]=> NULL ["servingamount"]=> NULL ["Id"]=> int(2) ["Version"]=> int(0) ["Name"]=> string(35) "Sanitarium Weet-Bix Blends Hi-Bran+" ["Solid"]=> int(1) ["ServingText"]=> string(28) "1 serving = 40g (2 biscuits)" ["ServingMeasure"]=> string(1) "g" ["ServingAmount"]=> int(40) }

There should be just 7 fields, but the first set are all NULL and then there's the object I'm hoping for.

I tried..

<?php
class Food {
  // Properties
  public $id;
  public $version;
  public $name;
  public $solid;
  public $servingtext;
  public $servingmeasure;
  public $servingamount;

  private function __construct__() {}

  // Methods
  function set_id($id){
    $this->id = $id;
  }

with

<?php
require "./templates/header.php";

try 
{
    include __DIR__ . '../../connection.php';
    $conobj = new Connection();
    $dbconn = $conobj->get_connection();
} catch (Throwable $t) {
    error_log(__FILE__ . ':' . $t->getMessage());
    echo 'Connection Error ' . $t->getMessage();
}
require "./models/food2.php";
$id = 2;
$version = 0;
$stmt = $dbconn->prepare('SELECT * FROM Foods WHERE Id = :Id and Version = :Version;');
$stmt->execute([':Id' => $id, ':Version' => $version]);
$food = $stmt->fetchObject('Food');
var_dump($food);

Same result. Then with the same Food class tried:

<?php
require "./templates/header.php";

try 
{
    include __DIR__ . '../../connection.php';
    $conobj = new Connection();
    $dbconn = $conobj->get_connection();
} catch (Throwable $t) {
    error_log(__FILE__ . ':' . $t->getMessage());
    echo 'Connection Error ' . $t->getMessage();
}
require "./models/food2.php";
$id = 2;
$version = 0;
$food = $dbconn->query('SELECT * FROM Foods WHERE Id = ' . $id . ' AND Version = ' . $version . ';')->fetchObject('Food');
var_dump($food);

Again, the result with 2 entries.

Please can someone help with why I'm getting the NULLs version first. I don't want or need it. Happy to be told it's a newbie error! I have had plenty of success retrieving arrays but would like to go down the OO path.

Thanks, Paul

PHP 8.1.30, MySQL 9.1.0 and NGINX 1.27.2 in a Docker container


Solution

  • fetchObject() generates the class and gives you the first 7 columns of null, as you added them on the class Food, and they default to NULL

    // Your properties, they all get NULL
    public $id;
    public $version;
    public $name;
    public $solid;
    public $servingtext;
    public $servingmeasure;
    public $servingamount;
    

    then the fetchObject() injects more variables: the columns of the result query also turns into class properties and makes it seems like its has duplicated, but we can trace it from the results of the vardump().

    id duplicates with Id

    version duplicates with Version

    name duplicates with Name

    ...

    Make the public properties variables match the column names you get on your query. From id to Id, servingtext to ServingText, etc.

    Or find a way to generate the class without using fetchObject().

    https://www.php.net/manual/en/pdostatement.fetchobject.php