用于取消引用函数结果的 PHP 语法

Posted

技术标签:

【中文标题】用于取消引用函数结果的 PHP 语法【英文标题】:PHP syntax for dereferencing function result 【发布时间】:2010-10-19 01:41:44 【问题描述】:

背景

在我经常使用的所有其他编程语言中,对函数的返回值进行操作很简单,而无需声明一个新变量来保存函数结果。

然而,在 php 中,这似乎并不那么简单:

example1(函数结果为数组)

<?php 
function foobar()
    return preg_split('/\s+/', 'zero one two three four five');


// can php say "zero"?

/// print( foobar()[0] ); /// <-- nope
/// print( &foobar()[0] );     /// <-- nope
/// print( &foobar()->[0] );     /// <-- nope
/// print( "$foobar()[0]" );    /// <-- nope
?>

example2(函数结果是一个对象)

<?php    
function zoobar()
  // NOTE: casting (object) Array() has other problems in PHP
  // see e.g., http://***.com/questions/1869812
  $vout   = (object) Array('0'=>'zero','fname'=>'homer','lname'=>'simpson',);
  return $vout;


//  can php say "zero"?       
//  print zoobar()->0;         //  <- nope (parse error)      
//  print zoobar()->0;       //  <- nope                    
//  print zoobar()->'0';     //  <- nope                    
//  $vtemp = zoobar();         //  does using a variable help?
//  print $vtemp->0;         //  <- nope     

【问题讨论】:

为了方便不滚动到后面答案的读者,PHP 5.4 中添加了数组取消引用(在此评论时处于测试阶段)... 注意:此问题被错误地标记为与 array dereferencing 重复。 这个问题不是重复的,因为它不仅仅与数组有关。 PHP 函数可以返回任何值类型,而不仅仅是数组(参见原帖中的示例 2,其中函数结果是一个对象,而不是数组)。 对于那些懒得通读所有答案的人来说,最“漂亮”的解决方案是call_user_func(function($a, $b)return $a[$b];, $arr, $offset)。亚军奖颁给current(array_slice($arr, $offset, 1)) @Pacerier 你用什么标准比另一个更“漂亮”?一个更有效率吗?坦白说,第二种选择写起来更快更容易。 【参考方案1】:

PHP 无法访问函数的数组结果。有些人称之为问题,有些人只是接受这是语言的设计方式。所以 PHP 让你创建不必要的变量只是为了提取你需要的数据。

所以你需要这样做。

$var = foobar();
print($var[0]);

【讨论】:

我意识到我对此仍然非常陌生,但为什么会出现这样的问题?这...对我来说很有意义,您需要创建一个变量来保存一个值/结果;虽然不可否认:非常新 有些人称之为问题,但这正是语言的设计方式。其他语言的设计方式使这成为可能,来自这些语言的人认为这是一个问题。 这是一个问题,因为如果您有一个返回结构化变量或对象的函数,很容易忘记您的位置。例如,如果您的变量中有 $data['tvshow']['episodes'][1]['description'] 作为有效地址怎么办? 真的,语言在允许流畅使用结果方面似乎是一致的,那么为什么不使用数组呢?似乎他们同意了。 @ÓlafurWaage,不,PHP 不是这样设计的。这是一个疏忽,而不是“只是语言的设计方式”。正是因为这是一个问题,它在 PHP 5.4 中被修复【参考方案2】:

好吧,您可以根据情况使用以下任何一种解决方案:

function foo() 
    return array("foo","bar","foobar","barfoo","tofu");

echo(array_shift(foo())); // prints "foo"
echo(array_pop(foo())); // prints "tofu"

或者您可以使用 list() 从返回的数组中获取特定值:

list($foo, $bar) = foo();
echo($foo); // prints "foo"
echo($bar); // print "bar"

编辑:我之前给出的 each() 示例代码不正确。 each() 返回一个键值对。所以使用 foreach() 可能更容易:

foreach(foo() as $key=>$val) 
    echo($val);

【讨论】:

