0

I am trying to create a "User" object inside my class "User" based on the properties I have stored inside my database, which I use PDO to connect to.

I've search some pages on Google and found that most people use the fetchObject method for that. Right now, I am trying to use this to create an object of this current class but I keep getting the error:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function User::__construct(), 0 passed and exactly 11 expected in ...

Everyone keeps using this one the web but I can't seem to find their constructors, because they may not have any attributes to receive.

My current code is this:

public static function createUserBySQL($id)
    {
        $stmt = BD::getConnection()->prepare("SELECT * FROM user WHERE username = ?");
        $stmt->execute([$id]);
        $user = $stmt->fetchObject(__CLASS__);
        var_dump($user);
        return $user;
    }

This may be easy to solve but it's my first time doing OOP in PHP with PDO, so I don't know yet all of the tips and tricks to workaround that easily ;)

Thanks,
mikeysantana

QUICK EDIT: All of the attributes from "User" instance are private and I wanted to keep it like that to maintain the code logic.

3
  • 1
    fetchObject() doesn't work by passing the column values to the constructor. It creates the object, initializes all the properties from the columns, and then calls the constructor with no arguments. Commented Mar 9, 2019 at 21:58
  • 1
    This is almost the only thing described in the manual under this entry: php.net/manual/en/pdostatement.fetchobject.php Commented Mar 9, 2019 at 21:59
  • 1
    fetchObject does some magic stuff. It sets the object's attributes directly. The constructor must not await any parameters. Commented Mar 9, 2019 at 22:00

3 Answers 3

2

You need to make the parameters to your constructor optional. The documentation says:

When an object is fetched, its properties are assigned from respective column values, and afterwards its constructor is invoked.

When the constructor is invoked, no arguments are supplied, which is why you're getting that error.

The constructor needs to check whether the arguments were explicitly provided, and only fill in the properties when they are. There are some examples of how to do this in the comments section of the above documentation.

Sign up to request clarification or add additional context in comments.

Comments

1

After some tries, I actually managed to get this working without setting default values in constructors or any workaround. The key is in the PDO::FETCH_PROPS_LATE* and the arguments array at the end.

The solution

$ctor_args = array(1, 'a placeholder')// pass an array of placeholder values.

$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Post", $ctor_args); 

Working example

class Post
{
    private $id;
    private $content;

    function __construct($id, $content){
        $this->id = $id;
        $this->content = $content;
    }

    public function getId(){
        return $this->id;
    }
}
$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Post", [0,0]); 

print_r($result[0]->getId());
// 1

print_r($result);

// Array
// (
//     [0] => Post Object
//         (
//             [id:Post:private] => 1
//             [content:Post:private] => value from the db
//         )

//     [1] => Post Object
//         (
//             [id:Post:private] => 2
//             [content:Post:private] => it is working!
//         )
// )

Warning:

*When PDO::FETCH_PROPS_LATE is used with PDO::FETCH_CLASS, the constructor of the class is called before the properties are assigned from the respective column values.

So keep in mind the constructor will be called with the placeholder values, not the data from the database, so this solution is (absolutely) not recommended if you manipulate the input values right away inside the constructor. But works fine for just initializing the Class properties.

The problem with it

class Count{
        private $number5;

        function __construct($number)
            {
                $this->number5 = $number;

                print_r(10 / $this->number5); // should be 10/5, so print 2
            }
        }        
$result = $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, "Count", [0]); 

// Warning: Division by zero in C:\xampp\htdocs\app\Model\Post.php on line 15 INF
// Warning: Division by zero in C:\xampp\htdocs\app\Model\Post.php on line 15 INF

Yes, it calls the constructor twice.

7 Comments

Man, if it's what I think it is, it's a breakthrough. Hope you aren't mistaken. Going to check
ah, i see. you just supplied fake constructor parameters. smart, but not really what I thought it is.
Well, it is working, and is the simpler then using functions as wrappers or add logic checking nulls.
so you just could have make it an inline array, "Post", [0,0]); dunno why bother with a distinct variable
I see, if you have some logic inside the constructor it will execute with the fake values.
|
0

Thanks everyone for your help.

To help future readers of this question, here is my solution:

I have kept the method "createUserBySQL" above as it is, I've only changed my constructor.

The constructor now has all of it's attributes in the signature optional, like this:

function __construct($name = null, $surname = null ...)

Inside the constructor I did a validation to see if all arguments were null. Since I had 11 of them, doing an if statement for all would be quite annoying, so I've used the method func_get_args() that returns an array with all arguments passed to the constructor.

The final constructor would look something like this:

function __construct($firstname = null, $surname = null, ...)
    {
        if (func_get_args() != null){
            $this->firstname = $firstname;
            $this->surname = $surname;
            ...
        }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.