So I have an item class as follows:
class Item
{
private $db;
private $data = array(
'AltItem1' => null,
'AltItem2' => null,
'BaseUOM' => null,
'Category1' => null,
'Category2' => null,
'Category3' => null,
'Category4' => null,
'Iden' => null,
'IsHCS' => null,
'ItemDesc' => null,
'ItemNmbr' => null,
'ItemType' => null,
'MSDS' => null,
'NoteText' => null,
'NonStock' => null,
'PrcLevel' => null,
'TipPrice' => null,
'DTM_UpdType' => null,
'DTM_UpdDateTime' => null,
'DTM_DownloadDateTime' => null,
'DTM_UploadDateTime' => null
);
public function __construct(mysqli $db, $id = null){
$this->db = $db;
if(!empty($id)){
$id = (int)$id;
$this->populate($id);
}
}
public function __get($key)
{
if(array_key_exists($key, $this->data)){
return $this->data[$key];
}
error_log("Invalid key '$key'");
return null;
}
public function __set($key, $value)
{
if(array_key_exists($key, $this->data)){
$this->data[$key] = $value;
return true;
}
return false;
}
public function populate($id)
{
$sql = sprintf(
"SELECT %s FROM ItemMaster WHERE id = ?",
implode(", ", array_keys($this->data))
);
$stmt = $this->db->stmt_init();
$stmt->prepare($sql) or die ("Could not prepare statement:" . $stmt->error);
$stmt->bind_param('i', $id);
$stmt->execute() or die('exec');
$stmt->store_result();
if($stmt->num_rows == 1)
{
$params = array();
foreach($this->data as $key => $val){
$params[] = &$this->data[$key];
}
call_user_func_array(array($stmt, 'bind_result'), $params);
$stmt->fetch();
$return = true;
}
else{
user_error("No rows returned for id '$id'");
$return = false;
}
return $return;
}
public function insert()
{
$params = $this->data;
$values = array();
foreach($params as $param){
$values[] = "?";
}
$sql = sprintf(
"INSERT INTO recurrence (%s) VALUES (%s)",
implode(", ", array_keys($params)),
implode(", ", $values)
);
$stmt = $this->db->stmt_init();
$stmt->prepare($sql) or die ("Could not prepare statement:" . $stmt->error);
$types = str_repeat("s", count($params));
array_unshift($params, $types);
call_user_func_array(array($stmt, "bind_param"), $params);
$stmt->execute();
$stmt->store_result();
$result = $stmt->result_metadata();
}
public function update()
{
$sql = "UPDATE recurrence SET ";
$params = array();
foreach($this->data as $key => $value){
$params[] = "$key = ?";
}
$sql .= implode(", ", $params) . " WHERE id = ?";
$stmt = $this->db->stmt_init();
$stmt->prepare($sql) or die ("Could not prepare statement:" . $stmt->error);
$params = $this->data;
$params[] = $this->data['id'];
$types = str_repeat("s", count($params));
array_unshift($params, $types);
call_user_func_array(array($stmt, "bind_param"), $params);
$stmt->execute();
$stmt->store_result();
$result = $stmt->result_metadata();
}
}
My question is what would be the best way to extend this class with the data structure the way I have it? I basically want another class for an item in a shopping cart. So some extra fields would be quantity, cart id, etc. Or is there a better way to do this without extending the class?
On another note, say I have another variable $price thats not store directly in the database. So I make it a public variable, but I would have to make helper methods to access it wouldn’t I? If that’s the case, is my $data array the best solution of this type of item?
Thanks in advance.
I’m not 100% sure what kind of usage of the private
$datavariable you might be doing, so my tendency here would be to take a slightly different approach.Instead of grouping all your data fields inside a single private variable of the object, I would make each field a private variable itself, ie:
This would immediately solve your problem with having publicly available data fields as well, as you could simply declare such fields as a public member. Public members don’t require a getter and a setter, so you wouldn’t have to worry about that… you could just access them through
$this->price(internally), or$item->price(externally). Saves you some code. And it would be a quick modification of yourpopulate()function to set all your new properties, as all you’d have to do would be to set$this->$$keyinstead of$this->data[$key].Now, with your use of
__set()and__get(), it looks like you want to be able to access the private$datamember even from outside the object. There’s no reason you can’t continue that by having each field declared separately private as well.__set()and__get()will operate exactly the same way, you’d just need a minor adjustment, ie:As a final bonus, extending the class becomes easier, because you don’t have to redeclare all the fields in their entirety if you want to override the
$dataproperty. You simply add the new fields of your children as new private members.So I’m not sure if that makes your life easier, but I think that would be my approach.