在 PHP 5.5.10 中它仍然抛出以下错误:“严格标准:只有变量应该在 php 中通过引用传递”。可笑。 @ZsoltGyöngyösi,该错误出现在早在 PHP 5.05 中。 请参阅 3v4l.org/voQIS。此外,性能说明:array_pop 可能很快,因为您只需删除最后一个元素,但 array_shift 非常慢,因为它需要通过将数字索引向下移动 1 来更改 all .【参考方案3】:

编写一个实现相同功能的包装函数。由于 PHP 的简单类型转换,这可能是非常开放的:

function array_value ($array, $key) 
return $array[$key];

【讨论】:

最有效的函数将在这里使用数组引用。示例:function array_value(&amp;$a,$k) $b = &amp;$a; return $b[$k]; 我认为你可以通过告诉函数通过引用返回,即函数 &array_value (... @KyleFarris,我非常怀疑现在效率更高,甚至将来也不会。 (还有test results here。)这是因为1)语言规范主义者不鼓励在不需要数组引用时使用数组引用,2)当前和未来的语言实现者试图优化一般用例,其中大部分来自这样的处方。【参考方案4】:

这行得通吗?

 return ($foo->getBarArray())[0];

否则,您可以发布 getBarArray() 函数吗?从您目前发布的内容来看,我不明白为什么这不起作用。

【讨论】:

不,那也行不通。无论函数如何,它都会引发“意外 [”错误。 这里有 28 个答案。如果您可以删除此答案(实际上,这甚至不是答案),此页面的访问者将感谢您,因此我们有更多的信号和更少的噪音。【参考方案5】:

不幸的是,没有办法做到这一点,尽管在大多数其他编程语言中都有。

如果你真的想做一个单行,你可以创建一个名为 a() 的函数并执行类似的操作

$test = a(func(), 1); // second parameter is the key.

但除此之外,PHP 不支持 func()[1]。

【讨论】:

哦,哇,我不知道。你知道为什么这不起作用吗? func() 本质上不应该是具有返回值的数组类型,因此 [1] 作用于数组吗?还是 PHP 解析不好? PHP 不像其他语言那样解析它,所以你必须先将它定义为一个变量。 @Kouroki Kaze:array_slice 仍然返回一个数组,即使切片会产生单个值。您可以将它与 current 结合使用,但是对于单行来说这开始有点长了。 ;-) @James,这很长,但这不是重点。它仍然是一行,并且有效。【参考方案6】:

这太牵强了,但如果你真的需要它在一行中:


return index0( $foo->getBarArray() );

/* ... */

function index0( $some_array )

  return $some_array[0];


【讨论】:

【参考方案7】:

正如其他人所提到的,这是不可能的。 PHP 的语法不允许这样做。但是,我确实有一个建议可以从另一个方向解决问题。

如果您可以控制getBarArray 方法并且可以访问 PHP 标准库(安装在许多 PHP 5.2.X 主机上并且默认安装在 PHP 5.3 上),您应该考虑返回 @987654321@ 而不是原生 PHP 数组/集合。 ArrayObjects 有一个 @987654322@ 方法,可用于检索任何索引,因此您的代码可能类似于

<?php
class Example 
    function getBarArray() 
        $array = new ArrayObject();
        $array[] = 'uno';
        $array->append('dos');
        $array->append('tres');
        return $array;
    


$foo = new Example();
$value = $foo->getBarArray()->offsetGet(2);

如果您需要原生数组/集合,您可以随时转换结果。

//if you need 
$array = (array) $foo->getBarArray();

【讨论】:

【参考方案8】:

如果您只想返回数组中的第一项,请使用 current() 函数。

return current($foo->getBarArray());

http://php.net/manual/en/function.current.php

【讨论】:

不,不能保证current 当前指向第一个元素。请参阅3v4l.org/OZLjR 和3v4l.org/kEC9H 示例,其中盲目调用current 确实会给您非第一项。 无论何时拨打current都必须先拨打reset,否则要做好麻烦的准备。【参考方案9】:

实际上,我已经编写了一个允许这种行为的库:

http://code.google.com/p/php-preparser/

适用于一切:函数、方法。缓存,所以和 PHP 本身一样快 :)

【讨论】:

这是评论,不是答案。这里有 28 个答案。如果您可以将此答案转换为评论,此页面的访问者将感谢您。【参考方案10】:

