用于取消引用函数结果的 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(&$a,$k) $b = &$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 语法的主要内容,如果未能解决你的问题,请参考以下文章