php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #68507 SimpleXML objects casted to boolean inconsistently
Submitted: 2014-11-26 18:28 UTC Modified: 2017-01-11 11:27 UTC
From: dmitri dot sologoubenko at gmail dot com Assigned: requinix (profile)
Status: Closed Package: SimpleXML related
PHP Version: 5.5.19 OS: Ubuntu
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: dmitri dot sologoubenko at gmail dot com
New email:
PHP Version: OS:

 

 [2014-11-26 18:28 UTC] dmitri dot sologoubenko at gmail dot com
Description:
------------
As per PHP documentation (online, see http://php.net/manual/en/control-structures.if.php):

> As described in the section about expressions, expression is evaluated to 
> its Boolean value. If expression evaluates to TRUE, PHP will execute 
> statement, and if it evaluates to FALSE - it'll ignore it. More 
> information about what values evaluate to FALSE can be found in the 
> 'Converting to boolean' section.

The "Converting to boolean" section of this explanation states:

> Converting to boolean 
> When converting to boolean, the following values are considered FALSE: 
> ...omissis...
> SimpleXML objects created from empty tags

Children elements "b" and "d" ARE empty (no content), therefore I was expecting "false", and "a", "c", "e" ARE NOT empty, so I was expecting "true".

As is comes out, that statement in PHP documentation is absolutely NOT true, and the behaviour doesn't even seem consistent: implicit or explicit casts to boolean don't behave the same way (see case of element "c"), and if the bare SimpleXML object is used as "if" conditional expression (both "if" and ternary operator), somehow that conditional expression evaluates differently from a cast to boolean.


Test script:
---------------
<?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";
}


Expected result:
----------------
$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"; :                     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 [c]: <c>oink</c>
    - 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 [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"; :             true
    - if((boolean)$CHILD) return "true"; else return "false"; :            true
    - (($CHILD)?"true":"false"):                                           true
    - ((true == $CHILD)?"true":"false"):                                   true
    - (((boolean)$CHILD)?"true":"false"):                                  true


Actual result:
--------------
$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


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-11-26 18:37 UTC] dmitri dot sologoubenko at gmail dot com
Seems like the general rule - here - is, for bare objects as conditional expressions:

the SimpleXML object is considered "true" only and only if it:
  a) has content or children, and also
  b) has attributes
otherwise it is considered "false" (if block not executed).

Comparison to true follows different rules, and so does explicit casting to boolean. Only comparison to boolean follows the description in documentation (and that's implicit casting to boolean!).
 [2017-01-11 11:19 UTC] jdomenechbborges at gmail dot com
The issue seems to be solved slowly in the next releases starting from PHP 5.4 and in PHP 7.0 seems completely solved.


Test site
---------
http://phptester.net/


Result in 5.6
-------------
$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'; : 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 [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


Result in 7.0
-------------
$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'; : 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 [c]: <c>oink</c>
- 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 [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'; : true
- if((boolean)$CHILD) return 'true'; else return 'false'; : true
- (($CHILD)?'true':'false'): true
- ((true == $CHILD)?'true':'false'): true
- (((boolean)$CHILD)?'true':'false'): true
 [2017-01-11 11:27 UTC] requinix@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: requinix
 [2017-01-11 11:27 UTC] requinix@php.net
https://3v4l.org/ilcnA

<b> is not empty because it has an attribute.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Apr 27 14:01:30 2024 UTC