简体   繁体   English

在PHP中遇到关联数组结构的麻烦

[英]Having trouble with associative array structure in PHP

Not quite sure how to phrase this question but I'm having trouble with the structure of an associate array in a class I'm writing. 不太确定如何表达这个问题,但是我在编写的类中遇到了一个关联数组的结构问题。 The relevant parts of the code goes something like this: 代码的相关部分如下所示:

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

I want to be able use this to set class properties so I can access them like so: 我希望能够使用它来设置类属性,以便可以像这样访问它们:

$this->userData['username'];

for example, but this isn't working for me. 例如,但这对我不起作用。 Instead I have to access them like this for it to work: 相反,我必须像这样访问它们才能起作用:

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

I'm having to add the array index on to access any of the data, which I don't want to be doing but I don't know how to fix this. 我必须添加数组索引才能访问任何数据,我不想这样做,但是我不知道如何解决此问题。

This has to do with how PDOStatement::fetchAll() returns row data. 这与PDOStatement :: fetchAll()返回行数据的方式有关。

Even though you're only selecting a single row, it will still be returned with a row index (of zero), ie, if you did this 即使您仅选择一行,它仍将返回行索引(零),即,如果您这样做的话

print_r($row);

You'd get something like this 你会得到这样的东西

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

Note that by default, fetchAll() returns each column twice in the data - once by column name and once by column index 请注意,默认情况下,fetchAll()返回数据中的每一列两次-按列名一次,按列索引一次

The fact that you named your variable $row is probably part of what's tripping you up - semantically that should be $rows . 您为变量$row命名的事实可能是绊倒您的一部分-语义上应该是$rows

To fix this, you have a couple few choices 要解决此问题,您有几种选择

  1. Directly access the first row in the result 直接访问结果的第一行

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

     $row = $stmt->fetch(PDO::FETCH_ASSOC); // Notice the addtion of the foreach($row AS $key => $val) 

But in both cases, the for loop is unnecessary. 但是在两种情况下,都不需要for循环。 You could simply do 你可以做

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

Lastly, I must question why User::$userData is public but you've also written a getter for it (which, academically speaking, isn't even a getter - it's a fetcher) 最后,我必须质疑为什么User::$userData是公开的,但是您也为此写了一个吸气剂(从学术上讲,它甚至不是吸气剂-它是一个访存器)

A few notes on getters 关于吸气剂的一些注意事项

It's not uncommon for people to use get as the verb of choice when writing methods that return something. 人们在编写返回结果的方法时使用get作为选择动词并不罕见。 However, there is an equally broad school of thought that getters should be restricted to returning class members only . 然而,有思想的同样广泛的学校,干将应限于返回类成员。 Where I work, we have these lines in our coding standard regarding the naming of methods 在我工作的地方,我们在编码标准中包含有关方法命名的这些行

  • Methods which are not property getters or setters SHOULD avoid using get and set as a prefix 非属性get器或设置器的方法应避免使用getset作为前缀
    • Possible get alternatives: find, fetch, acquire, locate, pull, access 可能的获取替代方案:查找,获取,获取,定位,提取,访问
    • Possible set alternatives: push, apply, make, post, mark, attach, assign 可能的替代设置 :推送,应用,制作,发布,标记,附加,分配

This means developers are allowed to write get*() methods that don't just return a class property, but they're encouraged not to. 这意味着开发人员可以编写不仅返回类属性的get*()方法,而且鼓励他们不要这样做

So when I say "fetcher", that is a colloquial term, and not really part of the common software engineering vernacular. 因此,当我说“提取程序”时,这是一个口语化的术语,并不是真正的通用软件工程术语的一部分。

A better approach 更好的方法

Here's an example where we've applied some separation of concerns rigor. 这是一个示例,其中我们对关注点进行了严格的分离 The "getting" and "fetching" of the user data each have their own implementation ie, their own method. 用户数据的“获取”和“获取”分别具有自己的实现,即自己的方法。

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

Although I'd suggest adding a guard check to User::fetchUserData() in case PDO::fetch() returns FALSE . 尽管我建议向User::fetchUserData()添加保护检查,以防PDO::fetch()返回FALSE Perhaps something like 也许像

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

The problem is your $stmt->fetchAll() , in your query it does imply that you are trying to get a single row. 问题是您的$stmt->fetchAll() ,在您的查询中确实暗示您正在尝试获取单行。 You need to replace it with $stmt->fetch() 您需要将其替换为$stmt->fetch()

The reason is because in your example the $key to each row is the row index, so your assignment statement is, for row 0: 原因是因为在您的示例中,每行的$ key是行索引,所以对于第0行,您的赋值语句是:

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

What you want to do instead is to assign the values to the array using the value of two fields (I'm guessing): 您要做的是使用两个字段的值将值分配给数组(我猜):

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

Or, 要么,

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

However, the real problem is that, I think, you're trying to get a single row and pulling an array of results instead -- and the inadvertently iterating over rows, instead of what you think are fields. 但是,我认为真正的问题是,您试图获取一行并取而代之以获取结果数组-并在无意中遍历行,而不是您认为的字段。

If you're looking for a single user record, then you need to use associative single fetch, instead of fetchAll: 如果要查找单个用户记录,则需要使用关联的单个访存,而不是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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM