2012-12-12 38 views
5

我有一个功能奠定了即使是简单的功能:它是很好的做法,使用引用

$query = "SELECT * from lol"; 
database_query($query); 

考虑$query永远不会database_query函数内部改变,是它使用指针来$query这么好的做法该函数不需要将更多的内存分配给传入的值的新迭代?

function database_query(&$query){ 
    //do stuff that does not affect $query 
} 
+0

这个最近的问题可能会对您有所帮助: [为什么在PHP中很少使用引用?](http://programmers.stackexchange.com/q/188765/4978) –

回答

-2

这是一个非常有趣的问题,我花了一个半小时的时间阅读了关于PHP以及它如何处理引用(感谢Tim Cooper让我开始的链接)。

要回答你的问题,是的 - 当你调用一个函数时,最好使用这样的引用。通过使用引用,您将使用更少的资源 - 对于引用变量,没有“写入时复制”。下面是一些证据:

<?php 
function noref_nowrite($var_a){ 
    echo '<h3>NOT Using a Reference/Not Changing Data</h3>'; 
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>'; 
    echo '<p>'. debug_zval_dump($var_a) .'</p>'; 
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>'; 
} 
function noref_write($var_a){ 
    $var_a++; 
    echo '<h3>NOT Using a Reference/Changing Data</h3>'; 
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>'; 
    echo '<p>'. debug_zval_dump($var_a) .'</p>'; 
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>'; 
} 

function ref_nowrite(&$var_a){ 
    echo '<h3>Using a Reference/Not Changing Data</h3>'; 
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>'; 
    echo '<p>'. debug_zval_dump($var_a) .'</p>'; 
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>'; 
} 
function ref_write(&$var_a){ 
    $var_a++; 
    echo '<h3>Using a Reference/Changing Data</h3>'; 
    echo '<p>'. xdebug_debug_zval('var_a') .'</p>'; 
    echo '<p>'. debug_zval_dump($var_a) .'</p>'; 
    echo '<p>$var_a = '. $var_a .' and $GLOBALS[a] = '. $GLOBALS['a'] .'</p>'; 
} 

$a = 5; 
noref_nowrite($a); 
noref_write($a); 
ref_nowrite($a); 
ref_write($a); 
?> 

如果你复制/粘贴上面的代码到一个PHP页面并执行它,你会看到:

NOT Using a Reference/Not Changing Data 
var_a: (refcount=3, is_ref=0)=5 
long(5) refcount(4) 

$var_a = 5 and $GLOBALS[a] = 5 


NOT Using a Reference/Changing Data 
var_a: (refcount=1, is_ref=0)=6 
long(6) refcount(2) 
$var_a = 6 and $GLOBALS[a] = 5 

Using a Reference/Not Changing Data 
var_a: (refcount=3, is_ref=1)=5 
long(5) refcount(1) 
$var_a = 5 and $GLOBALS[a] = 5 

Using a Reference/Changing Data 
var_a: (refcount=3, is_ref=1)=6 
long(6) refcount(1) 
$var_a = 6 and $GLOBALS[a] = 6 

所以,我们在这里是四个基本的测试。我创建一个全局变量($ a)和分配给它的5

值当我打电话noref_nowrite功能,我们看到了XDebug计数3个引用而PHP的内置函数计算4.有趣的是,PHP优化此所以在内部它的真的很像调用ref_nowrite函数,因为PHP使$ var_a成为$ GLOBALS ['a']的引用。

当我调用noref_write函数时,我们看到refcount下降到1(或者如果您查看PHP的内置函数,则为2)。为什么?因为这是“写入时复制”问题发生的地方。直到我们增加了$ var_a PHP在内部使用$ var_a作为$ a的引用,但是当我们改变了值时,我们强迫PHP创建了一个变量副本,以便它可以增加。因此,$ var_a不再是对$ a的引用,而是改为引用它自己的数据。

ref_nowrite函数显示不明确的结果。单看它,我们无法证明任何事情。然而,ref_write函数告诉我们XDebug表示我们正在处理一个引用变量(is_ref = 1),最重要的是我们看到,在我们增加$ var_a后,全局变量$ a的值也发生了变化 - 这意味着$ var_a和$ GLOBALS ['a']绝对指向内存中的相同位置。这意味着更改$ var_a不会触发“写入时复制”情况 - 并且不应该因为我们正在处理引用。

玩这个说服自己和这里的一些更多阅读:

Detecting whether a PHP variable is a reference/referenced(我认为ircmaxell有一个深思熟虑的答案)

http://us2.php.net/debug-zval-dump

XDebug的文档:http://xdebug.org/docs/display

PHP参考做什么:http://us3.php.net/manual/en/language.references.whatdo.php

PHP参考计数基础知识:http://us3.php.net/manual/en/features.gc.refcounting-basics.php

+2

我不太确定这是什么目标,因为问题不在于PHP是否使用引用变量执行复制,显然不是这样做的,但是传递参数是否是好的做法作为参考如果价值没有被改变。你自己的测试表明PHP在变量数据没有被修改时会创建一个变量数据的副本,因此变量不应该作为参考传递。这只是创建不明确的代码。 –

+1

只要不传递某些东西作为参考,那并不打算作为参考传递,如果你不想要特定的行为。首先它是(在这种情况下是:超)微型优化(我认为引擎可以做得更好),因此你花了90分钟找到一些东西,没有任何好处。除此之外,问题是关于“良好的做法”,这绝对不是。 – KingCrunch

6

不,不这样做。如果函数("copy on write")内部的非传递引用参数的值发生更改,PHP将只创建字符串的另一个副本。没有理由让参与者将参数作为参考,从而让人们看到你的函数在做什么的错误印象。

另外,references are not pointers

+0

这是不正确的。 PHP不会为引用变量写一个副本。 –

+0

@BennyHill:在谈论写入时复制时,我并没有提到引用变量。我已经为你澄清了这一点。 –

+0

@BennyHill当你的应用程序大于一个文件的示例脚本时,你永远无法确定有多少不同的引用指向相同的值。您可能会触发堆栈跟踪中高于上面某个值的写入时复制。 – KingCrunch

1

$query的值是一个字符串。字符串没有内部可变状态 - 在PHP中“更改”包含字符串的变量的唯一方法是为其分配一个新字符串(或者通过引用一个函数来传递它,然后为该字符串分配一个新字符串等)。因此,当你做$foo = $query;时,任何合理的实现都会简单地将指针复制到内部字符数组中,而不是复制实际字符,因为它们不能改变。所以,即使你不知道PHP有copy-on-write,你可以得出结论,按值传递字符串并不昂贵。

相关问题