Php 修改的PDO&;lastInsertId()

Php 修改的PDO&;lastInsertId(),php,database,class,pdo,last-insert-id,Php,Database,Class,Pdo,Last Insert Id,这只是一种新的PDO形式,我并不完全理解。我知道类似的问题已经在这个网站上解决了。但是我被这个新的(对我来说是新的)基于类的PDO系统所吸引。它圆滑简洁。我把一切都弄清楚了,所有的动态用户数据都插入到数据库中了。但是,我不知道如何使用这种特殊样式包含lastInsertId()。用户没有输入post-id&我不能使用GET-request,这是我通常获取post-id的方式 在多次尝试失败后,我所拥有的是我所能做的最好的。很明显,它不起作用。如果您对我的代码有任何修改,我们将不胜感激 以下是数据

这只是一种新的PDO形式,我并不完全理解。我知道类似的问题已经在这个网站上解决了。但是我被这个新的(对我来说是新的)基于类的PDO系统所吸引。它圆滑简洁。我把一切都弄清楚了,所有的动态用户数据都插入到数据库中了。但是,我不知道如何使用这种特殊样式包含lastInsertId()。用户没有输入post-id&我不能使用GET-request,这是我通常获取post-id的方式

在多次尝试失败后,我所拥有的是我所能做的最好的。很明显,它不起作用。如果您对我的代码有任何修改,我们将不胜感激

以下是数据库类:

functions.php

class DB{

    private static function connect(){
        $pdo = new PDO('mysql:host=localhost;dbname=poetionpics;charset=utf8', 'root', '');
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $pdo;
    }
    public static function query($query, $params = array()){
        $stmt = self::connect()->prepare($query);
        $stmt->execute($params);

        if(explode(' ', $query)[0] == 'SELECT'){
        $data = $stmt->fetchALL();
        return $data;
        }
    }
    public function lastInsertId(){

        $pdo = new PDO('mysql:host=localhost;dbname=poetionpics;charset=utf8', 'root', '');
    $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

    return $pdo->lastInsertId();
        }


}
这是我的插入代码:

action.php

for($count = 0; $count < count($_POST['hidden_post_title']); $count++){

$post_title = (isset($_POST['hidden_post_title'][$count])) ? strip_tags($_POST['hidden_post_title'][$count]) : NULL;
$post_desc = (isset($_POST['hidden_post_desc'][$count])) ? strip_tags($_POST['hidden_post_desc'][$count]) : NULL;
$newvidurl = (isset($_POST['hidden_vid_url'][$count])) ? strip_tags($_POST['hidden_vid_url'][$count]) : NULL;
$url_1 = (isset($_POST['url1_hidden_id'][$count])) ? strip_tags($_POST['url1_hidden_id'][$count]) : NULL;
$url_2 = (isset($_POST['url2_hidden_id'][$count])) ? strip_tags($_POST['url2_hidden_id'][$count]) : NULL;


DB::query('INSERT INTO cloudbook_posts VALUES (\'\', :post_title,  :post_desc)',
array(':post_title'=>$post_title, ':post_desc'=>$post_desc));

//This is possibly problematic code or wrong location....

$postid = DB::lastInsertId('SELECT id FROM cloudbook_posts WHERE  id=:id',
array(':id'=>$_POST['id']))[0]['id'];

//End problematic code

DB::query('INSERT INTO vid_info VALUES (\'\', :newvidurl, :postid)',
array(':newvidurl'=>$newvidurl, ':postid'=>$postid));

DB::query('INSERT INTO url_1 VALUES (\'\', :url_1, :postid)',
array(':url_1'=>$url_1, ':postid'=>$post_id));
}

echo str_replace(array('hidden_post_title', 'hidden_post_desc',    'url1_hidden_id', 'url2_hidden_id', '{', '}', '"', ',', ':'), '',
htmlspecialchars(json_encode($result), ENT_NOQUOTES));

?>
我想要的是:

vid_info table
id |       newvidurl    | postid
69 |   some user data   | $postid (see action.php for variable value)

这确实是一个有趣的案例

lastInsertId()
问题是设计不当(部分是cargo cult复制粘贴的代码)的直接后果

这种“PDO的新形式”只是一种展示(如此普遍,以至于我甚至写了一篇关于它的文章)。其中一个问题是:

