Is this the right way to write OOP PDO classes?
If a User object represents a single User, you would want one User instance per actual user you are working with in the application. For example, say your user might have friends:

class User {
    private $friends;

    public function addFriend(User $friend) {
        if (!in_array($friend, $this-&gt;friends)) {
            $this-&gt;friends[] = $friend;
        }
    }
}


Now, your User object can hold an array of other User objects, who he's friends with! You can do all sorts of cool stuff with that, like listing mutual friends (since those Users have their $friends array too!), displaying a list of friends on the page, or just figuring out who has more friends.

The User object is commonly known as a Domain object, it's an object which is part of the Domain Logic or Business Logic, i.e. the actual application, the actual purpose of the application, the part that does the actual work.



Review:


Most naming conventions in PHP dictate that $variableNames should be camelCased and not lowercase_underscores, however, stick with that works for you, and don't break existing convention if you're working in a collaborative project.
It's often preferable to separate the part where the User's details are kept and actual computation and processing takes place, and the part which is responsible for fetching and saving the User's details from permanent storage of some sort. 


Consider this:

class User {
    private $id;
    private $name;

    public function __construct($id, $name) {
        $this-&gt;id = $id;
        $this-&gt;name = $name;
    }
}


This User object is different, it doesn't know where the details come from, they are injected from that magical place outside of the object where it doesn't know anything about. This User could have come from a database, he could have come from session, a file, a REST api, or I could have just made it up for testing purposes. 

So how do you get the details from the database? You use the Data Mapper pattern.

class UserMapper {

    public function __construct(PDO $db_connection) {
        $this-&gt;db = $db_connection;
    }

    /** 
      * Fetch user details from the database based on ID.
      * If $user exists, fill it. If not, create a new one.
      */
    public function fetch($id, User $user = null) { ... }
    /**
      * Save $user back into the database
      */
    public function save(User $user) { ... }

    ....
}


You can have more methods like "fetch the N top user with most comments", or "Fetch all the friends of this $user"

The point is, the Mapper is responsible for getting/saving all necessary data from the database or whatever other permanent storage you might need, and fill the actual Domain Object, which is then used by the application to do processing.