经过进一步研究,我相信答案是否定的,这样的临时变量确实是处理从函数返回的数组的规范方法。

看起来这将从 PHP 5.4 开始改变。

另外,这个答案最初是针对这个版本的问题:

How to avoid temporary variables in PHP when using an array returned from a function

【讨论】:

这里有 28 个答案。如果您可以删除此答案,此页面的访问者将感谢您,以便我们有更多的信号和更少的噪音。【参考方案11】:

当然,您可以返回一个对象而不是数组并以这种方式访问​​它:

echo "This should be 2: " . test()->b ."\n";

但我没有找到用数组来做到这一点的可能性:(

【讨论】:

【参考方案12】:

如果它只是为了美观,那么如果您返回一个对象,则对象表示法将起作用。就内存管理而言,如果进行临时复制,则不会进行临时复制,而只会更改引用。

【讨论】:

【参考方案13】:

我通常的解决方法是使用这样的通用函数

 function e($a, $key, $def = null)  return isset($a[$key]) ? $a[$key] : $def; 

然后

  echo e(someFunc(), 'key');

另外,当您不需要时,这也避免了“未定义索引”警告。

至于foo()[x]不起作用的原因,答案很不礼貌,不打算在这里发表。 ;)

【讨论】:

你有没有碰巧发现自己在查看使用这种技术的代码时,并想知道(即使只是几毫秒),“现在这又做了什么?” 这仍然会创建一个临时的(实际上是 2 或 3 个),但它们在较低的范围内很快就会消失,所以这是一个奖励。 @BenDunlap,它是黑盒的。所以重要的是方法名称。 @user187291,你为什么说“答案很不礼貌”?【参考方案14】:

这些是解决问题的一些方法。

首先,如果您返回的变量数组不是集合的一部分,但每个变量都有不同的含义,则可以直接使用它来命名变量。

其他两种方法是返回值集合的结果。

function test() 
  return array(1, 2);
   
list($a, $b) = test();
echo "This should be 2: $b\n";

function test2() 
   return new ArrayObject(array('a' => 1, 'b' => 2), ArrayObject::ARRAY_AS_PROPS);

$tmp2 = test2();
echo "This should be 2: $tmp2->b\n";

function test3() 
   return (object) array('a' => 1, 'b' => 2);

$tmp3 = test3();
echo "This should be 2: $tmp3->b\n";

【讨论】:

【参考方案15】:

你可以使用参考:

$ref =& myFunc();
echo $ref['foo'];

这样,您实际上并没有创建返回数组的副本。

【讨论】:

【参考方案16】:

从 PHP 5.4 开始可以解除数组引用:

http://svn.php.net/viewvc?view=revision&revision=300266

示例(source):

function foo() 
    return array(1, 2, 3);

echo foo()[2]; // prints 3

使用 PHP 5.3 你会得到

Parse error: syntax error, unexpected '[', expecting ',' or ';' 

原答案:

这是beenaskedalreadybefore。答案是不。这是不可能的。

就这个话题致quoteAndi Gutmans:

这是一个众所周知的功能请求 但在 PHP 5.0 中不受支持。一世 不能告诉你它是否会是 支持的。它需要一些研究 和很多想法。

您还可以在 PHP Bugtracker 中找到此 request a number of times。有关技术细节,我建议您查看official RFC 和/或在PHP Internals 上询问。

【讨论】:

哇,很好的工作找到了这个问题的所有其他版本。我确实先看了一下,根据 *** 创建者的说法,这意味着值得拥有另一个版本的问题,以使其更易于谷歌搜索。 注意:这个问题被错误地标记为“已经问过”array dereferencing。 这个问题还没有被问过,因为它不仅仅与数组有关。 PHP 函数可以返回任何值类型,而不仅仅是数组(参见原帖中的示例 2,其中函数结果是一个对象,而不是数组)。【参考方案17】:

您不能在 PHP 中链接这样的表达式,因此您必须将 array_test() 的结果保存在一个变量中。

试试这个:

function array_test() 
  return array(0, 1, 2);


$array = array_test();
echo $array[0];

【讨论】:

【参考方案18】:

