奇怪的行为三元运算符[关闭]
Posted
技术标签:
【中文标题】奇怪的行为三元运算符[关闭]【英文标题】:strange behaviour ternary operator [closed] 【发布时间】:2012-10-20 00:02:32 【问题描述】:来自 C# 我必须用 php 做一个项目。
我正在使用此代码:
$transport = 'T';
$vehicle = (
( $transport == 'B' ) ? 'bus' :
( $transport == 'A' ) ? 'airplane' :
( $transport == 'T' ) ? 'train' :
( $transport == 'C' ) ? 'car' :
( $transport == 'H' ) ? 'horse' :
'feet' );
echo $vehicle;
我希望它打印train
,但我得到horse
。键盘示例:http://codepad.org/rWllfrht
谁能解释这种奇怪的行为?
【问题讨论】:
不要使用该代码。这是对三元运算符的可怕、不可原谅的滥用。如果我在生产中发现该代码,我会立即将其删除并与作者进行非常严厉的言辞。使用switch
语句。
这段代码几乎一字不差地取自***页面en.wikipedia.org/wiki/%3F:#PHP,它解释了发生了什么。我打电话给巨魔:p
最丑陋,最难以理解的三元用法我不高兴看到。它依赖于我不想调试的奇怪的关联级联。正如其他人所说,使用开关。
噢噢!看看所有漂亮的反对票!维基用户一定很生气,因为没有给出归属:P
从我读到的 wiki 中,这是一个公认的错误。我仍然没有 100% 明白。这是一个多么好的网站。有效问题,3 次反对票,21 次咆哮不要使用那个,没有解释。欢迎使用 ***!
【参考方案1】:
没有看到任何关于为什么你的代码在其他答案中被破坏的解释,所以这里是一个快速的破败。
这里的问题更明显的是你添加了括号来使计算的隐含顺序更加明确。
这是您的代码的精简版本,它仍然会产生“马”的错误结果:
$t = 'T';
( $t == 'T' ) ? 'train' :
( $t == 'C' ) ? 'car' :
( $t == 'H' ) ? 'horse' : 'feet';
首先,让我们展开它:
( $t == 'T' ) ? 'train' : ( $t == 'C' ) ? 'car' : ( $t == 'H' ) ? 'horse' : 'feet';
接下来,我将在已经存在隐式括号的地方添加显式括号:
((($t == 'T') ? 'train' : ($t == 'C')) ? 'car' : ($t == 'H')) ? 'horse' : 'feet';
接下来,我们可以解决您的比较问题:
((true ? 'train' : false) ? 'car' : false) ? 'horse' : 'feet';
你应该开始明白为什么这是坏的。第一个三元将true ? 'train' : 'false'
评估为'train'
:
('train' ? 'car' : false) ? 'horse' : 'feet';
因为'train'
在转换为布尔值时为真,所以现在的结果是'car'
:
'car' ? 'horse' : 'feet';
再一次,因为非空字符串是“真”,所以结果现在是“马”。所以,第一次true
出现在你可怕的嵌套 case 语句中时,结果将级联所有剩余的语句,丢弃下一个运算符的“true”分支的前一个值。
解决方案是避免此代码。这是一种过于聪明的尝试,结果是一个破碎的、难以理解的混乱。绝对没有理由使用它。选择一个switch
语句,它专门为您想要做的事情而设计。
【讨论】:
在任何合理的语言中都能正常工作(Java、C#、C++)。记录在案的错误不是功能造成的。 为了更好的衡量标准,这里是 javascript、Perl 和 Ruby。我还没有找到一种以“PHP 方式”完成它的语言。不过,+1 用于解释这里发生了什么。 “PHP 方式”是一个公认的错误,它仍然存在以实现向后兼容性,即使跨主要版本也是如此。我不希望在任何其他由理智的作者编写的语言中找到它。 它在任何语言中都令人困惑,几乎任何语言都会提供更好的结构,旨在以清晰的方式做到这一点。 微薄,你说这不是问题下评论中的错误。我相信这是一个错误,并没有像你在那里所说的那样为向后兼容而修复。 @ChrisMiller 我并不是说没有更好的方法可以用任何语言做到这一点,只是 PHP 处理它的方式非常违反直觉。【参考方案2】:由于 PHP 语言语法中的错误,这无法按预期工作,如下所示:http://en.wikipedia.org/wiki/%3F:#PHP
这是一个可以工作的简单版本:
$transport = 'T';
$vehicle = (
( $transport == 'B' ? 'bus' :
( $transport == 'A' ? 'airplane' :
( $transport == 'T' ? 'train' :
( $transport == 'C' ? 'car' :
( $transport == 'H' ? 'horse' :
'feet' ))))));
echo $vehicle;
但正如其他人所说,我同意这不是最好的方法。您可以使用 switch case、if else if 或关联数组,并且更具可读性。
【讨论】:
【参考方案3】:这是 PHP 的一种“按预期工作,即使它显然是错误的”行为。它不会以这种方式关联,因此虽然此代码适用于大多数其他语言,但它会在 PHP 中失败。课?学会在不寻常的关联范式上使用括号。第二课?三元不是灵丹妙药,虽然它既美观又紧凑,但只能在可读时使用。恕我直言,嵌套的三元语句很丑。
【讨论】:
【参考方案4】:我不确定您为什么选择使用这种形式的语法,正如 comment 中提到的那样,这将是调试的一场噩梦……开关盒在这里可能是更好的选择 -
$vehicle = '';
switch($transport)
case 'B' :
$vehicle = 'bus';
break;
case 'A' :
$vehicle = 'airplane';
break;
...
default:
// undefined cases
break;
参考资料 -
switch statement
【讨论】:
不知道为什么这被否决了......这是最合适的开发人员会实施的解决方案! 它没有回答问题(这是在寻找解释,而不是替代方案) @que - 有时解释是“你做错了”。除了那个解释 - 我已经给出了一个替代方案。 这是我的意思。【参考方案5】:如果您想做这样的事情,请学会爱上括号:
$vehicle = ( ( $transport == 'B' ) ? 'bus' :
(( $transport == 'A' ) ? 'airplane' :
(( $transport == 'T' ) ? 'train' :
(( $transport == 'C' ) ? 'car' :
(( $transport == 'H' ) ? 'horse' :'feet')))) );
由于 PHP 对三元 http://php.net/manual/en/language.operators.comparison.php 的操作顺序,需要清楚地包含三元的每个右手边。
顺便说一下,从那个页面他们明确建议不要像这样堆叠它们......
注意:建议您避免“堆叠”三元表达式。在单个语句中使用多个三元运算符时 PHP 的行为并不明显:
【讨论】:
@jackflash 并不是说它很好,但它使可怕的三元工作。 指向实际问题的唯一答案,即使您可以稍微解释一下不带括号的表达式中发生了什么。 @user1782842 我原来的答案忘记了括号,现在已经修复了。 @Ray 这样做时会发生什么......你忘记了括号:) 无论如何,OP 只是在欺骗我们。【参考方案6】:我不建议你使用这样的代码,但出于教育目的应该是
$transport = 'T';
$vehicle = (
($transport == 'B') ? 'bus' :
(($transport == 'A') ? 'airplane' :
(($transport == 'T') ? 'train' :
(($transport == 'C') ? 'car' :
(($transport == 'H') ? 'horse' : 'feet'))))
);
echo $vehicle;
更好的代码应该是
$transport = 'T';
switch ($transport)
case 'A' :
$vehicle = 'airplane';
break;
case 'B' :
$vehicle = 'bus';
break;
case 'C' :
$vehicle = 'car';
break;
case 'H' :
$vehicle = 'horse';
break;
case 'T' :
$vehicle = 'train';
break;
default :
$vehicle = 'teleportation';
break;
echo $vehicle;
或者更好:
$transport = 'T';
$array = array('A'=>'airplane','B'=>"bus","C"=>"car","H"=>"horse","T"=>"train");
echo isset($array[$transport]) ? $array[$transport] : null;
或者,使用数据库:
SELECT name FROM transpotationTable WHERE someKey = '$transport'
【讨论】:
在 PHP 7 中,你甚至可以这样写:['A'=>'airplane','B'=>"bus","C"=>"car","H"=>"horse","T"=>"train"][$transport] ?? null
噢@Andrea。那是不错。
或者对于 OP 的情况:['A'=>'airplane','B'=>"bus","C"=>"car","H"=>"horse","T"=>"train"][$transport] ?? "feet"
以上是关于奇怪的行为三元运算符[关闭]的主要内容,如果未能解决你的问题,请参考以下文章