Jump to content

Recommended Posts

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

Link to comment
https://forums.phpfreaks.com/topic/188142-oop-instantiate-not-working/
Share on other sites

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.

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

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.

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.