我在php.net之前发布此内容,以便更好地了解我在PHP 5.x和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()只是oci_execute和oci_fetch_array。 checkResult()只验证返回的行包含第二个参数中的值。
在PHP 7(无论如何是7.0.8和7.0.10)中,对checkResult的第二次调用报告返回的行包含RECORD#2270而不是预期的2274.
在gdb中搜索代码,这是我拼凑的内容:
oci_bind_by_name的& $变量参数最终被z /取消引用,并在bindp-> zval(oci8_statement.c:1250)中作为简单字符串zval存在。这是可以的,因为只要所有的zval都指向相同的字符串,其他更简单的测试就可以工作。
从oci_bind_by_name返回时,$ cacheRow [0]现在是预期的引用。
在下一个$ cacheRow [0] =' 2274'当在赋值期间生成$ cacheRow的副本时,生成的副本中的$ cacheRow [0]不再是引用,只是指向原始字符串的zval。
复制完成后,当分配到新的$ cacheRow [0]时,它只是改变了它的str指针。
现在新的$ cacheRow [0]指向一个不同于oci8_statement的bindp-> zval的字符串,所以下一个oci_execute将拉出旧的绑定值。
我可以通过确保涉及$ cache [0](in-to和out-of)的赋值是by-reference来解决这个问题。这避免了这个问题,因为$ 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参数的引用计数,那么我的原始测试在PHP之间的行为相同5和PHP 7.然后,我愿意确信这是预期的行为,我确实需要使用ref-by-ref。
答案 0 :(得分:1)
尝试刚上传到https://bugs.php.net/patch-display.php?bug_id=71148&patch=oci8-php7-bind&revision=latest
的PHP OCI8补丁答案 1 :(得分:0)
查看https://bugs.php.net/bug.php?id=71148中的评论 有影响OCI8的PHP 7引用计数更改(对于PHP性能)。我们尝试在OCI8扩展中碰撞引用计数,但这打破了其他事情。