6

I am not sure if this is totally the wrong thing to do, so I am looking for a bit of advice.

I have set up a database class with the constructor establishing a PDO connection to a MySQL database.

I've been looking at singletons and global variables, but there always seems to be someone who recommends against either/or.

I'm experimenting with a user class which extends the database class, so I can call upon the PDO functions/methods but maintain separate user class code. Is this a stupid thing to do?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tommyd456
  • 10,443
  • 26
  • 89
  • 163
  • what's your users function? what should they do? –  Oct 19 '11 at 20:32
  • add new users, update user details etc... – tommyd456 Oct 19 '11 at 20:34
  • if you store your user data in database - I think it would be right way to inherit your user class from DB –  Oct 19 '11 at 20:35
  • possible duplicate of [ORM/DAO/DataMapper/ActiveRecord/TableGateway differences?](http://stackoverflow.com/questions/3198419/orm-dao-datamapper-activerecord-tablegateway-differences) - its not an exact fit but basically it contains the terms you want to google, especially ActiveRecord. Whether its a good or bad idea to use that pattern in your application cannot be answered from the information you give. In general, it has a few problems. In practise, it works. – Gordon Oct 19 '11 at 20:56

5 Answers5

4

You should generally pass a connection into your user, so your user class would take a database type object into its constructor and then use that database object to execute queries against the database. That way your data access logic remains separate from your business logic. This is called composition, as opposed to what you're talking about, which is inhertance.

If you really wanted to be technical, it would be best to have a user object with nothing but public variables, and then you would use a 'service' to implement your business logic.

class UserService implements IUserService
{
    private $_db;
    function __construct(IDb $db) {
        $this->_db = db;
    }

    function GetAllUsers() {
        $users = Array();

        $result = $this->_db->Query("select * from user")

        foreach($result as $user) {

            //Would resolve this into your user domain object here
            users[] = $user;
        }
        return users;
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nathan gonzalez
  • 11,817
  • 4
  • 41
  • 57
  • I think that's what I'm doing now but wasn't sure whether it's the best way. I currently create a User object and pass the DB connection details to it. The construct then calls the parent construct and the connection is established - is this what you mean? – tommyd456 Oct 19 '11 at 20:38
  • Sorry - read your post again as I misunderstood. So taking into account what you said what would happen if I then went on to create other classes - if they all connected to a database it wouldn't be ideal would it??? – tommyd456 Oct 19 '11 at 20:47
  • you would pass the same (already constructed) instance of the db object to anyone needing a connection. within a single request of course. – nathan gonzalez Oct 19 '11 at 20:55
  • light code example added. interfaces used for abstraction, but aren't necessary for the concept. – nathan gonzalez Oct 19 '11 at 21:09
  • definitely the way to go. each class should have a separate responsibility, and should be combined using dependency injection if they need to work together. – dqhendricks Oct 19 '11 at 23:34
4

Well, ask yourself if User is a special case of Database. I'm not sure how others perceive it, but I would be kind of offended. I think what you need is to read about the Liskov substitution principle.

As for solving your "people tell me that globals are bad" issue, here are two videos you should watch:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tereško
  • 58,060
  • 25
  • 98
  • 150
  • Two very good links. It's not often I hear/read something online which is as logical and well presented as those vids. Thanks. – James Feb 12 '15 at 12:06
2

The idea behind class extensions in OOP is for child classes to be related to the parent classes. For instance, a school might have a Person class with extension classes of Faculty and Students. Both of the child classes are people, so it makes sense for them to extend the Person class. But a User is not a type of Database, so some people might get upset if you make it an extension.

Personally, I would send the database object as an argument to the User class in the constructor and simply assign that object to a class property. For instance:

class User
{
    protected $db;
    function __construct($username, $password, $db)
    {
        //some code...
        $this->db = $db;
    }
}

Alternatively, though some might yell at you for it, you can use the global keyword to inherit a variable in the global scope for use within your methods. The downside is that you would then have to declare it global in every method that needs it, or you could do:

class User
{
    protected $db;
    function __construct($username, $password)
    {
        global $db;
        //some code...
        $this->db = $db;
    }
}

But in answer to your question, no I don't think you should make User an extension of Database; even though it would do what you need, it isn't a proper OOP practice.

imkingdavid
  • 1,411
  • 13
  • 26
  • Hi thanks for your response - i was a bit worried about globals as lots of people seem to warn against them. I took Nathans approach above and passed a db object into the User constructor. This seems to do the trick! – tommyd456 Oct 19 '11 at 21:26
  • Could I just ask - in your first code example I noticed that you have $username and $password parameters as well as the $db object parameter. Why do you have the $user/$pass ones because surely the connection will already have been established when you created the database object? – tommyd456 Oct 19 '11 at 21:52
  • Sorry for the confusion... $username and $password in the constructor aren't for the database, but rather the username and password of the user in the User object. I was just assuming that you'd instantiate the User object with the username and password of the user for authentication. – imkingdavid Oct 19 '11 at 22:19
  • Oh ok - that leads me to this question then... would you actually have a method in your User class that registers/adds a user to the database because there obviously won't have a username/password to provide to create the User object??? – tommyd456 Oct 21 '11 at 10:29
  • The user class should be able to be instantiated without information from the database. Ideally, the user class would be used for both registered users and the anonymous guest user, in which case it would be populated with default information such as the visiter's IP and such. And then yes, there would be a method to register the user if it is anonymous with the given information, just requiring that they provide a username, password, email, etc. – imkingdavid Oct 21 '11 at 13:26
  • This is because a class is an object, the class properties are meant as properties to describe the object (in this case, username, password, IP, is_logged_in, etc.), and its methods are things that the user can do or that can be done to the user. A user can register, a user can login, a user can be authenticated, etc. – imkingdavid Oct 21 '11 at 13:27
  • Yes I agree - but I have decided (and you may advise against this) to pass the $username/$password to the login method but not the constructor. This seems to make more sense to me – tommyd456 Oct 21 '11 at 13:47
  • That works as well (in fact, that's how I did it in my most recent script). I don't think either way is necessarily right or wrong--in fact, the former may be more difficult in terms of having to wait to create the User object until you have the user/pass info--it really just comes down to a matter of preference and what works best for you. – imkingdavid Oct 21 '11 at 20:09
0

It is pretty simple according to the definition of an object. It is the encapsulation of data and the operation which is performed on that data so if we only consider the theoretical point of view it would leads us in pleasurable environment.

My suggestion would be to create an abstract data access class with the generalized basic crud operations and a simple query execution using either PDO, ADO or some other database abstraction library. Now use this class as a parent for most of your model classes like the User.

Now the basic CRUD is provided by the abstract data access class and you can write the behavior specific to the user object like getting all posts for the user by consuming the simple query interface of the abstract parent class.

This approach will bring more modularity in term of coupling functionality and more readability and reuse-ability.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abdullah
  • 762
  • 5
  • 14
-5

I don't see anything wrong with it for specific cases. You could use it for something as simple as wrapping a user's DB credentials in an object so they don't have to specify them everywhere the DB object is used.

$db = new UserDB();

would be a bit nicer than

$db = new StandarDB($username, $password, $default_db);
Marc B
  • 356,200
  • 43
  • 426
  • 500