MasterACE14 Posted January 12, 2010 Share Posted January 12, 2010 Hello, I've worked on a user class which I use to grab row/s from my database and put them into an object. However the variables(properties) I declare in the class are the only ones that work, the rest is giving me errors even though I have an instantiate method which should be making it so I don't have to declare every single variable. Here's my class... class User { protected static $table_name="cf_users"; public $id; public $username; public $password; public static function find_by_id($id=0) { $result_array = self::find_by_sql("SELECT * FROM ".self::$table_name." WHERE id={$id} LIMIT 1"); return !empty($result_array) ? array_shift($result_array) : false; } public static function find_by_sql($sql="") { global $database; $result_set = $database->query($sql); $object_array = array(); while ($row = $database->fetch_array($result_set)) { $object_array[] = self::instantiate($row); } return $object_array; } private static function instantiate($record) { // Could check that $record exists and is an array $object = new self; // Simple, long-form approach: // $object->id = $record['id']; // $object->username = $record['username']; // $object->password = $record['password']; // $object->first_name = $record['first_name']; // $object->last_name = $record['last_name']; // More dynamic, short-form approach: foreach($record as $attribute=>$value){ if($object->has_attribute($attribute)) { $object->$attribute = $value; } } return $object; } private function has_attribute($attribute) { // get_object_vars returns an associative array with all attributes // (incl. private ones!) as the keys and their current values as the value $object_vars = get_object_vars($this); // We don't care about the value, we just want to know if the key exists // Will return true or false return array_key_exists($attribute, $object_vars); } } as you can see in my class I declare $id, $username and $password. Now when I do something like the following... $user = User::find_by_id($_SESSION['user_id']); echo $user->username; That echo's out my username fine. But if I try to echo out any other field besides id, username or password... such as 'exp' for example I get the following error... Notice: Undefined property: User::$exp in C:\xampp\xampp\htdocs\conflictingforces\lib\base.php on line 10 I'm not sure where I've gone wrong? any help is appreciated like always Thanks, Ace Quote Link to comment https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/ Share on other sites More sharing options...
KevinM1 Posted January 12, 2010 Share Posted January 12, 2010 You're asking if the OBJECT has an attribute with the same name as one of your db column names. You only declare four non-static attributes. If your object doesn't have one of the attributes you're looking for, it doesn't magically get added to your object. Therefore, you're attempting to access something that doesn't exist. You may want to rethink your design. IMO, a user object shouldn't populate itself. That should be the job of an abstract user factory class, which would create and populate a user object through static methods much like what you already have. That would allow the user class to only be concerned with storing individual user data and manipulating that data. Quote Link to comment https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/#findComment-993320 Share on other sites More sharing options...
MasterACE14 Posted January 12, 2010 Author Share Posted January 12, 2010 IMO, a user object shouldn't populate itself. That should be the job of an abstract user factory class, which would create and populate a user object through static methods much like what you already have. That would allow the user class to only be concerned with storing individual user data and manipulating that data. I've just read through a few different articles and tutorials on 'Class Abstraction' (php.net), 'factory classes' and 'abstract user factory classes' and it really doesn't make much sense to me at all. :S Quote Link to comment https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/#findComment-993344 Share on other sites More sharing options...
MasterACE14 Posted January 12, 2010 Author Share Posted January 12, 2010 with my class, the find_by_sql(); method works. So does that mean that instantiate(); isn't working correctly? Quote Link to comment https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/#findComment-993358 Share on other sites More sharing options...
KevinM1 Posted January 12, 2010 Share Posted January 12, 2010 with my class, the find_by_sql(); method works. So does that mean that instantiate(); isn't working correctly? That's correct. Like I said earlier, you only declare three (I originally said four...miscounted) non-static properties: id, username, and password. Your instantiate method receives a database row as an argument, and iterates over it, checking to see if your object has a property with the same name as the current column name you're at at that point of the loop. If so, it assigns the value that's stored in that db column into the variable. If not, it does nothing. So, since you didn't declare '$exp' in your object, you get an error when you try to access it since it doesn't exist within your object. Factories are ridiculously easy to implement. You can make them entirely abstract, as there often isn't a reason to actually have an instance of one. Instead, you can rely on static methods to handle everything. A quick example: abstract class UserFactory { private static $dbc = /* whatever database object you'll use */; private static $tableName = "cf_users"; public static function findById($id = 0) { $result = self::findBySql("SELECT * FROM " . self::$tableName. " WHERE id = $id LIMIT 1"); return $result; } public static function findBySql($sql = '') { $users = array(); $result = $dbc->query($sql); while($row = $dbc->fetchArray($result)) { $users[] = self::instantiate($row); } return $users; } private static function instantiate($record) { $user = new User($record[0], $record[1], $record[2] /* until all the properties are filled */ ); return $user; } } class User { private $id; //may not be necessary if you only use it in db queries private $userName; private $password; //ditto /* continue declaring all of the property fields a User object should have */ public function __construct($id, $userName, $password /* etc */ ) { $this->id = $id; $this->userName = $userName; $this->password = $password; /* etc */ } } $singleUser = UserFactory::findById(24); $multipleUsers = UserFactory::findBySql("SELECT * FROM cf_users"); Instead of hard coding the database information into the factory, you could have the class obtain that info by reading it from a config file or by accessing an application registry. Quote Link to comment https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/#findComment-993530 Share on other sites More sharing options...
MasterACE14 Posted January 12, 2010 Author Share Posted January 12, 2010 Thanks! it makes sense now, I can see how that's a better way of doing it. Thanks again Quote Link to comment https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/#findComment-993573 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.