我在这里发布这篇文章是为了更好地理解PHP5.x和7.x之间的行为差异。
以下代码适用于PHP5.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()只有oci_execute和oci_fetch_array。checkResult()只是验证返回的行是否包含第二个参数中的值。
在PHP7(至少是7.0.8和7.0.10 )中,对checkResult的第二个调用报告返回的行包含RECORD# 2270,而不是预期的2274。
通过gdb中的代码进行跟踪,下面是我拼凑起来的内容:
现在,新的$cacheRow指向与oci8 8_语句的bindp->zval不同的字符串,因此下一个oci_execute将提取旧的绑定值。
我可以通过确保涉及$cache0的作业是参考的来解决这个问题。这避免了这个问题,因为$cacheRow数组从未分开。
我也可以用纯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';
}由于我可以在纯PHP测试中得到不同的行为,这取决于我是否保持对bbn传递参数的引用,这使我认为,如果oci_bind_by_name增加了传入bind_var参数的拒绝次数,我的原始测试将在PHP5和PHP7之间的行为相同。然后,我愿意再次确信这是预期的行为,我确实需要使用赋值-by-ref。
发布于 2016-10-13 04:54:44
发布于 2016-08-17 00:56:32
参见https://bugs.php.net/bug.php?id=71148中的注释--PHP7ref正在计算对OCI8产生影响的更改(对于performance)。我们试验了在OCI8扩展中碰撞引用数,但这破坏了其他事情。
https://stackoverflow.com/questions/38861588
复制相似问题