【问题标题】:Is there a better way of accessing and storing only required class properties有没有更好的方法来访问和存储只需要的类属性
【发布时间】:2012-11-14 08:08:31
【问题描述】:

如果我想从数据库中获取客户的电子邮件地址,那么下面的方法很糟糕,因为 $row 将为customer 表中的每个字段都包含一个元素:

$result = mysqli_query ('SELECT * FROM customer WHERE custid = 1');
$row = mysqli_fetch_array ($result, MYSQLI_ASSOC);

这被认为更好,因为 $row 将包含电子邮件地址的单个元素,这就是我们所需要的:

$result = mysqli_query ('SELECT email FROM customer WHERE custid = 1');
$row = mysqli_fetch_array ($result, MYSQLI_ASSOC);

我正在尝试将相同的逻辑应用于对象。如果一个“客户”对象有 50 个属性/字段,那么当您只需要访问一个时填充所有 50 个属性是否很常见?

下面是一个客户类和对象的基本示例,如果我们想要做的只是获取客户的电子邮件地址,而不是所有其他详细信息(在此示例中,“客户”对象有 5 个属性,但实际上可能还有更多):

class Customer {

    private $custid;
    private $firstname;
    private $lastname;
    private $email;
    private $dateadded;

    public function getCustomer ($id) {
        $result = mysql_queryi ('SELECT * FROM customer WHERE custid = ' . $id);
        $row = mysqli_fetch_array ($result, MYSQLI_ASSOC);
        foreach ($row as $key => $value) {
            if (isset ($this->$key)) {
                $this->$key = $value;
            }
        }
    }
}

$customer = new Customer ();
$customer->getCustomer (1); // All I wanted is the email address, but now I have everything :-(

【问题讨论】:

    标签: php class object properties mysqli


    【解决方案1】:

    您可以为您的 getCustomer 函数添加第二个参数,该函数接受要查询的字段数组

    public function getCustomer ($id, $fields=array('*')) {
        $fields = implode(',', $fields);
        $result = mysql_queryi("SELECT {$fields} FROM customer WHERE ...");
        // ...
    

    用法

    // get entire customer
    $customer->getCustomer(1);
    
    // just get the email field
    $customer->getCustomer(1, array('email'));
    
    // get full name
    $customer->getCustomer(1, array('firstname', 'lastname'));
    

    奖金:

    我建议您在模型中存储字段的方式略有不同

    class Customer
        private $_data;
    
        public function getCustomer($id, $fields=array('*')) {
            // ...
        }
    
        // PHP magic set method
        // calling $this->foo = 'bar' results in $this->_data['foo'] = 'bar'
        public function __set($key, $value) {
            return $this->_data[$key] = $value;
        }
    
        // PHP magic get method
        // calling $this->foo results in $this->_data['foo']
        public function __get($key) {
            return array_key_exists($key, $this->_data)
                ? $this->_data[$key]
                : null
            ;
        }
    }
    

    这样你就可以摆脱所有静态定义的实例变量;例如,private $custid;private $firstname;private ...

    相反,所有字段都将存储在 $this->_data 私有关联数组中。

    这样做的好处是您甚至不必更改 getCustomer 函数的编写方式。

    Learn more about PHP magic methods

    【讨论】:

      【解决方案2】:

      您可以创建一个获取电子邮件地址的方法:

      public function getCustomerEmail ($id) {
          $result = mysql_queryi ('SELECT email FROM customer WHERE custid = ' . (int)$id);
          $row = mysqli_fetch_array ($result, MYSQLI_ASSOC);
          foreach ($row as $key => $value) {
              if (isset ($this->$key)) {
                  $this->$key = $value;
              }
          }
      }
      

      PS:不要忘记在查询中使用变量之前对其进行清理

      【讨论】:

      • 固体PS,这是一场等待发生的噩梦哈哈
      • 是的——尽管我更愿意将它转换为函数外部的 (int) 而不是内部。但在字符串的情况下,你当然想转义它们。
      【解决方案3】:

      首先...
      您真的应该将用于从实际对象中获取客户对象的逻辑分开......我建议查看存储库/外观模式的示例。

      例如。 CustomerCollectionInstance->getCustomer($id) 返回一个客户实体。

      您的示例非常简单,因此与仅提取电子邮件和所有字段的区别应该是微不足道的。如果您的对象很大,假设一个客户可能有 500 个订单。订单应该被分成自己的对象,当实体对象被组装时,重的对象不应该被加载,而是在它们的位置有代理对象,当访问时查询数据库以获取该数据。



      例如。

      • 您在 CustomerCollection 上调用 getCustomer...

      • CustomerCollection 返回一个加载了基本数据的 CustomerEntity,并且使用 CustomerOrderCollectionProxy 对象设置了 customerOrders。

      • 您调用 CustomerEntity->getOrders() 返回 CustomerOrderCollectionProxy 对象

      • 1234563您需要的日期。



      请参阅代理模式以获取示例。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-02-23
        • 1970-01-01
        • 2013-12-08
        • 1970-01-01
        • 2018-01-30
        • 1970-01-01
        • 2017-02-18
        相关资源
        最近更新 更多