错误消息“严格标准:仅变量应通过引用传递”


81
$el = array_shift($instance->find(..))

上面的代码以某种方式报告了严格的标准警告,但是不会:

function get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

那么,它将何时报告警告呢?


1
$ instance-> find(..)返回什么?
Silver


我认为示例(或逻辑)在问题中可能走错了路,因为第二个示例(get_arr()函数)确实产生了严格的标准声明(测试过PHP 5.2和PHP 5.5)。
MrWhite

Answers:


93

考虑以下代码:

error_reporting(E_STRICT);
class test {
    function test_arr(&$a) {
        var_dump($a);
    }
    function get_arr() {
        return array(1, 2);
    }
}

$t = new test;
$t->test_arr($t->get_arr());

这将生成以下输出:

Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

原因?该test::get_arr()方法不是变量,在严格模式下将生成警告。此行为非常不直观,因为该get_arr()方法返回一个数组值。

要在严格模式下解决此错误,请更改方法的签名,使其不使用引用:

function test_arr($a) {
    var_dump($a);
}

由于您无法更改签名,array_shift因此还可以使用中间变量:

$inter = get_arr();
$el = array_shift($inter);

7
@ user198729:我也在寻找解释或解决方法,发现您可以将current()用于第一项。遗憾的是,end()不适用于最后一个,因为它“将内部指针移至最后一个元素”。current(array_reverse(somefunction()))起作用(是的,这很愚蠢)
MSpreij 2011年

1
使用current假定数组指针位于第一个元素。在大多数情况下,这可能是一个有效的假设,但需要提防。
cmbuckley 2013年

1
@leepowers当然,还有一个相同的问题array_shift(),那就是它期望引用被修改:-)
cmbuckley

1
@ user198729您可以$intermediate通过使用额外的一对括号来避免该值。$el = array_shift( ( get_arr() ) );。参见stackoverflow.com/questions/9848295/…–
Chloe,

1
@Chloe这是我看到的最简单的代码解决方案!谢谢!
hargobind '16

7

$instance->find() 返回对变量的引用。

当您尝试将此引用用作函数的参数时,无需先将其存储在变量中即可获取报告。

这有助于防止内存泄漏,并且在以后的PHP版本中可能会成为错误。

如果您的第二个代码块编写如下(请注意&函数签名中的),则会抛出错误:

function &get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

因此,一个快速(但不太好)的修复方法是:

$el = array_shift($tmp = $instance->find(..));

基本上,您首先要对临时变量进行赋值,然后将变量作为参数发送。


它现在应该可以正常工作(选中)。为了返回引用,您必须在方法签名处声明它,而不是在返回语句中声明(我的错)。
萨吉2010年

不,我不能更改签名。@ pygorex1的中间变量可以解决这个问题,但是看起来很多余,不是吗?
user198729 2010年

我知道您不能更改签名,只需说明它是如何发生的。您必须使用临时(= intermediate)变量,但是您可以在同一行中使用它。看看我的第二段代码。
萨吉2010年

4
我尝试了您的第二个片段,但没有用。它只能在单独的一行中使用
user198729 2010年

3
确实。分配返回分配的值array_shift($tmp = $instance->find(..))$instance->find(..)to$tmp值赋值,然后将赋值传递给array_shift()-与传递$tmp自身不同,因此,这比没有赋值的原始情况更好。
菲尔2014年

6

错误的原因是内部PHP编程数据结构函数array_shift()[php.net/end]的使用。

该函数将数组作为参数。尽管array_shift()在手册的原型中指出了“&”号,但该功能的扩展定义后没有任何警告文档,也没有任何明显的解释表明该参数实际上是通过引用传递的。

也许这是/理解/。但是,我不理解,因此我很难检测到错误原因。

重现代码:

function get_arr()
{
    return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);

3

这段代码:

$monthly_index = array_shift(unpack('H*', date('m/Y')));

需要更改为:

$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);


0

好吧,在类似的明显情况下,您总是可以通过在函数前面使用“ @”来告诉PHP禁止显示消息。

$monthly_index = @array_shift(unpack('H*', date('m/Y')));

用这种方法抑制所有错误可能不是最佳的编程实践之一,但是在某些情况下(如这种情况),它很方便并且可以接受。

结果,我确信您的朋友“系统管理员”会对污染程度较小的文件感到满意error.log


我不知道是谁拒绝了这个答案,但是提出的解决方案确实有效,并且是PHP标准技术。真令人失望...下次我可能不再回答问题... :(
朱利奥·马尔基

5
我认为这是因为抑制错误消息并不能解决代码问题。当这种错误类型在将来的PHP版本中从E_STRICT更改为E_ERROR且您的代码现在无法运行并且也不产生任何错误/输出时,您将怎么办?
路加福音

@TinoDidriksen,我理解并同意为某些“坏习惯”提供建议的理由,尤其是对于新生代。但是,存在一种资源可以在安全使用且适用于建议的上下文的情况下使用。如果要取消错误抑制器“ @”,则应将其从语言本身中删除。与“ eval”相同(它可能是邪恶的,但有其用途)。我反对的不是关于某些资源的使用,而是建议的概括。在特定情况下,即使是用于调试目的,使用它也不会有任何危害。
朱利奥·马尔基
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.