Вопрос о расширении объекта PHP - PullRequest
1 голос
/ 28 июня 2009

Итак, у меня есть класс предметов следующим образом:


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();
    } 

    }

У меня вопрос, что будет лучшим способом расширить этот класс структурой данных, как у меня? Я в основном хочу другой класс для предмета в корзине. Таким образом, некоторые дополнительные поля - это количество, идентификатор корзины и т. Д. Или есть лучший способ сделать это без расширения класса?

С другой стороны, скажем, у меня есть другая переменная $ price, которая не хранится непосредственно в базе данных. Так что я делаю это общедоступной переменной, но мне придется создавать вспомогательные методы для доступа к ней, не так ли? Если это так, мой массив $ data - лучшее решение для этого типа предметов?

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 28 июня 2009

Я не уверен на 100%, каким способом вы можете использовать приватную переменную $data, поэтому моя тенденция здесь заключается в том, чтобы использовать немного другой подход.

Вместо того, чтобы группировать все ваши поля данных внутри одной частной переменной объекта, я бы сделал каждое поле самой частной переменной, то есть:

class Item
{
    private $db;
    private $AltItem1;
    private $AltItem2;
...
etc.

Это сразу же решит вашу проблему с наличием общедоступных полей данных, так как вы можете просто объявить такие поля как открытый член. Публичным членам не требуются геттер и сеттер, поэтому вам не придется об этом беспокоиться ... вы можете просто получить к ним доступ через $this->price (внутри) или $item->price (снаружи). Сохраняет некоторый код. И это будет быстрая модификация вашей функции populate() для установки всех ваших новых свойств, поскольку все, что вам нужно будет сделать, это установить $this->$$key вместо $this->data[$key].

Теперь, когда вы используете __set() и __get(), похоже, что вы хотите иметь доступ к приватному члену $data даже вне объекта. Нет причины, по которой вы не можете продолжать это, если каждое поле будет также объявлено как частное. __set() и __get() будут работать точно так же, вам просто потребуется небольшая настройка, например:

public function __get($varname)
{
    if ($this->$varname !== null) return $this->varname;
    error_log("Invalid key '$key'");
    return null;
}

В качестве заключительного бонуса расширение класса становится проще, поскольку вам не нужно повторно объявлять все поля целиком, если вы хотите переопределить свойство $data. Вы просто добавляете новые поля ваших детей в качестве новых частных пользователей.

Так что я не уверен, облегчит ли это вашу жизнь, но я думаю, что это был бы мой подход.

1 голос
/ 28 июня 2009

Если вам нужны подробности, я не могу вам чем-то помочь, но с точки зрения логики:

С чисто объектно-ориентированной точки зрения, я думаю, что это лучше всего решить, создав класс Cart для отслеживания предметов. По сути, это может быть класс-оболочка для списка соответствующего вида (для конкретного языка, и я не очень разбираюсь в PHP = P).

Я не вижу особой причины, чтобы заставить элемент отслеживать корзину, в которой он находится, - в большинстве случаев отслеживание корзины имеет больше смысла. (С точки зрения реального моделирования: отслеживают ли предметы корзину, в которой они могут находиться или не быть?

Я не совсем уверен, что вы спрашиваете во втором вопросе - не могли бы вы уточнить, пожалуйста? Извините, я не могу вам помочь.

David

...