jjzjj

php - PDO 返回空属性名称

coder 2023-06-14 原文

我遇到了 pdo_odbc 和 PDO::FETCH_OBJ(和 PDO::FETCH_CLASS)的奇怪问题,导致以下错误消息:

PHP Fatal error:  Cannot access empty property

这是代码:
$dbh = new PDO("odbc:FOO");

$sth = $dbh->query("
  SELECT rolename
  FROM dbc.allrolerights
  WHERE databasename = 'BAR'
");

$result = $sth->fetch(PDO::FETCH_OBJ);

供引用的 FOO DSN 是使用 tdodbc 包提供的 tdata.so 驱动程序的 Teradata 数据源。

我相信这是因为当 PDO 调用 zend_API.h:object_init_ex() 来实例化 stdClass 对象时,字段名称(从 ODBC 查询返回)是空白的。如果我切换到 PDO::FETCH_LAZY 和 var_dump() 行,我会得到以下信息:
object(PDORow)#3 (2) {
  ["queryString"]=>
  string(95) "
  SELECT rolename
  FROM dbc.allrolerights
  WHERE databasename = 'BAR'
"
  [""]=>
  string(30) "FNAR                          "
}

这似乎支持它。我已经尝试了几种不同的 PDO 属性组合和一堆不同的角度来解决这个问题。一种解决方案是获取关联数组并将其传递给类构造函数。但是,这对于在幕后直接使用 PDO::FETCH_CLASS 的某些框架和 ORM 不起作用。

我想补充一点,其他 fetch 方法似乎做正确的事情,例如,PDO::FETCH_NAMED:
array(1) {
  ["RoleName"]=>
  string(30) "FNAR                          "
}

我正在寻找可以放入 PDO dbh 或 sth 定义中,或者放入数据源或驱动程序的 odbc.ini 或 odbcinst.ini 中的内容,以解决此问题。先感谢您。

更新: odbc_fetch_object()(即不是 PDO)对于完全相同的所有内容都非常有效。只是想提一下。显然,PHP、unixODBC 或 ODBC 驱动程序似乎没有任何严重问题。这是 PDO 代码中的内容。是时候打开错误报告了... opened
$dbh = odbc_connect("FOO", NULL, NULL)
  or die(odbc_error_msg());

$sth = odbc_exec($dbh, "
  SELECT rolename
  FROM dbc.allrolerights
  WHERE databasename = 'BAR'
");

$result = odbc_fetch_object($sth);
var_dump($result);

和输出:
object(stdClass)#1 (1) {
  ["RoleName"]=>
  string(30) "FNAR                          "
}

更新 2:情况继续变得越来越离奇。我可以执行 PDO::FETCH_LAZY 并查看上面 var_dump() 中看到的空白列名称,但是如果我尝试按名称访问该属性(例如 $result->RoleName),它会起作用!这些 fetch 方法有什么不同之处,以至于其中一些有时可以访问字段名称,而另一些则不能?

ODBC 跟踪(“工作”参见“不工作”)的并排比较显示没有差异(除了不同的指针地址)。 PDO::FETCH_BOUND 适用于编号列和命名列。 PDO::FETCH_INTO 具有 RoleName 属性的对象没有。

最佳答案

