在我们的位置上,我们在使用mysqli和PDO进行预备语句和事务支持之类的工作之间有所分歧。有些项目使用其中一个,另一些使用。我们几乎不可能迁移到另一个RDBMS。

我更喜欢PDO,其唯一原因是它允许为准备好的语句使用命名参数,而据我所知mysqli不允许。 />
在我们将项目合并为仅使用一种方法时,是否有其他选择作为标准的利弊?

评论

本文将有助于选择要使用的一个。如果您考虑性能,这可能会帮助您选择。

#1 楼

好吧,您可以与面向对象方面,准备好的语句,它成为标准的事实等进行争论。但是我知道,在大多数情况下,说服某人使用杀手级功能可以更好地工作。这样就可以了:

使用PDO的真正好处是您可以获取数据,并将其自动注入到对象中。如果您不想使用ORM(因为这只是一个快速的脚本),但是您确实喜欢对象映射,那么它真的很酷:

class Student {

    public $id;
    public $first_name;
    public $last_name

    public function getFullName() {
        return $this->first_name.' '.$this->last_name
    }
}

try 
{
    $dbh = new PDO("mysql:host=$hostname;dbname=school", $username, $password)

    $stmt = $dbh->query("SELECT * FROM students");

    /* MAGIC HAPPENS HERE */

    $stmt->setFetchMode(PDO::FETCH_INTO, new Student);


    foreach($stmt as $student)
    {
        echo $student->getFullName().'<br />';
    } 

    $dbh = null;
}
catch(PDOException $e)
{
    echo $e->getMessage();
}


评论


上面的和$ mysqliResult-> fetch_object(“ student”)之间有什么区别; ?

–安迪·弗莱明(Andy Fleming)
2011年4月15日在7:18

@ e-satis不,我使用PHP。公共字段违反了封装,因此,根据最佳实践,这只是...哈哈:) Google不使用公共字段,仅使用访问者:google-styleguide.googlecode.com/svn/trunk/…。

– OZ_
11年5月24日在21:08

@ e-satis:很抱歉跳进去,但是如果您希望控制变量更改时发生的情况,则必须使用getter和setter方法。否则,您不能简单地保证对象的内部状态(如果内部有另一个对象,则尤其如此)。这是完全独立于语言的。 @OZ_:请放松。个人批评只会使别人处于防御状态。

–詹姆斯P.
2011-6-4 17:08



@monadic:同意。当处理核心组件或复杂对象等时,封装当然是一个有效的参数,但是作为记录的表示,否则它将是可读写的。数组,这是可以接受的。此外,当记录在系统中浮动时,它还使类型检查更容易。

–丹·拉格
2011年7月16日,0:50



@outis我希望我不会在这里占少数,但是我不认为应该根据他们对新开发人员的安全性来判断答案。听起来很刺耳,但这是真的。关于SO的答案的目的不仅在于提供复制和粘贴代码,还在于提供理解。确保在示例中涵盖每个安全漏洞或模式缺陷不是回答者的工作,因为让我们面对现实,将代码复制到的应用程序与使用相同代码的其他所有应用程序本质上是不同的。

– Mattygabe
2011年9月1日14:11在

#2 楼

将应用程序从一个数据库迁移到另一个数据库并不是很常见,但是迟早您可能会发现自己正在使用不同的RDBMS处理另一个项目。如果您在家中使用PDO,那么到那时至少要少学习一件事。

除此之外,我发现PDO API更加直观,而且感觉更真实面向。如果您知道我的意思,mysqli感觉它只是一个已被对象化的过程API。简而言之,我发现PDO更易于使用,但这当然是主观的。

#3 楼

我开始使用PDO,因为我认为语句支持会更好。我使用的是ActiveRecord式数据访问层,实现动态生成的语句要容易得多。 MySQLi的参数绑定必须在单个函数/方法调用中完成,因此,如果您直到运行时才知道要绑定多少个参数,您将被迫使用call_user_func_array()(我相信这是正确的函数名)选择。忘记简单的动态结果绑定。

