Рассмотрим этот код 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):
Как описано в разделе о выражениях, выражение оценивается
к его логическому значению. Если выражение имеет значение TRUE, PHP будет
выполнить оператор, и если он оценивается как ЛОЖЬ — он будет игнорировать его.
Более подробную информацию о том, какие значения оценивают в FALSE, можно найти в
раздел «Преобразование в логическое значение».
Раздел «Преобразование в логическое значение» этого объяснения гласит:
Преобразование в логическое значение
При преобразовании в логическое значение следующие значения считаются ЛОЖНЫМИ:
… omissis …
Если вы выполните код выше, это результаты на моем 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» пусты, поэтому я ожидал «false», а «a», «c», «e» НЕ пустые, поэтому я ожидал «true».
Как выясняется, это утверждение в документации PHP абсолютно НЕ соответствует действительности, и поведение даже не выглядит согласованным: неявное или явное приведение к логическому типу не ведет себя одинаково (см. Случай элемента «c»), и если голый объект SimpleXML используется как условное выражение «если» (как «если», так и троичный оператор), так как это выражение оценивается по-разному от приведения к логическому.
У кого-нибудь есть представление о том, что здесь происходит?
Прежде всего, давайте отбросим часть вашего кода.
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";
}
Следующий:
Первый и третий тест
Это в основном то же самое. Объект считается истинным, если у него есть свойства. Таким образом, у тега xml без атрибутов нет свойств (просто var_dump их).
Объекты без свойств (не имеющие атрибутов, НО ЗАМЕЧАНИЕ, ОНИ МОГУТ иметь значение, которое возвращает итератор), считаются ложными: c
, d
Второй тест
Этот тест, с другой стороны, не тестирует сам объект. Но все значения, возвращаемые им от приведения к: int, bool и string.
Один из этих тестов требует __toString
магический метод. Который возвращает значение. Затем он оценивает true
(Элементы a
а также c
)
Так что это не случайно, но имеет особые правила, считая его истинным или ложным.
Забыл добавить
Примечание: SimpleXML установил правило добавления итерационных свойств в большинство методов. Их нельзя просмотреть с помощью var_dump () или чего-либо еще, что может исследовать объекты.
Это «странное» поведение является следствием того, что он внедряет инераторов.
Редактировать:
Как вы указали в комментарии, что заставило вас проанализировать это поведение. Я думаю, что вы никогда не должны проверять объекты SimpleXML на if($obj)
основа.
Вместо этого используйте SimpleXML::attributes()
или же strval
сделать все проверки. Тогда вы уверены, что вы проверяете.
Edit2:
$ xmlObject считается истинным (не пустым), если имеет свойства OR
Chilren (подузлы) (это прекрасно работает)
Чтобы проверить, имеет ли объект значение, вы приводите его к строке.
В этом случае пустое значение не означает, что оно имеет значение, только если оно имеет дочерние элементы или свойства.
Других решений пока нет …