简体   繁体   English

php7,引用和oci_bind_by_name

[英]php7, references and oci_bind_by_name

I'm posting this here before php.net to maybe get a better understanding of the difference in behavior that I'm seeing between PHP 5.x and 7.x. 我在php.net之前发布这个,以便更好地理解我在PHP 5.x和7.x之间看到的行为差异。

The following code works in PHP 5.x but not 7.x 以下代码适用于PHP 5.x但不适用于7.x.

$conn = oci_connect('****', '****', '****', '****');
$stmt = oci_parse($conn, 'select record# from company where record#=:1');

$cache = [];

$cacheRow[0] = '2270';

oci_bind_by_name($stmt, ":1", $cacheRow[0], 2*strlen($cacheRow[0])+32);

$cache[0] = $cacheRow;

$result = runStmt($stmt);
checkResult($result, '2270');

$cacheRow = $cache[0];
$cacheRow[0] = '2274';
$cache[0] = $cacheRow;

$result = runStmt($stmt);
checkResult($result, '2274');

runStmt() just oci_execute and oci_fetch_array. runStmt()只是oci_execute和oci_fetch_array。 checkResult() just verifies that the row returned contains the value in the second parameter. checkResult()只验证返回的行包含第二个参数中的值。

In PHP 7 (7.0.8 and 7.0.10 anyway) the second call to checkResult reports that the row returned contains the RECORD# 2270 not the expected 2274. 在PHP 7(无论如何是7.0.8和7.0.10)中,对checkResult的第二次调用报告返回的行包含RECORD#2270而不是预期的2274。

Tracing through the code in gdb here's what I've pieced together: 跟踪gdb中的代码,这是我拼凑到的内容:

  • The &$variable parameter of oci_bind_by_name ends up be dereferenced by z/ and lives on as a simple string zval in bindp->zval (oci8_statement.c:1250). oci_bind_by_name的&$ variable参数最终被z /取消引用,并在bindp-> zval(oci8_statement.c:1250)中作为一个简单的字符串zval存在。 This is ok, as other simpler tests work as long as all the zvals are pointing at the same string. 这是可以的,因为只要所有的zval都指向相同的字符串,其他更简单的测试就可以工作。

  • On return from oci_bind_by_name $cacheRow[0] is now a reference as expected. 从oci_bind_by_name返回时,$ cacheRow [0]现在是预期的引用。

  • On the next $cacheRow[0] = '2274' when the copy of $cacheRow is made during the assignment, $cacheRow[0] in the resulting copy is no longer a reference, just a zval pointing to the original string. 在下一个$ cacheRow [0] ='2274',当在赋值期间生成$ cacheRow的副本时,生成的副本中的$ cacheRow [0]不再是引用,只是指向原始字符串的zval。

  • After the copy when the assignment into the new $cacheRow[0] is made it just changes its str pointer. 在复制到新$ cacheRow [0]的赋值后,它只是改变了它的str指针。

Now the new $cacheRow[0] is pointing to a different string than oci8_statement's bindp->zval so the next oci_execute will pull the old bound value. 现在新的$ cacheRow [0]指向一个不同于oci8_statement的bindp-> zval的字符串,所以下一个oci_execute将拉出旧的绑定值。

I can work around this by ensuring that the assignments involving $cache[0] (both in-to and out-of) are by-reference. 我可以通过确保涉及$ cache [0](in-to和out-of)的赋值是by-reference来解决这个问题。 This avoids the issue because the $cacheRow array is never separated. 这避免了这个问题,因为$ cacheRow数组永远不会分开。

I can also reproduce this in pure PHP code 我也可以用纯PHP代码重现这一点

function bbn1(&$var)
{
}

function test1()
{
    $cache = [];

    $cacheRow[0] = '2270';

    bbn1($cacheRow[0]);
    $x = $cacheRow[0];

    $cache[0] = $cacheRow;

    $cacheRow = $cache[0];
    // Copy-on-write of $cacheRow does not preserve the reference in 
    // $cacheRow[0] because $cacheRow[0]'s refcount == 1
    // zend_array_dup_element in zend_hash.c
    $cacheRow[0] = '2274';

}

function bbn2(&$var)
{
    static $cache = [];
    $cache[] =& $var;
}

function test2()
{
    $cache = [];

    $cacheRow[0] = '2270';

    bbn2($cacheRow[0]);
    $x = $cacheRow[0];

    $cache[0] = $cacheRow;

    $cacheRow = $cache[0];

    // Copy-on-write of $cacheRow preserves the reference in 
    // $cacheRow[0] because $cacheRow[0]'s refcount != 1
    // zend_array_dup_element in zend_hash.c
    $cacheRow[0] = '2274';

}

Since I can get different behaviors in the pure PHP tests depending on if I keep a reference to the passed parameter to bbn this makes me think that if oci_bind_by_name increased the refcount on its incoming bind_var parameter my original test would behave identically between PHP 5 and PHP 7. Then again, I'm willing to be convinced that this is expected behavior and I really do need to use assignment-by-ref. 由于我可以在纯PHP测试中获得不同的行为,具体取决于我是否将对传递的参数的引用保留为bbn,这使我认为如果oci_bind_by_name增加了其传入的bind_var参数的引用计数,那么我的原始测试在PHP 5和PHP之间的行为相同7.然后,我愿意确信这是预期的行为,我确实需要使用assign-by-ref。

See comments in https://bugs.php.net/bug.php?id=71148 There were PHP 7 ref counting changes (for PHP performance) that have impacted OCI8. 请参阅https://bugs.php.net/bug.php?id=71148中的注释。已经影响OCI8的PHP 7引用计数更改(针对PHP性能)。 We experimented with bumping the ref count inside the OCI8 extension but this broke other things. 我们尝试在OCI8扩展中撞击引用计数,但这打破了其他事情。

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

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