PHP中的关联数组结构有问题

时间:2014-09-18 16:45:24

标签: php arrays

不太确定如何表达这个问题,但我在编写的类中遇到了关联数组的结构问题。代码的相关部分如下:

class User {

    public $userData;

    function getUserData() {
        $stmt = $this->conn->prepare('SELECT * FROM user_table WHERE id = :id');
        $stmt->execute(array('id' => $this->ID));
        $row = $stmt->fetchAll();

        foreach($row AS $key => $val) {
            $this->userData[$key] = $val;
        }
        return $this->userData;
    }

我希望能够使用它来设置类属性,以便我可以像这样访问它们:

$this->userData['username'];
例如,

,但这对我不起作用。相反,我必须像这样访问它们才能工作:

$this->userData[0]['username'];

我必须添加数组索引才能访问任何数据,我不想这样做,但我不知道如何解决这个问题。

3 个答案:

答案 0 :(得分:2)

这与PDOStatement::fetchAll()返回行数据的方式有关。

即使您只选择一行,它仍将返回行索引(零),即,如果您这样做

print_r($row);

你会得到这样的东西

Array
(
    [0] => Array
        (
            [username] => Roy
            [0] => Roy
        )
)

请注意,默认情况下,fetchAll()会在数据中返回两次列 - 一次按列名称,一次按列索引

您为变量$row命名的事实可能是绊倒你的一部分 - 在语义上应该是$rows

要解决此问题,您可以选择几个

  1. 直接访问结果中的第一行

    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); // Notice the addtion of the
    foreach($rows[0] AS $key => $val)
    
  2. 使用PDOStatement::fetch()代替

    $row = $stmt->fetch(PDO::FETCH_ASSOC); // Notice the addtion of the
    foreach($row AS $key => $val)
    
  3. 但在这两种情况下,for循环都是不必要的。你可以简单地做

    $this->userData = $stmt->fetch(PDO::FETCH_ASSOC);
    

    最后,我必须质疑为什么User::$userData是公开的,但你也为它写了一个吸气剂(从学术角度讲,它甚至不是吸气剂 - 它是一个吸气剂)

    关于吸气剂的一些注释

    在编写返回某些内容的方法时,人们使用 get 作为选择的动词并不罕见。但是,有一个同样广泛的思想流派,即吸毒者应该仅限于返回班级成员 。在我工作的地方,我们在编码标准中有关于方法命名的这些内容

    • 非属性获取者或设置者的方法应避免使用getset作为前缀
      • 可能获取替代方案:查找,获取,获取,定位,提取,访问
      • 可能的设置替代方案:推送,应用,制作,发布,标记,附加,分配

    这意味着允许开发人员编写只返回类属性的get*()方法,但不鼓励他们这样做。

    所以当我说“fetcher”时,这是一个口语术语,而不是普通软件工程白话的一部分。

    更好的方法

    以下是我们应用了一些separation of concerns严谨性的示例。用户数据的“获取”和“获取”每个都有自己的实现,即他们自己的方法。

    class User
    {
      private $userData = null;
    
      /**
       * Lazy-load-style getter for $userData
       *
       * @return array
       */
      public function getUserData()
      {
        if (null === $this->userData)
        {
          $this->userData = $this->fetchUserData();
        }
        return $this->userData;
      }
    
      /**
       * Fetch the user's data from the database
       *
       * @return array Associative array of user data where the keys
       *               are column names
       */
      private function fetchUserData()
      {
        $stmt = $this->conn->prepare('SELECT * FROM user_table WHERE id = :id');
        $stmt->execute(array('id' => $this->ID));
    
        return $stmt->fetch(PDO::FETCH_ASSOC);
      }
    }
    

    虽然如果User::fetchUserData()返回 FALSE ,我建议在PDO::fetch()添加一次警卫检查。也许像是

    $user = $stmt->fetch(PDO::FETCH_ASSOC);
    if (false === $user)
    {
      throw new Exception("User with id ($this->ID) not found");
    }
    

答案 1 :(得分:1)

问题在于您的$stmt->fetchAll(),在您的查询中,它确实暗示您正在尝试获取单行。您需要将其替换为$stmt->fetch()

答案 2 :(得分:1)

原因是因为在您的示例中,每行的$ key是行索引,因此对于第0行,您的赋值语句为:

$this->userData[0] = $val;

您要做的是使用两个字段的值将值分配给数组(I'猜测):

$this->userData[$val['field1']] = $val['field2'];

或者,

$this->userData['username'] = $val['username'];

然而,真正的问题是,我认为,你试图获得一行并取代一系列结果 - 而无意中迭代行,而不是你认为的字段。< / p>

如果您要查找单个用户记录,则需要使用关联单次提取,而不是fetchAll:

class User {

public $userData;

function getUserData() {
    $stmt = $this->conn->prepare('SELECT * FROM user_table WHERE id = :id');
    $stmt->execute(array('id' => $this->ID));
    $this->userData = $stmt->fetch(PDO::FETCH_ASSOC);

    return $this->userData;
}