PHP中的"&"运算符

35

我不是PHP程序员(但了解其他语言),我正在尝试理解一个用PHP(5.1.6)完成的网页,以进行一些更改。

该页面具有以下代码(简化版):

$db_hosts = array();
$sql = 'SELECT h.hostid, h.host FROM hosts h ';

$db_items = DBselect($sql);

while($db_item = DBfetch($db_items)){
    $name = $db_item['host'];
    $db_host = &$db_hosts[$db_item['hostid']];
}

我试图理解最后一行代码,$db_host = &$db_hosts[$db_item['hostid']];

它似乎在创建一个名为$db_host的新变量并将某些内容放入其中,但我不理解&$db_hosts

我感到疑惑是因为据我所知,$db_hosts是一个空数组。

我在这里这里找到了相关信息,但我并不完全确定,因为在这些链接中,操作符是"=&",而在代码中,操作符与变量连接起来成为"= &$db_hosts"(等号和&之间有一个空格)。

由于我尝试修改它但没有成功,所以我认为最好寻求帮助...

9个回答

42

这些是引用,与C或C++中的“指针”类似。

更多信息可以在PHP手册中找到。

在这种情况下,由于$db_hosts为空,构造$db_hosts[$db_item['hostid']]将创建一个新的数组,并在索引$db_item['hostid']上放置一个空项,然后返回项的引用,使$db_host成为当前$db_hosts[$db_item['hostid']]的“别名”。


1
这是正确的。我同时做了太多的事情,回复得太快了 :-) - Josh
7
正如我们正在讨论PHP引用一样,需要提供一个名为“不要使用PHP引用”的帖子链接 - http://schlueters.de/blog/archives/125-Do-not-use-PHP-references.html - Tom Morris
4
稍作更正,实际上它们与 C 语言中的指针并不相同。您可以在 http://www.php.net/manual/en/language.references.arent.php 查看相关信息。 - Qarib Haider

24

& 在 PHP 中被用于表示引用(参见此手册章节),但认为它是一个操作符是误导人的。这就是为什么有些人喜欢写$foo =& $bar而不是$foo = &$bar - 这两种写法意思是相同的,但强调了“引用性”是赋值操作的一个属性,而不是变量本身的属性。

在某些编程语言如 C 或 C++ 中,您可以“获取对”特定变量的引用;得到的值可以作为一个独立实体传递,并且可以通过“取消引用”找出它所指向的位置。PHP 的引用并非如此。

事实上,所有的 PHP 变量实际上都是对一个名为 zval 的内部类型的引用。您不能直接操作 PHP 中的 zval,也不能创建额外的间接层级 - 每个变量都是对一个 zval 的引用,仅此而已。(请参阅注释:对象下面的内容。)

通过引用赋值($foo =& $bar)、通过引用传递(function foo(&$bar) { ... })或通过引用返回(return &$foo)所做的是告诉 PHP 您希望两个变量指向同一个 zval。请注意,您并没有将一个变量“指向”另一个变量 - 它们都是同样“真实”的,对其中任意一个调用 unset() 都不会对另一个造成任何影响。

注释:对象

通常会误导性地说,自 PHP5 以来对象总是“按引用传递”。事实上,它们有一个额外的间接层级,其中 zval 本身就是指向特定对象的指针。这使我们可以引用三个不同的东西:变量、它所指向的 zval,以及该 zval 所指向的对象:

// Create an object, and point three variables at it in different ways:
$foo = new stdClass;
$bar_by_value = $foo;
$bar_by_ref =& $foo;

// Change the object: updates the object shared by all three variables
$foo->value = 42;
// Change the value (zval) of $foo: will update $bar_by_ref, 
//   but $bar_by_value still points at the original object
$foo = 42; 
// Change the variable itself: will never affect $bar_by_value or $bar_by_ref
unset($foo);

谢谢解释,但是如果您更改$bar_by_ref->value = 43;,那么会更新$bar_by_value$foo吗?例如,我有一个浮点数数组,我想四舍五入。像foreach($float as& $f) $f = ROUND($f, 1);这样的调用可以工作吗?并将所有$float值更新为四舍五入的数字? - Jaquarh
@Jaquarh 简而言之,是的和是的,尽管这两个问题非常不同。对于第一个问题,只需考虑对象 $bar_by_ref 指向的是什么;是否与 $foo 相同,还是在其他地方创建了一个新对象?foreach 循环基本上就像编写 $f =& $float[0]; $f = round($f, 1); $f =& $float[1]; $f = round($f, 1); 等等,因此遵循引用的普通规则。 - IMSoP
我现在理解这个概念了!说实话,阅读关于zval的内容很有趣,因为它展示了它们可以像foreach一样被操作,以改变一个数组而不是重新创建一个全新的数组。感谢您抽出时间回复我的评论! - Jaquarh

12

问题:

在PHP中,"&"表示什么意思?

PHP "&"运算符

