Is this a bug or am I wrong? - php

/**
* Returns nodes found by xpath expression
*
* #param string $xpath
* #return array
*/
public function getXpath($xpath)
{
if (empty($this->_xml)) {
return false;
}
if (!$result = #$this->_xml->xpath($xpath)) {
return false;
}
return $result;
}
This code is taken from Magento. You can checkout the specific file in their public svn:
http://svn.magentocommerce.com/source/branches/1.5/lib/Varien/Simplexml/Config.php
Now I think that (!$result = #$this->_xml->xpath($xpath)) can never ever evaluate to true and thus the return false statement can never happen.
Because the assignment of the return value of xpath, regardless of whether it is true or false to the variable $result always returns true and negated always returns false.
So this is a bug or a completely redundant code, or am i wrong?
FYI: I am currently debugging a problem where some config elements get "lost" and I assume the error is somewhere in there.

This is a weird way of building a condition like that, but I think it makes sense.
$result = will assign the result of the xpath operation to $result.
If that result is false (a value which xpath() will return in case of an error), the condition will match and the function will return false.

"Because the assignment of the return value of xpath to the variable $result always returns true" this statement is wrong and I have no idea why did you make this conclusion. Value of assignment operator is always equal to value that was assigned, so it can easily be false or true (($x = false) == false )

You can test that with
var_dump(!$result = FALSE); // TRUE
var_dump(!$result = array()); // TRUE
var_dump(!$result = array(1)); // FALSE
So if SimpleXml::xpath returns an empty array or FALSE, the Magento function will return FALSE. Negating an array will typecast it to boolean first. Empty Arrays typecasted to Boolean will be FALSE. Which means, when your XPath is syntactically correct, but did not find any results, Magento will return FALSE.

I find it helps to parenthesise the inner assignment like this:
if (! ($result = #$this->_xml->xpath($xpath)) ) {
Visually the assignment is now a sub-task and must be executed before being inverted. Without the extra parentheses it performs exactly the same, this just helps your own code reading.
Any assignment command returns the value being returned. This lets you do things like:
$a = $b = $c = $d = $e = 'A made-up value';
The new value of $e is being returned to $d, which is being returned to $c, and so on...

Related

Type juggling - Ressource to boolean

I stumbled upon this bit of code (written by someone else):
$result = do_stuff(); //returns false on failure, and mysql resource on success
return $result !== false;
If I get it right, it casts $result to a boolean and returns it.
How could we justify the use of $result !== false instead of (bool)$result? Is the former one more efficient?
I'm not sure what you mean by justify. Casting to bool will probably, depending on the result of do_stuff(), do the same, but is in fact something else and implies something else as well.
Example:
If you have 0 as returnvalue, casting to bool will make your function return false, but 0 !== false will return true. This is probably not a usecase you have here according to your comment, but it is implied.
So what you are saying here is "return false if $result is exactly false, otherwise always return true", while casting to bool will return false on any value of $result that is 'false-ish'.
My justification would be that this is clearer: you are implying that the result is either really false, or you actually consider it true.

My function always returns a boolean value instead of query results

I have an application that reads in one of its classes:
public function __construct()
{
global $config;
//Establish a connection to the database and get results set
$this->db = new Database("localhost",$config["dbuser"],$config["dbpass"],"student");
$this->records = $this->db->query("SELECT * FROM major") or die("ERROR: ".$this->db->error);
echo "<pre>".var_dump($this->records)."</pre>";
}
My problem is that var_dump shows that $this->records is a boolean. I've read the documentation and see that the SELECT query should return a result set. This is the only query used by the application.
The DB Class:
class Database
{
private $con;
public function __construct($server,$user,$password,$database)
{
$this->con = new mysqli($server,$user,$password,$database) or die ("FATAL ERR: ".mysqli_error());
}
public function query($qry)
{
if(!isset($this->con)) die("ERROR: YOU ARE TRYING TO QUERY BEFORE THE CONNECTION IS ESTABLISHED!");
return $this->con->query($qry) or die("FATAL ERROR:".$this->con->error);
}
}
Any ideas where I am going wrong?
That is incorrect. The assignment operator (=) has a higher precedence than the literal "or" operator. (Not to be confused with the "||" operator, which has a higher precedence than "=".)
There seems to be a bug in mysqli::query(), that causes it to return the boolean "true" in rare cases on a select statement. (Legal return values would be the boolean "false" or a mysqli_result object.)
You don't have to believe me on that assertion, you can easily try it yourself in a PHP shell:
$a = false or true;
var_dump($a);
Result:
bool (false)
That is because the above assignment is equivalent to:
($a = false) or true;
The issue in this question is not related to mysqli_query() function, but to the operator precedence.
There, the = operator has a higher precedence over OR operator, means assignment will be executed before OR (I explained this behavior in detail in the other answer, mysqli or die, does it have to die? )
The problem line is
return $this->con->query($qry) or die("FATAL ERROR:".$this->con->error);
Here, return operator has (for the obvious reason) the lowest precedence possible. Means that first PHP will execute the logical operator and then return its result - a boolean value!
But why doesn't the script actually die due to the logical operator execution?
Because of that logical operator execution optimization explained in the answer by the link above. PHP doesn't bother to actually execute the rightmost operator. It's enough that the leftmost one is already evaluates to true, means the whole expression will return true either way.
To solve this problem, the code of the function have to be changed this way:
public function query($qry)
{
$ret = $this->con->query($qry) or trigger_error($this->con->error);
return $ret;
}
while the calling code should be changed to simple
$this->records = $this->db->query("SELECT * FROM major");
echo "<pre>".var_dump($this->records)."</pre>";
call, as checking for the error for the second time makes no sense - this function will never return a false-like value.
The answer would be in what is called Magic Methods. One of PHP's magic methods is called __debugInfo(). If this Magic Method is defined, when you call var_dumb(obj), it will output whatever the function says to output. This is normally done to hide the private and protected functions of a parent class.

Successfully parsed SimpleXMLElement comparison to 'false' returning 'true'

I got a very awkward and specific issue with a simplexml evaluation.
The code:
$simplexml = simplexml_load_string($xmlstring);
var_dump($simplexml);
var_dump($simplexml == false); //this comparison
var_dump($simplexml) returns the actual structure of my simplexml but the comparison returns 'true' for this specific simplexml, which I can't show the structure because of my contract.
I'm sure that's very specifc issue 'cause I tried other XML strings and the comparison returns 'false'.
$simplexml = simplexml_load_string('<a><b>test</b></a>');
var_dump($simplexml); //returns the actual structure
var_dump($simplexml == false); //returns false
I solved the problem using the '===' operator, but I'm not satisfied with just making it work. I want to understand why the '==' operator returns true.
I read about the two operators and the SimpleXMLElement and on my sight it should return 'false' for both operators.
What are the possible reasons for a comparison between a succesfully parsed SimpleXMLElement and the boolean 'false' to return 'true'?
I this this is a better way to do it using boolean casting (bool)
$simplexml = simplexml_load_string('<a><b>test</b></a>');
var_dump($simplexml); //returns the actual structure
var_dump((bool) $simplexml); // Retuns true
var_dump((bool) $simplexml == false); //returns false
var_dump((bool) $simplexml === false); //returns false
Demo : http://codepad.viper-7.com/xZtuNG
=== compares values and type… except with objects, where === is only true if both operands are actually the same object! For objects, == compares both value (of every attribute) and type, which is what === does for every other type.
EDIT 1
See Latest Bug on Something similar https://bugs.php.net/bug.php?id=54547
var_dump($simplexml == false); //returns false
This is expected behavior and it is explained by data comparison via "loose" data typing. In PHP, NULL, zero, and boolean FALSE are considered "Falsy" values; everything else is considered "Truthy." Inside the parentheses, PHP performs an evaluation of the expression. In this case, PHP evaluates a comparison of the named variable OBJECT and the boolean FALSE. They are not the same, so the return value from the comparison is FALSE and this is what *var_dump()* prints.
You can use this to your advantage in the if() statement. Example:
$simplexml = SimpleXML_Load_String('<a><b>test</b></a>');
if ($simplexml) { /* process the object */ }
else { /* process the failure to load the XML */ }
Have a look here:
http://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting
It says that SimpleXML objects created from empty tags evaluate to false. Maybe that's what's going on?

Is it correct way to return value in PHP

I have very basic question regarding return value of a function, and checking the variable value.
function test($var1, $var2){
if ($var1 == $var2){
$var3 = "abc";
return $var3;
}
return false
}
$value = test($var1, $var2);
if ($value){
echo "Value is".$value; //should output abc.
} else {
echo "Not equal";
}
Is it ok to either return a value or return false? For example I am not returning TRUE, it is ok?
When i call the function, i store the return value in a variable $value. How can i check the function did return the $var3? Which of the if condition should be used?
if (!empty($value)) or if (isset($value)) or if ($value) or if (value != false)
Yes, it is common practice in PHP to return FALSE as an indicator of an error condition. (What constitutes an error is your own decision and depends on what the function is supposed to do.)
However, since PHP automatically casts values to Boolean that are of another type (like the empty string or 0, which evaluate to FALSE as well), you should do an explicit check for FALSE like this:
if ($value !== FALSE) ...
As Felix Kling notes in the comments, this is called "strict comparison" (or "identity comparison"). It checks if a value is identical to FALSE, where as != FALSE, == FALSE and if ($value) only check if a value could be interpreted as FALSE.
I'm not a PHP developer, but I don't think your first approach works.
There are other things than the boolean value false interpreted as false:
When converting to boolean, the following values are considered FALSE:
* the boolean FALSE itself
* the integer 0 (zero)
* the float 0.0 (zero)
* the empty string, and the string "0"
* an array with zero elements
* an object with zero member variables (PHP 4 only)
* the special type NULL (including unset variables)
* SimpleXML objects created from empty tags
http://php.net/manual/en/language.types.boolean.php
It's perfectly OK to return different data types.
If you want to check against false, use: if ($value !== false). If you get lost which condition to use, this will clarify it: http://www.php.net/manual/en/types.comparisons.php
Your function returns false, so I would go with that check: if ($value != false)
$var3 = "abc";
return $var3;
That's pointless. You're returning a value, not a variable. return "abc"; is perfectly fine.
Is it ok to either return a value or return false?
Yes, that's perfectly fine for a simple case such as this.
How can i check the function did return the $var3?
As said above, the function returns the value "abc", not $var3. You're saving it in a new variable $value. This variable is definitely set (you just created it right there), so there's no need for isset or empty. Just test whether its value is true or false (or whatever else you want to test for). So the way you're doing it in fine.
Yes, you can return pretty much anything from the function, or you can just "return" without returning anything. In your example, you'll get a string or "false" in return.
To check for false you either do if (!$variable) or if ($variable===false). Zero will return true if you do "if ($variable==false)" due to auto casting of zero to false (and any other positive number to true). Three "===" makes sure it really is false and nothing else. The isset($var) checks for existance, not value - and is not applicable to your example since your function will return a value or "false" and thus always exists.
The only right answer here is: it depends.
I always ask myself this question when creating a function like this. To answer it, I analyze what the function does, instead of what it returns.
For instance, if I have a getter, I expect to get a value, or nothing. In this case I often return null when nothing is found/something went wrong.
A test function like yours should return a boolean at all times, in my opinion. Returning a variable when you're checking for something to be true or false is semantically incorrect, I think.
Aside from the semantics: returning 0, false or null does not really matter when you're checking it with if (test($var1, $var2)), since it will all work the same. However, if you want some finer details, you want to do an identity check (===) rather than a equality check. In PHP this is sometimes the case, for instance strpos can return 0 or false, 0 being a match is found, and false is not. Therefore the following would fail:
// returns 0, which is casted to false, so the 'else' part is executed
if (strpos('a', 'abc')) {
// 'abc' contains 'a'
} else {
// 'abc' does not contain 'a'
}
So, long story short: it depends...

A php if statement with one equal sign...? What does this mean?

I'm attempting to troubleshoot a problem, and need to understand what this if statement is saying:
if ($confirmation = $payment_modules->confirmation()) {
All the resources I can find only show if statements with double equal signs, not single. Is this one of the shorthand forms of a php if? What is it doing?
(If it's actually wrong syntax, changing it to a double equal sign doesn't resolve the problem. As-is, in some scenarios it does return true. In the scenario I'm troubleshooting, it doesn't return true until after I refresh the browser.)
Any help is greatly appreciated!!!
It's a form of shorthand, which is exactly equivalent to this:
$confirmation = $payment_modules->confirmation();
if ($confirmation) {
}
This will first assign the value of $payment_modules->confirmation() to $confirmation. The = operator will evaluate to the new value of $confirmation.
This has the same effect as writing:
$confirmation = $payment_modules->confirmation();
if ($confirmation) {
// this will get executed if $confirmation is not false, null, or zero
}
The code works because an assignment returns the value assigned, so if $payment_modules->confirmation() is true, $confirmation will be set to true, and then the assignment will return true. Same thing for false.
That's why you can use a command to assign to many variables, as in a = b = 0. Assigns zero to b and returns that zero. Therefore, it becomes a = 0. And a receives zero and it will return that zero, which can or can not be used.
Sometimes people like to do an assignment and then check if the assignment went through okay. Pair this up with functions that return false (or equivalent) on failure, and you can do an assignment and a check at the same time.
In order to understand this, remember that assignments are a kind of expression, and so (like all expressions) have a return value. That return value is equal to whatever got put into the variable. That is why you can do something like
a = b = c = 0;
to assign all of those variables at the same time.
= means assignment ( $a = 1 ), == is for comparison ( true == false is false ). I think in your example it should use = because it assigns it to the return value of confirmation, which should be something that evaluates to true.
Try doing a var_dump:
var_dump( $payment_modules->confirmation() );
See what boolean it evaluates to, and from there you can troubleshoot. Post more code if you want more help.
class test() {
public function confirmation() { return true; }
}
$boolean = test::confirmation();
var_dump( $boolean );
Will equate to true

Categories