最重要的是,我喜欢PDO,因为它是非常合理的抽象级别。在不需要编写SQL的完全抽象的系统中可以很容易地使用它,但也可以使使用更优化的纯查询类型的系统,或者将两者混合和匹配变得容易。 >

评论


可以与动态生成的查询进行结果绑定,我们可以在应用程序中完成。然而,这是一个巨大的痛苦。

– Pim Jager
09年4月21日在7:50

#4 楼

PDO是标准,这是大多数开发人员期望使用的标准。 mysqli本质上是针对特定问题的定制解决方案,但它具有其他特定于DBMS的库的所有问题。 PDO是所有辛勤工作和明智思维的去向。

#5 楼

还有一些需要记住的事情:目前(PHP 5.2),PDO库存在错误。它充满了奇怪的错误。例如:在将PDOStatement存储到变量中之前,该变量应为unset(),以避免产生大量错误。其中大多数已在PHP 5.3中修复,它们将于2009年初在PHP 5.3中发布,其中可能还存在许多其他错误。如果您想要一个稳定的发行版,那么应该专注于将PDO用于PHP 6.1;如果想要对社区提供帮助,则应该专注于将PDO用于PHP 5.3。

评论


我认为PDO提供的收益值得理解和解决错误。 PHP本身充满了非常严重的错误,有些甚至使我们无法有效解决,但它提供了许多好处,导致我们使用它而不是其他选择。

–布莱恩·沃肖(Brian Warshaw)
09年11月10日在16:55

嗯,很奇怪,我从未遇到过PDO的任何错误。而且我经常使用它。

– NikiC
2011年1月23日在10:49

Mysqli也有错误。所有软件都有错误。

– Bill Karwin
13年5月6日在19:02

#6 楼

关于PDO的另一个显着(良好)区别是,它的PDO::quote()方法自动添加了引号,而mysqli::real_escape_string()(和类似名称)却没有:PDO :: quote()将引号括起来输入字符串(如果需要)和
使用适合基础驱动程序的引号
来转义输入字符串中的特殊字符。


#7 楼

如果您的站点/ Web应用程序真正成为现实,那么PDO将使扩展变得容易得多,因为您可以每天设置主从连接来在数据库中分配负载,此外PHP正朝着将PDO迁移为标准的方向发展。

PDO信息

缩放Web应用程序

#8 楼

从执行速度的角度来看,MySQLi胜出了,但是除非您使用MySQLi有一个很好的包装器,否则它处理预准备语句的功能就很糟糕。

因此,简而言之,如果您正在寻找速度的提高,那么MySQLi;如果您希望易于使用,请使用PDO。

评论


在速度方面,您能否提供基准?

–朱利叶斯·F
09年11月28日在14:44

乔纳森·罗布森(Jonathen Robson)在jonathanrobson.me/2010/06/mysqli-vs-pdo-benchmarks上做了不错的速度比较。简介:插入-几乎相等,选择-mysqli对于未准备好的语句快约2.5%,对于准备好的语句快约6.7%。考虑到性能损失很小,使用PDO的功能和灵活性通常会超过性能损失。

–亚当
2011-3-8在12:09



@Adam感谢您链接到我的博客!

– jnrbsn
2012年3月23日19:33

@ daemonfire300是的,不需要基准测试。 PDO包装了mysqli库。如果有人可以证明PDO比mysqli更快,我可能会大吃一惊。 :-D

–戴因
13年1月13日在10:05

@jnrbsn您是否同意亚当的话?

–Basit
13年2月2日,14:47

#9 楼

我个人使用PDO,但是我认为这主要是优先考虑的问题。

PDO具有一些功能,可以帮助再次进行SQL注入(准备好的语句),但是如果您对SQL保持谨慎,则可以实现这一点。也可以使用mysqli。