极度贫民区,但是,只能使用 PHP 来完成。这利用了一个 lambda 函数(在 PHP 5.3 中引入)。看到并感到惊讶(而且,咳咳,害怕):

function foo() 
    return array(
        'bar' => 'baz',
        'foo' => 'bar',


// prints 'baz'
echo call_user_func_array(function($a,$k)  
    return $a[$k]; 
, array(foo(),'bar'));

在大多数其他语言中,我们必须经历这么多美好的事情。

为了记录,我做了一些类似于诺尔特所做的事情。对不起,如果我让任何人的眼睛流血了。

【讨论】:

call_user_func 单独工作:3v4l.org/qIbtp。我们不需要call_user_func_array。顺便说一句,“ghetto”有很多含义……“ghetto”在这里是什么意思? 伙计,那是 4.5 年前的事了。谁知道我当时在想什么?可能只是意味着像“用ducktape和string放在一起”。【参考方案19】:

有三种方法可以做同样的事情:

    正如Chacha102所说,使用函数返回索引值:

    function get($from, $id)
        return $from[$id];
    
    

    然后,你可以使用:

    get($foo->getBarArray(),0);
    

    获取第一个元素,以此类推。

    一种使用 current 和 array_slice 的懒惰方式:

    $first = current(array_slice($foo->getBarArray(),0,1));
    $second = current(array_slice($foo->getBarArray(),1,1));
    

    使用相同的函数返回数组和值:

    class FooClass 
        function getBarArray($id = NULL) 
            $array = array();
    
            // Do something to get $array contents
    
            if(is_null($id))
                return $array;
            else
                return $array[$id];
            
    
    

    然后就可以获取整个数组和单个数组项了。

    $array = $foo->getBarArray();
    

    $first_item = $foo->getBarArray(0);
    

【讨论】:

current(array_slice($arr, $offset, 1)) 很好。因为新数组刚刚创建并且没有泄漏变量引用,所以current 保证 (by the specs) 指向第一个元素,而无需调用reset【参考方案20】:

这特别是数组取消引用,目前 php5.3 不支持,但在下一个版本 5.4 中应该可以。另一方面,在当前的 php 版本中可以取消引用对象。我也很期待这个功能!

【讨论】:

注意:这个问题被错误地标记为数组取消引用的重复。这个问题不是重复的,因为它不仅仅与数组有关。 PHP 函数可以返回任何值类型,而不仅仅是数组(参见原帖中的示例 2,其中函数结果是一个对象,而不是数组)。 @dreftymac 在 PHP 7 中,这最终被清理了,您现在可以在任何表达式中使用函数调用。【参考方案21】:

简答:

是的。 PHP中可以对函数的返回值进行操作,只要函数结果和你的PHP版本支持即可。

参考例子2:

//  can php say "homer"?      
//  print zoobar()->fname;     //  homer <-- yup

案例:

函数结果是一个数组并且你的PHP版本足够新 函数结果是一个对象,你想要的对象成员是可达的

【讨论】:

【参考方案22】:

以前在 PHP 5.3 中您必须这样做:

function returnArray() 
  return array(1, 2, 3);

$tmp = returnArray();
$ssecondElement = $tmp[1];

结果:2

从 PHP 5.4 开始,可以按如下方式取消引用数组:

function returnArray() 
  return array(1, 2, 3);

$secondElement = returnArray()[1];

结果:2

从 PHP 5.5 开始:

你甚至可以变得聪明:

echo [1, 2, 3][1];

结果:2

你也可以对字符串做同样的事情。这称为字符串解引用:

echo 'PHP'[1];

结果:H

【讨论】:

使用 PHP 已经有很长时间了,直到现在我才意识到 echo [1, 2, 3][1] 是一个东西。谢谢你的教育,朋友!

以上是关于用于取消引用函数结果的 PHP 语法的主要内容,如果未能解决你的问题,请参考以下文章

我在这 1 行代码中的语法有啥问题(指针、引用和取消引用哦,天哪)?

用于转义 MySQL 正则表达式语法的 PHP 函数

使用后期静态绑定引用 self 的 PHP 语法

PHP数组语法/运算符?

php strrev()函数 语法

php stripcslashes()函数 语法