您必须了解,每个PDO实例都会创建到DB服务器的不同连接。因此,永远不要在每个函数中打开和关闭新连接。因为它会大大降低您的PHP速度,并且不允许您使用某些只能在同一连接中使用的DB功能,即事务或获取插入id

因此,现在您可以看出问题来自于在
lastInsertId()
方法中创建了一个新连接这一事实。解决方法是始终保持相同的连接

有两种方法可以解决这个问题:一种是目前更简单的方法,一种是将来更难实现的方法,另一种是更难实现的方法,但这会降低代码的耦合性,更容易维护。在我的另一篇文章中解释了这两个问题,这篇文章介绍了如何创建这样一个“圆滑而简洁的基于类的PDO系统”(但基于在堆栈溢出方面的大量经验和问题)

最合适的解决方案是在静态的东西产生的时候得到它。因此,最好的解决方案是创建一个常规类,然后将其传递给所有代码。在这种情况下,对
$this->dbh
的所有调用都有意义,并指向同一个PDO实例。在这种情况下,您必须将
DB:query()
符号更改为
$DB->query()

然而,本文中的代码使用了不同的扩展PDO的方法。您的方法更好,所以让我们将代码重写为常规类

class DB{

    public function __construct()
    {
        $host = '127.0.0.1';
        $db   = 'poetionpics';
        $user = 'root';
        $pass = '';
        $charset = 'utf8mb4';

        $options = [
            \PDO::ATTR_ERRMODE            => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
            \PDO::ATTR_EMULATE_PREPARES   => false,
        ];
        $dsn = "mysql:host=$host;dbname=$db;charset=$charset";
        try {
             $pdo = new \PDO($dsn, $user, $pass, $options);
        } catch (\PDOException $e) {
             throw new \PDOException($e->getMessage(), (int)$e->getCode());
        }
    }
    public function query($query, $params = array())
    {
        $stmt = $this->pdo->prepare($query);
        $stmt->execute($params);
        return $stmt;
    }
    public function lastInsertId()
    {
        return $this->pdo->lastInsertId();
    }
}
但请记住,由于您不是在扩展PDO,所以必须复制类中的所有PDO方法

如果当时放弃这种圆滑方法的想法让您无法忍受,那么您可以使用静态方法,但是可以为您保留一个PDO实例。在上面链接的文章中,同样有两种解释方法

在拥有适当的DB类之后,我们可以重写您的查询

$db = new DB();

$sql = 'INSERT INTO cloudbook_posts VALUES (null, :post_title,  :post_desc)';
$db->query($sql, ['post_title'=>$post_title, 'post_desc'=>$post_desc]);

$postid = $db->lastInsertId();

$sql = 'INSERT INTO vid_info VALUES (null, :newvidurl, :postid)';
$db->query($sql, ['newvidurl'=>$newvidurl, 'postid'=>$postid]);

[0]['id']
的目的是什么?您使用的是
lastInsertId
,但您不是在插入,而是在尝试选择。您似乎想得太多了。没有理由在sql查询中选择最后一个insert id——php会为您做这件事。您几乎只需要使用
$postid=$db->lastInsertId()或者您已经使用它>代码> $POSITD= PDO::LaSTReDistId()/<代码>这是一个很好的工作,但请考虑阅读我的文章。并且lastInsertId()方法名称是绝对不正确和误导的。至少调用它just insert()Dharman,[0]['id]的目的是从“cloudbook_posts”表中的MySql数据库中选择id字段。我没有显示cloudbook|u posts表b/c,这个问题没有必要,但是,按顺序,posts表是id | post|title | post|desc…..哦,谢谢,YCS!在没有意识到你给了我这个答案的情况下,我在阅读了你的文章后在文章的页面上问了一个问题。请忽略这个问题。这太完美了!!这是我问过的第一个问题,所以我还是习惯了一切。我现在就去批准你的回答,我的朋友。
$db = new DB();

$sql = 'INSERT INTO cloudbook_posts VALUES (null, :post_title,  :post_desc)';
$db->query($sql, ['post_title'=>$post_title, 'post_desc'=>$post_desc]);

$postid = $db->lastInsertId();

$sql = 'INSERT INTO vid_info VALUES (null, :newvidurl, :postid)';
$db->query($sql, ['newvidurl'=>$newvidurl, 'postid'=>$postid]);