johnsmith153 Posted November 19, 2010 Share Posted November 19, 2010 class Database { // actual database interaction // also uses mysql_real_escape etc. } class Users extends Database { function checkIfUsernameExists() { } } class addUser extends Users { // perform all add user stuff } class searchUser extends Users { // all search user stuff } So, to add a new user, I would instantiate, then perform various queries to the addUser class, probably also using the checkIfUsernameExists method in the Users class. Finally, Database would add the record. Question: what do I instantiate? Do I instantiate just the addUser one, or first the Database class? I know how to do it, but what about instantiation, using parent:: self:: etc. etc. (how do I link these clasess together is what I think I mean). Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/ Share on other sites More sharing options...
dontpanic Posted November 19, 2010 Share Posted November 19, 2010 If ClassB inherits from ClassA (using the extend keyword), instantiating an object of ClassB automatically instantiates the ClassA-inherited members. You could instantiate an object of CassA, but it would only have the members and methods of ClassA and would have NO knowledge of ClassB (ClassA can't access ClassB's members, inheritance is a one-way street). Here's an example: <?php // test.php class Widget { public $foo = 'hello'; public $bar = 'world'; function widgetize() { echo $this->foo . ' ' . $this->bar . "\n"; } } class WidgetConfabilator extends Widget { function confabilate($new_bar) { $this->bar = $new_bar; } } $myObj = new WidgetConfabilator(); $myObj->widgetize(); $myObj->confabilate("php land"); $myObj->widgetize(); // Reusing same variable--I'm lazy $myObj = new Widget(); $myObj->widgetize(); $myObj->confabilate("php land"); // Error $myObj->widgetize(); // This code never gets executed ?> C:\Scripts>php .\test.php hello world hello php land hello world Fatal error: Call to undefined method Widget::confabilate() in C:\Scripts\test.php on line 31 Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136866 Share on other sites More sharing options...
AbraCadaver Posted November 19, 2010 Share Posted November 19, 2010 I wouldn't expect addUser and searchUser to be classes but methods of User where addUser() would do some stuff and call something like insert() that's inherited from Database and searchUser() would call find(), etc... Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136872 Share on other sites More sharing options...
KevinM1 Posted November 19, 2010 Share Posted November 19, 2010 Your design is all sorts of messed up. You don't need to create a child class every time you want to gain some functionality. Objects can contain other objects. Also, your User activities should be methods as they act on a User. Classes denote things. Methods denote actions on things. Further, does it make sense to have a User be a Database? Roughly, you should have something like: abstract class Database { public static function searchUser($info) { // search for the user and return the User object if it is found } } class User { private $_db; public function __construct(Database $db) { $_db = $db; } public function saveChanges() { // search the $_db to see if $this exists. If so, create a new User and save. Otherwise, update existing User } } Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136877 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 Thanks, and I have taken all this onboard. Listening to bits of the advice, other advice I have been given and my own favoured style, I want to do this: (1) Use the database class like this: http://snipplr.com/view/12697.16543/ (2) But also want to encapsulate most of the code they have used outside of the Database class (in their example) in a Users class. Yes, I would include all searchUser and addUser methods in the Users class (rather than creating theirown classes), this should have been obvious to me (thanks). Would this be ok, and how would I then do it? I think I would instantiate the User class and access the Database from that - but how do you then store the connection variable (in procedural programming I simply do $con = mysql_connect etc. but where do I store the $con variable if I'm not instantiating the class?) An important point is that there could be many classes accessing many different databases and tables so I need to bear this in mind (it's not only the Users class that gets used for db work). I don't think putting the query in the Database class is right bearing this in mind. I may have 20 or so child classes of Database (Users, Product etc...). Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136907 Share on other sites More sharing options...
AbraCadaver Posted November 19, 2010 Share Posted November 19, 2010 Look up the singleton and registry patterns. Either one should work. Inside your User class you would access then like this (probably in the constructor): class User { private $db; function __construct() { // singleton (Database class is singleton and returns a single instance) $this->db = Database::get_instance(); // registry (Database instance is stored in a registry) $this->db = registry::get('db'); } } Or, when you instantiate the User object you can pass in the Database instance: $db = new Database(); $user = new User($db); Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136912 Share on other sites More sharing options...
dontpanic Posted November 19, 2010 Share Posted November 19, 2010 I was working on a reply but AbraCadaver hit all the points I needed to make. Here's the example I had going just for kicks: // Database class from http://snipplr.com/view/12697.16543/ class Database { private $host; private $user; private $pwd; // etc ... } // Your home-brewed User class class User { private $db; private $id; public $name; public function __construct($database, $id) { $this->db = $database; $this->id = $id } public function update_record() { $this->db->query("UPDATE employee_table SET name='$this->name' WHERE id='$this->id'"); } // etc... } // Now using these classes is very simple. Every object of type 'User' will // need to know what database to work on. // Instantiate our employee database $employee_db = new Database(); $employee_db->init('localhost', 'mysql_user', 'mysql_password', 'employee_db_name'); // Instantiate our customer database $customer_db = new Database(); $customer_db->init('localhost', 'mysql_user', 'mysql_password', 'customer_db_name'); // Now on to the users, lets work with an employee-style user $some_employee = new User($employee_db); $some_employee->name = "John Doe"; // Change some data $some_employee->update_record(); // Update database record // And using the second database... $some_customer = new User($customer_db); // etc... Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136914 Share on other sites More sharing options...
AbraCadaver Posted November 19, 2010 Share Posted November 19, 2010 Also, I think you would be much better off using a different database class. That one is not professional in my opinion. Either build one to suit your needs (maybe using PDO) or find another more professionally developed one. Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136920 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 I'm not actually using the exact DB class - was going to write my own. I just understood it better than a lot - and found that it fit with how I wanted to do the inheritance side of things. To ensure when i do write my own that it's better than this, can you give me a few points as to what these are doing wrong. I suppose my Users class is better then declaring the query outside the class for a start (maybe a link to a better one, but it must use this inheritance style ideally). Thanks again to AbraCadaver, dontpanic and Nightslyr for the help - very thorough help and has saved me a lot of time. I was reviewing my learnings on Lynda.com to try and understand this - but am sure it's a little basic even for me! Thanks again. Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136923 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 I'm wrong. Lynda had all this - must have been asleep when that video was on. Actually, Lynda uses a call to User::update_record (no need to instantiate the User class). Only thing is, their code says you can use gloabal inside the class - so then you don't need to pass the instantiated Database variable to User::update_record() - but I can't get this to work. Can you use global inside a class? Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136940 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 You can use global inside a class, but must be inside the method, not just inside the class Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136942 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 class Database { protected $myDbase = "This is the database info"; } class User extends Database { public static function searchUsers($db) { return $db->myDbase; } } $db1 = new Database(); echo User::searchUsers($db1); Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136944 Share on other sites More sharing options...
dontpanic Posted November 19, 2010 Share Posted November 19, 2010 The global keyword is pretty tricky. You cannot have global member variables (it doesn't make sense, really), but you can use global variables within functions: class Foo { public function do_something() { global $var; echo "In class Foo, var=$var\n"; } } $obj = new Foo(); $var = 'bar'; $obj->do_something(); $var = 'changed'; $obj->do_something(); C:\Scripts>php .\test2.php In class Foo, var=bar In class Foo, var=changed Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136945 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 Now I've gone crazy. How about something like this: It's not finished, I could do with a hand finishing. DatabaseAccess does all the expected stuff you'll see in most Database classes (mysql_real_escape, mysql_connect etc.) DatabaseControl stores details of errors (whilst dealing with say add user request) and also manipulates results (may need to get from another class etc.) ...then we have Users and many othr classes. <?php class DatabaseAccess { protected $myDbase = array("dog", "cat", "rabbit");//based on query below etc will return something, use this as example } class DatabaseControl extends DatabaseAccess { protected = $error_logging; public = $result_set; function go($query, $db) { //this gets from what provided in $query and stores relevant error logging and result set ready for display at the end echo $this->$result_set; } } class User extends DatabaseControl { public static function searchUsers($db) { //stores $error-logging (only really when adding/updating) //also stored the $result_set in class above /////////////////// //commented out as needs adjustment //$returned = $db->myDbase; //$result = $db->fetch_array($returned); //return $result; } } //every time $db1 = new DatabaseAccess(); //per new query requirement $query1 = new DatabaseControl(); $query1 = go("User::searchUsers",$db1); //per new query requirement $query2 = new DatabaseControl(); $query2 = go("Product::findItem",$db1); ?> Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136948 Share on other sites More sharing options...
KevinM1 Posted November 19, 2010 Share Posted November 19, 2010 Don't use globals. You shouldn't use globals in procedural code. In OOP, they essentially destroy one of the basic principles of OOP itself. Argument lists exist for a reason. Pass in what you need as function/method parameters. EDIT: You really need to stop and look at what you're doing. You clearly don't understand when/why inheritance is used. What you need to do is compose objects, not simply create a whole long list of parent/children objects. Searching for a User makes sense from the context of a db, not from the context of a User itself. A User object should be returned from the search. Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136951 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 I've actually not used globals for my last example - thought it'd be easier, but actually more work to enter "global $db" into every method anyway. Any idea with the example I last posted? Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136962 Share on other sites More sharing options...
KevinM1 Posted November 19, 2010 Share Posted November 19, 2010 I've actually not used globals for my last example - thought it'd be easier, but actually more work to enter "global $db" into every method anyway. Any idea with the example I last posted? See my edit. Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136967 Share on other sites More sharing options...
dontpanic Posted November 19, 2010 Share Posted November 19, 2010 class User extends DatabaseControl You are missing a fundamental concept of object orientation (OO). Unlike procedural programming, OO is all about separating your data into small, logical groups called classes. The way your rolling all of your database functionality into your User objects tells us that you are thinking of objects incorrectly. Don't inherit Database with your User class, simply pass an object of type Database into your User constructor like our example code has shown. From inside the User class you can use that previously created database object to manipulate your database while ensuring only one connection is ever made. Honestly you should start with with exactly two classes, and expand to many classes with inheritance later on. Use a single Database class to encapsulate all database functionality, and a single User class to define a generic user. Have a look at php.net's object orientation tutorial. Its not the best introduction to OO, but I'm certain it will turn on a lot of lights for you. Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136969 Share on other sites More sharing options...
johnsmith153 Posted November 19, 2010 Author Share Posted November 19, 2010 So if I go with the solution posted by dontpanic at 03:34:46. If I ask the question very differently that may help me achieve what I want. When someone submits a form to add a record (say a new user) I then of course have various checks to make (does username exist?, create new password and encrypt it etc.) If there is an error (username requested already taken or password not minimum number of characters) I then want to store details of these errors so I can display them to the user. How would this best be done (which class / how interact etc)? Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136974 Share on other sites More sharing options...
dontpanic Posted November 19, 2010 Share Posted November 19, 2010 Either make another class, called something like "Logger", and pass an object of that type into your User or Database class's constructor and manage a log from there, or you could parse your class's return values and report in the procedural part of your script. for example, $logger = new Logger(); $myObj = new User($logger); $myOtherObj = new User($logger); // Uses the same logger! $myObj->do_something_bad(); // This function fails for whatever reason and reports to $logger or $myObj = new User(); $ret = $myObj->do_something_bad(); if ($ret == false) { echo 'An error occurred.'; } Could be possible solutions, but I'm sure you could think up any number of alternatives. This is one of those things that has lots of solutions, some good and some bad, but it all comes down to preference and context. If your class methods are atomic enough (as in, they do exactly one complete operation), it is very easy to check return values and report in the global scope. If your methods are long-winded it may be neccessary to report warnings or other non-critical sorts of things before you want to return. In that case I would go with a logger object that is either global (easy, not safe) or instanced (difficult, but safe). My first example uses a global logger object. Quote Link to comment https://forums.phpfreaks.com/topic/219221-oop-linking-parentchild-classes-and-if-to-instantiate-or-not/#findComment-1136988 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.