PHP SimpleXML如何作为表达式进行求值?

时间:2014-11-26 18:19:30

标签: php xml casting expression simplexml

考虑这个PHP代码:

<?php
$xmlString = 
  '<'.'?xml version="1.0" encoding="UTF-8"?'.'>' .
  '<rootEl>' .
      '<a attrA="valA">xxx</a>' .
      '<b attrB="valB"/>' .
      '<c>oink</c>' .
      '<d/>'.
      '<e>' .
          '<f>zzz</f>' .
      '</e>' .
  '</rootEl>';

$xml = simplexml_load_string( $xmlString );
foreach ( $xml->children() as $child ) {
    echo "\$CHILD [" . $child->getName() . "]: " . $child->asXML();
    echo "\n";
    $insideIf1 = false;
    if ($child) { $insideIf1 = true; }
    $insideIf2 = false;
    if (true == $child) { $insideIf2 = true; }
    $insideIf3 = false;
    if ((boolean)$child) { $insideIf3 = true; }

    echo "    - if(\$CHILD) return \"true\"; else return \"false\"; :                     " . (($insideIf1)?"true":"false")."\n";
    echo "    - if(true == \$CHILD) return \"true\"; else return \"false\"; :             " . (($insideIf2)?"true":"false")."\n";
    echo "    - if((boolean)\$CHILD) return \"true\"; else return \"false\"; :            " . (($insideIf3)?"true":"false")."\n";

    echo "    - ((\$CHILD)?\"true\":\"false\"):                                           " . (($child)?"true":"false")."\n";
    echo "    - ((true == \$CHILD)?\"true\":\"false\"):                                   " . ((true == $child)?"true":"false")."\n";
    echo "    - (((boolean)\$CHILD)?\"true\":\"false\"):                                  " . (((boolean)$child)?"true":"false")."\n";

    echo "\n";
}

根据PHP文档(在线,请参阅http://php.net/manual/en/control-structures.if.php):

  

如关于表达式的部分所述,将评估表达式   到它的布尔值。如果expression的计算结果为TRUE,那么PHP将会   执行语句,如果计算结果为FALSE - 它将忽略它。   有关哪些值评估为FALSE的更多信息,请参阅   '转换为布尔值'部分。

此解释的“转换为布尔”部分说明:

  

转换为布尔值   转换为布尔值时,以下值被视为FALSE:   ... ... omissis

     

从空标记

创建的SimpleXML对象

如果执行上面的代码,这些是PHP 5.5.9-1ubuntu4.5(cli)上的结果:

$CHILD [a]: <a attrA="valA">xxx</a>
- if($CHILD) return "true"; else return "false"; :                     true
- if(true == $CHILD) return "true"; else return "false"; :             true
- if((boolean)$CHILD) return "true"; else return "false"; :            true
- (($CHILD)?"true":"false"):                                           true
- ((true == $CHILD)?"true":"false"):                                   true
- (((boolean)$CHILD)?"true":"false"):                                  true

$CHILD [b]: <b attrB="valB"/>
- if($CHILD) return "true"; else return "false"; :                     true
- if(true == $CHILD) return "true"; else return "false"; :             false
- if((boolean)$CHILD) return "true"; else return "false"; :            true
- (($CHILD)?"true":"false"):                                           true
- ((true == $CHILD)?"true":"false"):                                   false
- (((boolean)$CHILD)?"true":"false"):                                  true

$CHILD [c]: <c>oink</c>
- if($CHILD) return "true"; else return "false"; :                     false
- if(true == $CHILD) return "true"; else return "false"; :             true
- if((boolean)$CHILD) return "true"; else return "false"; :            false
- (($CHILD)?"true":"false"):                                           false
- ((true == $CHILD)?"true":"false"):                                   true
- (((boolean)$CHILD)?"true":"false"):                                  false

$CHILD [d]: <d/>
- if($CHILD) return "true"; else return "false"; :                     false
- if(true == $CHILD) return "true"; else return "false"; :             false
- if((boolean)$CHILD) return "true"; else return "false"; :            false
- (($CHILD)?"true":"false"):                                           false
- ((true == $CHILD)?"true":"false"):                                   false
- (((boolean)$CHILD)?"true":"false"):                                  false

$CHILD [e]: <e><f>zzz</f></e>
- if($CHILD) return "true"; else return "false"; :                     true
- if(true == $CHILD) return "true"; else return "false"; :             false
- if((boolean)$CHILD) return "true"; else return "false"; :            true
- (($CHILD)?"true":"false"):                                           true
- ((true == $CHILD)?"true":"false"):                                   false
- (((boolean)$CHILD)?"true":"false"):                                  true

儿童元素“b”和“d”是空的,因此我期待“假”,而“a”,“c”,“e”不是空的,所以我期待“真实”。

正如出来的那样,PHP文档中的该语句绝对不正确,并且行为甚至看起来不一致:对布尔值的隐式或显式强制转换的行为方式不同(参见元素“c”的情况)如果将简单的SimpleXML对象用作“if”条件表达式(“if”和“三元运算符”),那么表达式的某种方式与转换为布尔值的方式不同。

有没有人知道这里发生了什么?

1 个答案:

答案 0 :(得分:0)

首先,让我们丢弃你的一些代码。

foreach ( $xml->children() as $child ) {
    echo "\$CHILD [" . htmlspecialchars($child->getName()) . "]: " . htmlspecialchars($child->asXML());
    echo "\n";
    $insideIf1 = false;
    if ($child) { $insideIf1 = true; }
    $insideIf2 = false;
    if (true == $child) { $insideIf2 = true; }
    $insideIf3 = false;
    if ((boolean)$child) { $insideIf3 = true; }

    var_dump($child);
  //  echo intval($child)."\n";
    echo 'VALUE EVALUATES TO: '. $child."\n";
    echo "    - if(\$CHILD) return \"true\"; else return \"false\"; :                     " . (($insideIf1)?"true":"false")."\n";
    echo "    - if(true == \$CHILD) return \"true\"; else return \"false\"; :             " . (($insideIf2)?"true":"false")."\n";
    echo "    - if((boolean)\$CHILD) return \"true\"; else return \"false\"; :            " . (($insideIf3)?"true":"false")."\n";
// This part evaluated exactly same as above. So no need to make confusion
    echo "\n";
}

下一步:

第一次和第三次测试
那些基本相同。如果对象具有属性,则该对象被视为true。所以基本上没有属性的xml标签没有属性(只是var_dump它们)。 没有属性的对象(没有属性但是注意它们可以有值 - 由迭代器返回)被视为错误:cd

第二次测试
另一方面,该测试不测试对象本身。但是它从cast转换为:int,bool和string返回的所有值。 其中一项测试需要__toString魔法。哪个返回值。然后它评估为true(元素ac

所以它不是随机的,但在考虑它是真还是假时有特殊规则。

忘记添加

  

注意:SimpleXML已经规定了向大多数方法添加迭代属性的规则。无法使用var_dump()或其他任何可以检查对象的内容来查看它们。

这种“奇怪”的行为是它实施内行者的结果。

编辑:
正如您在评论中所述,是什么让您分析这种行为。我认为你永远不应该选择if($obj)来检查SimpleXML对象 而是使用SimpleXML::attributes()strval进行所有检查。然后你确定你在检查什么。

EDIT2:
$ xmlObject如果具有属性OR Chilren (子节点),则认为是真的(不为空)(运行正常) 要检查对象是否具有值,请将其强制转换为字符串。

在这种情况下,空并不意味着它是否具有值,只有它具有子项或属性。