你的问题描述了两个问题:

  • Why is it that objects cannot be created with properties having empty-string names when using PDO::FETCH_OBJ, but apparently can when using other methods?



    Internal structures and implmentation 下所述在 PHP Internals Book 中,“dynamic properties”(即对象的成员变量未在其类定义中声明,而是在运行时创建)被实现为哈希表。

    如果希望使用当前保存在哈希表中的一组属性填充新实例化的标准对象,则可以简单地指向对象的 properties。现有哈希表中的变量——PHP 的 object_and_properties_init()函数,即 called by odbc_fetch_object() , does exactly that不对表的键执行任何完整性检查。因此,可以用奇怪的属性名称(例如空字符串)实例化一个对象。

    另一方面,如果已经有一个实例化的对象并且需要设置一个属性值(同时保留任何已经存在的其他值),则必须将该值复制到对象的哈希表中——PHP 的 zend_std_write_property()方法,为标准对象处理此操作,does exactly that首先对属性名称进行了完整性检查。因此,不能向现有对象添加具有奇怪名称(例如空字符串)的属性。

    在我看来,这两种方法在健全性检查方面的差异似乎是一个错误:无论创建此类属性的方法如何,都应该强制执行对动态属性名称的任何限制。是应该允许这种奇怪的名字(因此应该从后一种方法中删除健全性检查)还是不允许(因此应该在前一种方法中添加一些健全性检查),这是我将留给PHP 开发人员。

    How does PDO fit into all this?


    PDOStatement::fetch()首先准备存储结果的目的地,然后iterates over the columns依次存储每个字段:我想这样做是为了简化代码库,因为每个 fetch 样式都可以在相同的结构中实现。但是,这确实意味着当使用 PDO::FETCH_OBJ 调用时样式(还有 PDO::FETCH_CLASSPDO::FETCH_INTO ,正如您所观察到的),an object is instantiated firstits properties are populated later .因此,奇怪的属性名称(例如空字符串)会导致观察到的失败。

    您尝试过的其他 fetch 样式没有遇到同样的问题,因为:
  • PDO::FETCH_BOUND提取到先前调用 PDOStatement::bindColumn() 指定的变量中, 所以 PHP 从不尝试写入具有空名称的属性;
  • PDO::FETCH_LAZY skips the whole shebang并以与 odbc_fetch_object() 类似的方式进行操作多于。

  • 类似地,基于数组的 fetch 样式不会遇到类似的问题,因为空字符串键在这些哈希表中是完全有效的。
  • Why is it that PDO thinks the column names in this ODBC recordset are empty strings?



    这个问题的答案对我来说不太明显。

    我们之前看到,为了填充属性,PDO 使用 stmt->columns[i].name作为属性名称。这应该在 an earlier point 正确填写, 当 pdo_stmt_describe_columns() was called .这个函数依次had called司机的describer结果集中每一列的方法:在 PDO_ODBC 的情况下,即 odbc_stmt_describe()这确实assign a value to that field .

    因此,PHP 方面的一切看起来都很好。知道是否 the call to the driver's SQLDescribeCol() function 会很有趣。正确地将列名填充到作为其第三个参数提供的缓冲区中:有人认为没有,这表明问题出在 ODBC 驱动程序本身。您提到您正在使用 Teradata:但是您确定您对 PDO_ODBC(不起作用)和 ext/odbc(起作用)使用相同的驱动程序吗?

    特别是 Extension Level Functions 下的 Teradata 文档:

    By default, SQLDescribeCol and SQLColAttribute return the column name instead of the Teradata column title. If an application wants ODBC Driver for Teradata to return the column title instead of the actual column name, then the option Use Column Names in the Teradata ODBC Driver Options dialog box must not be selected for the DSN used, or set DontUseTitles = No on the UNIX OS.

    Returning the column title instead of the actual column name can cause problems for certain applications, such as Crystal Reports, because they expect to get the column name and not the column title.

  • 关于php - PDO 返回空属性名称,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22614222/

    有关php - PDO 返回空属性名称的更多相关文章

    1. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

      为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

    2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

      我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

    3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

      我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

    4. ruby - 多个属性的 update_column 方法 - 2

      我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

    5. ruby - Nokogiri 剥离所有属性 - 2

      我有这个html标记:我想得到这个:我如何使用Nokogiri做到这一点? 最佳答案 require'nokogiri'doc=Nokogiri::HTML('')您可以通过xpath删除所有属性:doc.xpath('//@*').remove或者,如果您需要做一些更复杂的事情,有时使用以下方法遍历所有元素会更容易:doc.traversedo|node|node.keys.eachdo|attribute|node.deleteattributeendend 关于ruby-Nokog

    6. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

      我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

    7. ruby-on-rails - Rails 模型——非持久类成员或属性? - 2

      对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs

    8. ruby - Ruby 中的隐式返回值是怎么回事? - 2

      所以我开始关注ruby​​,很多东西看起来不错,但我对隐式return语句很反感。我理解默认情况下让所有内容返回self或nil但不是语句的最后一个值。对我来说,它看起来非常脆弱(尤其是)如果你正在使用一个不打算返回某些东西的方法(尤其是一个改变状态/破坏性方法的函数!),其他人可能最终依赖于一个返回对方法的目的并不重要,并且有很大的改变机会。隐式返回有什么意义?有没有办法让事情变得更简单?总是有返回以防止隐含返回被认为是好的做法吗?我是不是太担心这个了?附言当人们想要从方法中返回特定的东西时,他们是否经常使用隐式返回,这不是让你组中的其他人更容易破坏彼此的代码吗?当然,记录一切并给出

    9. ruby-on-rails - ruby 日期方程不返回预期的真值 - 2

      为什么以下不同?Time.now.end_of_day==Time.now.end_of_day-0.days#falseTime.now.end_of_day.to_s==Time.now.end_of_day-0.days.to_s#true 最佳答案 因为纳秒数不同:ruby-1.9.2-p180:014>(Time.now.end_of_day-0.days).nsec=>999999000ruby-1.9.2-p180:015>Time.now.end_of_day.nsec=>999999998

    10. ruby - 从 String#split 返回的零长度字符串 - 2

      在Ruby1.9.3(可能还有更早的版本,不确定)中,我试图弄清楚为什么Ruby的String#split方法会给我某些结果。我得到的结果似乎与我的预期相反。这是一个例子:"abcabc".split("b")#=>["a","ca","c"]"abcabc".split("a")#=>["","bc","bc"]"abcabc".split("c")#=>["ab","ab"]在这里,第一个示例返回的正是我所期望的。但在第二个示例中,我很困惑为什么#split返回零长度字符串作为返回数组的第一个值。这是什么原因呢?这是我所期望的:"abcabc".split("a")#=>["bc"

    随机推荐