0

So I've just started coding in classes and I haven't quite got my head around it yet. So I understand the concept of OOP but I have a question.

I have "users" stored in a database, and I want a user class that will get information I might want about a user and do things related to a "user" object. I understand that.

So say I have a user class, with properties username and email I have the following code

<?php
    class User {
        private $username;
        private $email;

        public function __construct($username,$email) {
            $this->username=$username;
            $this->email=$email;
        }
    }
?>

Now I know I should have getters and setters to access username and email. Getters, I understand. But setters - do I need these? And if I do, should these update that field in the database for that user? Would my setter for email update the database as well as the $this->email ? It may seem like a silly question but I want to get this right.

Then finally what is the best way to get users from the database and create objects? Say elsewhere I want to create a user object from ID 50 - which would get user with ID 50 from the database and construct a user object with the database email and username fields, what is the best way to do this?

Thanks!

Tom
  • 1,068
  • 2
  • 25
  • 39
  • I've seen numerous approaches (some creating a UserManager class which performs all the operations that a User needs to do: i.e. login, logout, populate info, etc.), however, you may want to check out [this page](http://net.tutsplus.com/tutorials/php/pdo-vs-mysqli-which-should-you-use/) and look under "Object Mapping". Assuming you're using [PDO](http://php.net/manual/en/book.pdo.php) (or apparently mysqli) to connect to the database, you could use object mapping which makes populating an object so easy (for PDO look into `setFetchMode()`). – Mattiavelli Jul 30 '13 at 12:48
  • Try to read this perfect [book](http://martinfowler.com/books/eaa.html). It has wide explanetion for this and related problems. – Ivan Velichko Jul 30 '13 at 12:54

4 Answers4

2
  • But setters - do I need these?

It depends. If you do not have to do anything more than setting the property, you may not use one. You can ohwever need one if you need to check if the provided value matches, for example, a reg exp, or isn't too long/short, etc. You might also need one if you have setters for other properties and want to keep a uniform interface not to remember which property has or hasn't a setter.

  • And if I do, should these update that field in the database for that user?

If you are to modify several properties, it is better to only access the database a single time. Some database abstraction libraries do it that way :

$user->name = 'whatever';
$suer->email = 'whatever';
$user->save(); // Execute the modify query.

Accessing/modifying data in a database is expensive.

  • Then finally what is the best way to get users from the database and create objects?

If you are using, for example, mysql, you can use :

$users = [ ];

while($row = $result->fetch_assoc()) {
    $user = new User;
    foreach($row as $field => $value) {
       $user->$field = $value;
    }
    $users[] = $user;
}

But there might be more elegant ways to do that though.

Virus721
  • 8,061
  • 12
  • 67
  • 123
  • That's excellent - thanks. With your final point - where would you put this code? Would this be a function within the class, ie createUser, or would it be in your main code? Thanks – Tom Jul 30 '13 at 13:06
  • Hard to say, it's a bit up to you. You should read articles about how to implement the MVC design pattern. – Virus721 Jul 30 '13 at 13:11
2

Setters are used to set object properties values and in most cases this is it. There are many ways of achieving what you want and basically there are books written about that. I personally tend to have a scenario like follows:

1) Set object properties using setters

2) Call a separate function commit()/save()/whatever() that will write all values to the database

As of creating an object from a row, you'd better have separate factory classes (nice question and answer in stackOverflow - What is a Factory Design Pattern in PHP?). The idea of factory classes is that objects are not mutable and merely serve the purpose of data container. I included PDO just for demonstration purposes but of course there are other ways (it just seems good for a simple users table)

class UserFactory
{
    private $db;

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

    public function fromID($id)
    {
        $userObject = new User();
        $q = $this->db->prepare("SELECT * FROM user WHERE u_id = :id");
        $q->bindValue(":id", $id);
        $q->setFetchMode( PDO::FETCH_INTO, $userObject);
        $q->execute();
        $q->fetch(PDO::FETCH_INTO);
        return $userObject;
    }

    public static function fromRow($row)
    {
        $userObject = new User();
        $userObject->setName($row['name']);
        $userObject->setEmail($row['name']);
        return $userObject;
    }
}

And as of collection of objects

class UserCollection
{
    public static function getAllUsers($db)
    {
        $users = array();
        $q = $db->query("SELECT * FROM user");
        while($row = $q->fetch()){
            $users[] = UserFactory::fromRow($row);
        }
        return $users;          
    }
}

The idea behind is to pass the DB connection to the static method that will return an array holding all User objects initialized from the database. getAllUsers method here is static for demontration purposes and of course the same can be achieved by creating a contstructor that takes the database connection variable as an argument

Community
  • 1
  • 1
Vladimir Hraban
  • 3,543
  • 4
  • 26
  • 46
1

Your first decision is whether or not to get the user's properties from the database within the class or to do it from outside the class. Lets say you do it outside the class, then you would not have any argument in the construct and you could have:

$users = array();
while($row = $result->fetch_assoc()) {
    $user = new User();
    for($row as $field => $value) {
       $camelField = strtoupper(substr($field,0,1) . strtolower(substr($field, 1);
       $fieldClass = 'set' . $camelField;
       $user->{$fieldClass}($value);
    }
    $users[] = $user;
}

in your class you would have setters like

public function setName(value) {
    $this-<name = $value;
}
0

There are mainly two approaches on how to persist your objects:

Active Record / Table Gateway

Using this approach, each property in a class is mapped to a certain field on a database table.

Since you're using PHP, you may be already used this pattern if you used Zend_Db or CodeIgniter Active Record.

The problems with this pattern are that it may not be suitable for complex domain where heavy inheritance is in-use and an in-depth mapping is required. also, it usually tightly-couple your classes with a database which may exacerbate testing.

See also: Wikipedia, Fowler

Object-Relational Mapper (ORM)

'ORM' is a much heavier solution and it let you work purely with 'objects' and completely abstracts away the table/database layer.

It also need to be able to handle Objects Inheritance, Composition, Polymorphism and usually provide some functionality for 'Lazy Loading' of referenced objects.

Notable 'ORM's for PHP are (for example): Doctrine and Propel.

See also: Wikipedia

haim770
  • 48,394
  • 7
  • 105
  • 133