I'm a bit confused about operator precedence actually.
Here is an example that doesn't match with the php official website
function getValue($key) {
$array = ['un' => 1, 'six' => 6];
if (array_key_exists($key, $array)) {
return $array[$key];
}
return null;
}
var_dump(null === $t1=getValue('un'));
var_dump(null === $t2=getValue('blablablaaaaaa'));
// And now I switch
var_dump($t3=getValue('un') === null);
var_dump($t4=getValue('blablablaaaaaa') === null);
OUTPUT
bool(false)
bool(true)
// After the switch
bool(false)
bool(true)
This is not what I was expecting for the two first outputs, because the comparison is higher-precedence than assignment. So php should've tried to compare null === $t1, or $t1 has not been declared yet, so a warning or error or whatever should've been raised. Or that didn't happen. Do you notice that PHP sometimes treat assignment before comparison although comparison is higher-precedence and thus should always be performed before assignment?. Any explanations about this?
My second question is: should this be avoided by always splitting up this kind of expression?
UPDATE
N.B
var_dump($t1, $t2, $t3, $t4);
// OUTPUT
int(1)
NULL
// After the switch
bool(false)
bool(true)
=== is non-associative.
Non-associative operators are operators that have no defined behavior when used in sequence in an expression.
And in docs
= has a lower precedence than most other operators, PHP will still allow expressions similar to the following: if (!$a = foo()), in which case the return value of foo() is put into $a.
So it can be assumed PHP (in any of the expression) will first assign the return value of the function to the variable and then compare.
Related
Why this line of code does not work in php like as in JS:
$id = [];
$id = null || [];
if (count($id)) {
echo 'd';
}
Why $id still is null instead empty array []? Therefore count() gives an error.
In PHP, logical operators like || always return a boolean, even if given a non-boolean output.
So your statement is evaluated as "is either null or [] truthy?" Since both null and an empty array evaluate to false, the result is boolean false.
There are however two operators which would do something similar to JS's ||:
$a ?: $b is short-hand for $a ? $a : $b; in other words, it evaluates to $a if it's "truthy", or $b if not (this is documented along with the ternary operator for which it is a short-hand)
$a ?? $b is similar, but checks for null rather than "truthiness"; it's equivalent to isset($a) ? $a : $b (this is called the null-coalescing operator)
<?php
// PHP < 7
$id = isset($id) ? $id : [];
// PHP >= 7
$id = $id ?? [];
As of PHP 7 and above
Null Coalesce Operator
Another helpful link
Watch out!
I find PHP's handling of empty to be highly questionable:
empty($unsetVar) == true (fabulous, no need to check isset as warning is suppressed!)
empty(null) == true
empty('') == true
All fine, until we get to this nonsense:
empty(false) == true. Wait, WHAT???
You've GOT to be kidding me. In no world should false be taken to mean the same thing as no value at all! There's nothing "empty" about a false assertion. And due to this logical fallacy, you cannot use empty to check ANY variable that might have a VALUE of false.
In my projects, I use a static method:
public static function hasValue($value) {
return isset($value) && !is_null($value) && $value !== '';
}
Of course, using this method, I no longer get the free warning suppression provided by empty, so now I'm also forced to remember to call the method above with the notice/warning suppression operator #:
if(self::hasValue(#$possiblyUnsetVar)) {}
Very frustrating.
Refactoring legacy code I have found various occurrences of the following construct:
((bool) ~~$field->req ? ' required' : '')
According to the manual the Tilde (~) in PHP is the bitwise not, which simple shifts all bits in a variable to their opposite.
If I shift all bits in a variable to their opposite and then shift it back, the variable should be exactly the same as it was before right? So why would somebody do this? Am I missing something?
It should be !! (it converts the value to a boolean) but it is not needed at all. I guess the original coder mistaken ~ for ! then they added (bool) in front of it to achieve the desired result (because, as you noticed in the question, ~~ is a no-op).
The ternary operator (?:) forces the evaluation of its first argument as boolean.
The boolean value of $field->req is the same as of !! $field->req and (bool) ~~$field->req (and (bool)$field->req btw).
I would remove the (bool) ~~ part completely to get smaller and cleaner code.
Edit by questioner: The only effect of ~~ in PHP is to cut of decimals from a float value.
See the following results:
$a = 2.123;
$b = -2.123;
$c = new stdClass();
$d = ["a",2,"c"];
$e = "lord";
$f = -3;
$g = false;
$h = null;
$j = -2.99;
$k = 2.99;
var_dump(~~$a);
var_dump(~~$b);
// var_dump(~~$c); // error
// var_dump(~~$d); // error
var_dump(~~$e);
var_dump(~~$f);
// var_dump(~~$g); // error
// var_dump(~~$h); // error
var_dump(~~$j);
var_dump(~~$k);
var_dump(!!$a);
var_dump(!!$b);
var_dump(!!$c);
var_dump(!!$d);
var_dump(!!$e);
var_dump(!!$f);
var_dump(!!$g);
var_dump(!!$h);
var_dump(!!$j);
var_dump(!!$k);
int(2) int(-2) string(4) "lord" int(-3) int(-2) int(2)
bool(true) bool(true) bool(true) bool(true) bool(true) bool(true)
bool(false) bool(false) bool(true) bool(true)
I find myself doing this kind of thing somewhat often:
$foo = true;
$foo = $foo && false; // bool(false)
With bitwise operators, you can use the &= and |= shorthand:
$foo = 1;
$foo &= 0; // int(0)
Given that bitwise operations on 1 and 0 are functionally equivalent to boolean operations on true and false, we can rely on type-casting and do something like this:
$foo = true;
$foo &= false; // int(0)
$foo = (bool)$foo; // bool(false)
...but that's pretty ugly and defeats the purpose of using a shorthand assignment syntax, since we have to use another statement to get the type back to boolean.
What I'd really like to do is something like this:
$foo = true;
$foo &&= false; // bool(false)
...but &&= and ||= are not valid operators, obviously. So, my question is - is there some other sugary syntax or maybe an obscure core function that might serve as a stand-in? With variables as short as $foo, it's not a big deal to just use $foo = $foo && false syntax, but array elements with multiple dimensions, and/or object method calls can make the syntax quite lengthy.
In a way you have answered your own question:
bitwise operations on 1 and 0 are functionally equivalent to boolean operations on true and false
Bearing in mind that PHP is a weakly typed language, so it is not necessary to typecast to and from strict boolean values as 1 and 0 are equivalent to true and false (except strict equality, see below).
Consider the following code, using your examples:
$foo = true;
$foo &= false;
if (!$foo) {
echo 'Bitwise works!';
}
$bar = true;
$bar = $bar && false;
if (!$bar) {
echo 'Boolean works!';
}
// Output: Bitwise works!Boolean works!
Given PHP's implicit type juggling, falsy values, and with the exception of strict equaltiy, I'm hard pressed to see where such shorthand operations of &&= and ||= would not yield the same result as &= and |=. Especially when evaluating boolean values. It's likely why such shorthands don't exist in PHP.
Update
Some quick benchmarks prove these are indeed equivalent, except for truthy arrays/objects:
<?php
$values = array(false, 0, 0.0, "", "0", array(), 12, "string", array(1));
foreach ($values as $value) {
$bit_test = true;
$bit_test &= $value;
$bool_test = true;
$bool_test = $bool_test && false;
if ($bit_test != $bool_test) {
echo 'Difference for: ';
var_dump($value);
}
}
// Output:
// Difference for: array(1) {
// [0]=>
// int(1)
// }
As Jason mentioned, bitwise operators will work and it will not be necessary to convert the result back to boolean, as PHP will already handle their value as a boolean properly.
If you want an alternative that does not use bitwise operators, for the sake of readability or if you want strict equality, you can use this method :
function OrOp(&$booleanVar, $conditions)
{
$booleanVar = $booleanVar && $conditions;
return $booleanVar;
}
Which means, you could change this :
$foo = $foo && false;
To this :
OrOp($foo, false);
It would also work with multiple conditions :
OrOp($foo, $condition1 && $condition2 && $condition3);
Right, &&= and ||= operators are indeed missing in PHP because bitwise operators can not be used as a replacement (without casting).
Here is an example you would expect to return true but returns false:
$a = true;
$a &= 10; // => returns 0 (false) because 1 & 10 = 0
The missing &&= operator would return true because 1 && 10 = true
$a = true;
$a &&= 10; // => $a would be true
This question already exists:
Closed 10 years ago.
Possible Duplicate:
php == vs === operator
An easy answer for someone I'm sure. Can someone explain why this expression evaluates to true?
(1234 == '1234 test')
Because you are using the == (similarity) operator and PHP is coercing the string to an int.
To resolve it use the === (equality) operator, which checks not only if the value is the same, but also if the data type is the same, so "123" string and 123 int won't be considered equal.
In PHP (and JavaScript -- which has slightly different behavior), the comparison operator == works differently than it does in strongly-typed languages like C or Java. The === operator has the behavior that you most likely expect. Below is a breakdown of the two comparison operators as they apply to PHP.
==
This operator is officially known as the "equality" operator, though that doesn't really fit the normal definition of the word "equality". It does what is known as a type-juggling comparison. If the types of both operands don't match (in your example, 1234 was an integer and 1234 test was a string), PHP will implicitly cast the operands to each others' types and test the equality of the newly-typed values as shown below:
<?php
var_dump( (int) 'hi' ); // int(0)
var_dump( (string) 0 ); //string("0")
var_dump( 'hi' == 0 ); // bool(true)
var_dump( (int) '1hi' ); // int(1)
var_dump( 1 == '1hi' ); // bool(true)
It has a counterpart (type-juggling) inequality operator, !=.
===
The === operator, known as the "identical" operator, performs a strict check of the value and type of both operands and does not perform any implicit casts. Therefore, "0" does not === 0 and "1234 test"does not === 1234.
<?php
var_dump( '1234 test' === 1234 ); // bool(false)
It has a counterpart (strict) inequality operator, !==.
Quirks
Note that the === operator has behavior on objects that is considered strange by some. Say we have class A and variables $a and $b as defined below:
<?php
class A {
public $property = 'default value';
}
$a = new A();
$b = new A();
You might expect var_dump($a === $b); to output bool(true). It will actually return false. When used upon objects, the operator actually checks if both operands are references to the same object. The == operator, in this instance, works by checking the properties of the objects, so $a == $b.
PHP Manual Links
Comparison operators
Type juggling
When casting a string to an integer, any numeric characters up to the first non-numeric character becomes the number. Thus '1234 test' becomes 1234 because space is not a numeric character.
Thus 1234 == '1234 test'
If you want to force a string comparison, you should cast to string:
''.(1234) == '1234 test' // implicit
(string) 1234 == '1234 test' // explicit
strval(1234) == '1234 test' // procedural
You are loosely comparing two different types of data (an integer and a string). PHP has a very detailed chart of how comparisons work in their system when using the loose comparison binary operator (==):
http://php.net/manual/en/types.comparisons.php
If you want to ensure that the types are also in sync, that is that they are both integers or both strings, use the strong type comparison operator (===).
Note that, when using this operator, this will also return false:
1234 === '1234'
If you are unsure of your types when comparing, you can couple the strong-type comparison with PHP typecasting:
$a = 1234;
$b = '1234';
if ($a === $b) { } // Will not fire, as it is false
if ((int)$a === (int)$b) { } // Will fire, as it is true
The double equals will tell php to parse an int from the string. The string will evaluate to the integer 1234. Use triple equals '===' to get exact comparison.
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically
var_dump(0 == "a"); // 0 == 0 -> true
I'm a bit of an optimization freak (at least by my definition) and this question has been bugging me for quite a while.
I'm wondering if PHP does some optimization on && and ||:
Take the following example:
$a = "apple";
$b = "orange";
if ($a == "orange" && $b == "orange") {
//do stuff
}
When that code executes, it will check if $a is equal to "orange." In this case it isn't. However, there is an && operator. Since the first part ($a == "orange") already returned false, will PHP still check if $b is equal to "orange?"
I have the same question for ||:
$a = "orange";
$b = "orange";
if ($a == "orange" || $b == "orange") {
//do stuff
}
When it checks if $a is equal to "orange," it returns true. Since that would make the || operator return true, will PHP even check the second part of the || (since we already know it will be true)?
Hopefully I am making sense here, and hopefully somebody has an answer for me. Thank you!
PHP uses short circuit evaluation with binary conditionals (such as &&, || or their constant equivalents), so if the result of evaluating the LHS means the RHS isn't necessary, it won't.
For example...
method_exists($obj, 'func') AND $obj->func();
...is an exploitation of this fact. The RHS will only be evaluated if the LHS returns a truthy value in this example. The logic makes sense here, as you only want to call a method if it exists (so long as you're not using __call(), but that's another story).
You can also use OR in a similar fashion.
defined('BASE_PATH') OR die('Restricted access to this file.');
This pattern is used often as the first line in PHP files which are meant to be included and not accessed directly. If the BASE_PATH constant does not exist, the LHS is falsy so it executes the RHS, which die()s the script.
Yes, PHP short-circuits the && and || operators, meaning that no, the right operand won't be evaluated if the value of the left operand means that it doesn't need to be evaluated. There's no need to optimize them. You can test it like this:
function one() {
echo "One";
return false;
}
function two() {
echo "Two";
return true;
}
one() && two(); // Outputs One
echo "\n";
two() || one(); // Outputs Two
Here's a demo. If there were no short-circuiting, you'd get:
OneTwo
TwoOne