移动到另一个数据库并不是使用PDO的主要原因。只要您不使用“特殊SQL功能”,就可以从一个数据库切换到另一个数据库。但是,例如在使用“ SELECT ... LIMIT 1”时,您将无法进入“ SELECT TOP 1 ...”的MS-SQL。所以这还是有问题的。

评论


MySQLi已经准备了语句。

–塔
09年7月7日在9:59

#10 楼

编辑答案。

在对这两个API都有一定的经验之后,我会说有2种阻塞级别的功能使mysqli无法与本机准备的语句一起使用。
它们已经在2个优秀的版本中提到(但被低估了)答案:


将值绑定到任意数量的占位符

将数据作为纯数组返回

(两者在这个答案中也提到了)

由于某种原因mysqli都失败了。
现在第二个版本(get_result)有了一些改进,但是它仅适用于mysqlnd安装,这意味着您可以不要依赖您脚本中的此功能。

但是到目前为止,它还没有按值绑定。

因此,只有一个选择:PDO

所有其他原因,例如


命名为占位符(此语法糖被高估的方式)
不同的数据库支持(没有人真正使用过它)
提取到的对象(只是无用的语法糖)
速度差(有没有)

无关紧要。

同时,这两个API都缺少一些真正重要的功能,例如


identifier placeholder
placeholder for复杂的数据类型使动态绑定的繁琐性降低了。

因此,为了满足现实生活中的需求,必须基于这些API之一创建自己的抽象库。 ,实现手动解析的占位符。在这种情况下,我更喜欢mysqli,因为它的抽象级别较低。

评论


最后,一个知道并且不否认生活事实的人。

–易山
13年5月2日在7:15



#11 楼

在我的基准脚本中,每种方法都经过10000次测试,并打印出每种方法的总时间差。您应该在自己的配置上执行此操作,我确定结果会有所不同!

这些是我的结果:


SELECT NULL" -> PGO()快〜0.35秒
SHOW TABLE STATUS" -> mysqli()快约2.3秒
SELECT * FROM users" -> mysqli()快约33秒

注意:对于mysqli使用-> fetch_row(),列名不会添加到数组中,我没有找到在PGO中执行此操作的方法,但是即使我使用-> fetch_array(),mysqli也会稍慢一些,但仍然比PGO快(SELECT NULL除外)。

评论


什么是PGO?快33秒?!我觉得很难相信...

– Alix Axel
2011年7月26日下午4:15

#12 楼

PDO具有MySQLi我真正不喜欢的一件事是PDO能够将结果作为指定类类型的对象(例如$pdo->fetchObject('MyClass'))返回。 MySQLi的fetch_object()将仅返回一个stdClass对象。

评论


实际上,您可以手动指定一个类:“对象mysqli_result :: fetch_object([字符串$ class_name [,数组$ params]])”。仅当您不指定任何内容时才使用stdClass。

– Andrioid
2010年9月4日在8:12

#13 楼

请记住一件事。

Mysqli不支持fetch_assoc()函数,该函数将返回带有表示列名的键的列。当然,可以编写自己的函数来做到这一点,虽然时间不算太长,但是我确实很难编写它(对于非信奉者:如果您觉得方便,可以花一些时间自己尝试一下,不要这样做。 t作弊:))

评论


您是否尝试过该手册? php.net/manual/en/mysqli-result.fetch-assoc.php

–直到
08年9月24日在13:49

实施时间更长,但是是的,我检查了手册。它与准备好的语句一起工作吗?我怀疑...

– Mike
08/09/24在13:56

实际上,它有一个奇怪的部分支持。您可以在常规查询中获取数组,但不能在参数化查询中获取数组:-!

–ÁlvaroGonzález
2010-4-30 10:22

为什么不删除明显错误的答案?

–马吉德·弗拉德普尔
2012年4月19日在3:04

@MajidFouladpour-答案显然不是错误的。它只是缺少一些上下文。 Mysqli不完全支持关联数组检索。

–ÁlvaroGonzález
2012年4月24日11:02