一旦习惯了,它会让我们的生活更加轻松..(请仔细查看下面的示例)

&通常检查在$a和$b中都设置的位。

你有没有注意到这些调用是如何工作的?

   error_reporting(E_ERROR | E_WARNING | E_PARSE);
    error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE);
    error_reporting(E_ALL & ~E_NOTICE);
    error_reporting(E_ALL);

所有上述背后都是位运算符和位的游戏。

其中一个有用的用例就像下面所示的简单配置,因此单个整数字段可以为您存储数千个组合。

大多数人已经阅读了文档,但没有意识到这些位运算符的实际用法。

例子 - 这可以在日常PHP生活中非常有用

<?php

class Config {

    // our constants must be 1,2,4,8,16,32,64 ....so on
    const TYPE_CAT=1;
    const TYPE_DOG=2;
    const TYPE_LION=4;
    const TYPE_RAT=8;
    const TYPE_BIRD=16;
    const TYPE_ALL=31;

    private $config;

    public function __construct($config){
        $this->config=$config;

        if($this->is(Config::TYPE_CAT)){
            echo 'cat ';
        }
        if($this->is(Config::TYPE_DOG)){
            echo 'dog ';
        }
        if($this->is(Config::TYPE_RAT)){
            echo 'rat ';
        }
        if($this->is(Config::TYPE_LION)){
            echo 'lion ';
        }
        if($this->is(Config::TYPE_BIRD)){
            echo 'bird ';
        }
        echo "\n";
    }

    private function is($value){
        return $this->config & $value;
    }
}

new Config(Config::TYPE_ALL);
// cat dog rat lion bird
new Config(Config::TYPE_BIRD);
//bird
new Config(Config::TYPE_BIRD | Config::TYPE_DOG);
//dog bird
new Config(Config::TYPE_ALL & ~Config::TYPE_DOG & ~Config::TYPE_CAT);
//rat lion bird

12
这是一个非常好的例子......展示了完全不同的操作符。它也碰巧被拼写为"&",但问题中的操作符是按引用赋值,与位运算无关。 - IMSoP
很好,你可以随时为自己喜欢的内容点赞,这对你和其他人都有帮助。 - dev.meghraj
为什么TYPE_ALL=31?难道不应该是32吗? - Jeff Puckett
31表示包括所有内容,32则是单个数值,而31表示所有内容的组合。 - dev.meghraj
1
因为1+2+4+8+16=31。 - dehart


4
将该变量分配为参考变量,这样如果以后更改$db_host,则$db_hosts数组中的相应条目也会相应更改,反之亦然。
我曾在PHP中看到过相当多无意义的参考使用,类似于货物崇拜式。也许需要这个,也许不需要-您得查看程序的其余部分。

3

&被用作引用。查看在http://php.net/manual/en/language.references.php中的引用:

在PHP中,引用是一种通过不同的名称访问相同变量内容的方式。它们不像C指针;例如,您不能使用它们执行指针算术运算,它们不是实际的内存地址等等。


2

&符号用于获取变量的引用。它类似于其他语言(如C ++)中的引用,但有一些显着的区别。请参阅PHP手册中有关引用的部分


你在考虑 @ 符号。 - rook
1
@Michael Brooks:是的,我当时是这样认为的,抱歉回答得太快了。我已经更正了我的回答。 - Josh
3
乍一看似乎合理,但这是一个非常误导人的答案:&符号并不会“获取”一个引用,因为引用本身并不存在(就像C指针一样)。相反,最好将= &视为将两个变量绑定在一起的运算符,并将类似于function foo(&$ bar)的语法视为编写该赋值的方式。 - IMSoP

2
这是一个简单示例,用来解释PHP中&运算符的含义:
<?php

$x = "Hello";

$y = &$x;
echo "Value of x : " . $x . "\n";
echo "Value of y : " . $y . "\n";

$y = "Hi"; // Since $y is alias or reference of the variable $x, so value of $x will also be changed, see below:

echo "Value of x : " . $x . "\n";
echo "Value of y : " . $y . "\n";

以上代码的输出如下:
Value of x : Hello
Value of y : Hello
Value of x : Hi
Value of y : Hi

从上面的例子可以看出,这是变量的引用。
来自官方文档:什么是引用 在 PHP 中,引用是使用不同名称访问相同变量内容的一种方式。它们并不像 C 指针;例如,您不能使用它们执行指针算术运算,它们不是实际的内存地址等等。有关更多信息,请参见 引用不是什么。相反,它们是符号表别名。请注意,在PHP中,变量名和变量内容是不同的,因此相同的内容可以具有不同的名称。最接近的类比是Unix文件名和文件-变量名是目录条目,而变量内容是文件本身。可以将引用类比为Unix文件系统中的硬链接。

0

& 用作引用和位比较

位比较示例:

<?php
function test_odd($var){
  return($var & 1);
}

$a1=array(1,3,2,3,4,5,6,7);
print_r(array_filter($a1,"test_odd"));
?>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接