【问题标题】:PDO MySQL on Class functions关于类函数的 PDO MySQL
【发布时间】:2014-05-20 08:37:23
【问题描述】:

我有一个名为 Form 的类。我有一个 add_form() 方法,我调用它来将记录保存到数据库。 add_form() 基本上将记录添加到数据库并返回受影响的行。当我在不使用类或 OOP 方法的情况下使用此功能时,它可以正常工作。但现在我得到错误说 exec() 是一个未定义的函数。变量计数未定义?我使用 exec() 是因为它返回受影响的行,而不是只执行查询的 execute()。

class Forms
{
  private $database;
  private $count;

  public function __construct(PDO $database) 
  {
    $this->database = $database;
  }

  function add_form($lastname, $firstname, $island, $region, $province, $baranggay, $city, $address, $gender, $birthdate)
  {
    $sql  = "INSERT INTO forms (lastname, firstname, island, region, province, baranggay, city, address, gender, birthdate) VALUES (:lastname, :firstname, :island, :region, :province, :baranggay, :city, :address, :gender, :birthdate)";
    $stmt = $this->database->prepare($sql);
    $count->exec(array(
                  ':lastname'=>$lastname,
                  ':firstname'=>$firstname,
                  ':island'=>$island,
                  ':region'=>$region,
                  ':province'=>$province,
                  ':baranggay'=>$baranggay,
                  ':city'=>$city,
                  ':address'=>$address,
                  ':gender'=>$gender,
                  ':birthdate'=>$birthdate
                  ));
    return $count;
   }

}

【问题讨论】:

  • 请在未来:完整包含错误消息 + 告诉我们您尝试自己调试代码的内容...当然还有:RT(F)M...

标签: php mysql oop pdo


【解决方案1】:

有几件事,首先:您需要调用的方法称为PDOStatement::execute,而不是execexec 方法是PDOas the manual clearly shows 的方法。但是,PDO::exec 不是很安全,因为它不使用预准备语句,所以最好使用PDOStatement,然后使用适当的方法。从准备好的语句中获取受影响的行数也很容易......
接下来,您将准备好的语句(PDOStatement 实例)分配给名为 $stmt 的变量,但在 未定义的变量上调用 exec$count

   $stmt = $this->database->prepare($sql);
   $count->exec(array( //<--- should be $stmt->execute(array());
                  ':lastname'=>$lastname,
                  ':firstname'=>$firstname,
                  ':island'=>$island,
                  ':region'=>$region,
                  ':province'=>$province,
                  ':baranggay'=>$baranggay,
                  ':city'=>$city,
                  ':address'=>$address,
                  ':gender'=>$gender,
                  ':birthdate'=>$birthdate
));

然后,要获取受影响的行数,需要调用the rowCount method

return $stmt->rowCount();

将这些问题放在一起,并应用于您的代码,您应该将代码更改为:

$stmt->execute(array());
$count = $stmt->rowCount();
//optional:
$stmt->closeCursor();
return $count;

为了完整起见,这里是使用exec 的不安全版本:

$vals = array(
    'firstname' => 'Joe',
    'lastname'  => 'Goodboy'
);
$count = $pdo->exec(
    'INSERT INTO hackable (firstname, lastname)
    VALUES ("'.$vals['firstname'].'", "'.$vals['lastname'].'")'
);//all is well
//BUT:
$vals = array(
    'firstname' => 'Evil", /*', 
    'lastname'  => '*/ (SELECT CONCAT_WS(",", id, username, password)
        FROM users
        WHERE isAdmin = 1
        LIMIT 1
    )); --'
$count = $pdo->exec(
    'INSERT INTO hackable (firstname, lastname)
    VALUES ("'.$vals['firstname'].'", "'.$vals['lastname'].'")'
);//OUCH!!

后面的输入导致查询:

INSERT INTO hackable (firstname, lastname)
VALUES ("Evil", /*, "*/
    (SELECT CONCAT_WS(",", id, username, password)
     FROM users
     WHERE isAdmin = 1
    )); -- ", "")

这只是表明使用用户输入执行查询只是一个坏主意......

顺便说一下,一些代码审查
请养成始终编写访问修饰符和subscribe to the coding standards most major players subscribe to 的习惯。这意味着方法应该是 camalCased:add_form 应该是 addForm。也帮自己一个忙,添加文档块:

/**
 * Inserts data provided by $bind into forms table
 * @param array $bind
 * @return int
 * @throw PDOException (if PDO::ERRMODE is set to PDO::ERRMODE_EXCEPTION)
 */
public function addForm(array $bind)
{//PUBLIC + camelCased name
    $stmt = $this->database->prepare($queryString);
    $stmt->execute($bind);
    return $stmt->rowCount();
}

但总的来说,这个表单有一个固定的布局,并且需要给定数量的值。在较大的项目中,您最终可能会为此定义一个数据类:

class From extends DataModel
{//where DataModel is an abstract class
    protected $lastname = null;
    protected $firstname = null;
    //all properties hiere
    public function __construct(array $data)
    {//use assoc array in constructor
        foreach ($data as $key => $value)
        {
            $setter = 'set'.ucfirst($key);
            if (method_exists($this, $setter))//define setters for properties!
                $this->{$setter}($value);
        }
    }
    /**
     * method to turn instance into bind array
     * Optionally omit null values for WHERE clauses
     * @param bool $includeNulls = true
     * @return array
     */
    public function toBind ($includeNulls = true)
    {
        $bind = array(
            ':firstname' => $this->firstname,
            ':lastname'  => $this->lastname,
            //do this for all properties
        );
        if ($includeNulls === false)
            return array_filter($bind);//unset null values
        return $bind;
    }
}

如果你想知道为什么我敦促你使用 setter 和 getter,而不是使用魔法 __get__set 调用,check out some of my answers on codereview.stackexchange。我之前已经详细解释过了

【讨论】:

    猜你喜欢
    • 2012-04-12
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    • 2019-09-04
    • 2015-03-21
    • 2010-12-11
    • 1970-01-01
    相关资源
    最近更新 更多