It's interesting to note that 'empty()' and 'boolean : if($x)'
are paired as logical opposites, as are 'is_null()' and 'isset()'.
以下的表格显示了 PHP 类型 和 比较运算符 在松散和严格比较时的作用。该补充材料还和 类型戏法 的相关章节内容有关。同时,大量的用户注释和 » BlueShoes 的工作也给该材料提供了帮助。
在使用这些表格之前,需要明白变量类型及它们的意义。例如,"42"
是一个字符串而
42
是一个整数。false
是一个布尔值而 "false"
是一个字符串。
注意:
HTML 表单并不传递整数、浮点数或者布尔值,它们只传递字符串。要想检测一个字符串是不是数字,可以使用 is_numeric() 函数。
注意:
在没有定义变量 $x 的时候,诸如
if ($x)
的用法会导致一个E_NOTICE
级别的错误。所以,可以考虑用 empty() 或者 isset() 函数来初始化变量。
注意:
某些数值操作会导致一个特殊值,可以用常量
NAN
表示。 无论是松散还是严格比较,这个值和其他任意值(包括它自身,但排除true
)比较时都会产生false
的结果, 例如NAN != NAN
和NAN !== NAN
。 导致NAN
的操作例子包括sqrt(-1)
、asin(2)
、acosh(0)
。
表达式 | gettype() | empty() | is_null() | isset() | boolean : if($x) |
---|---|---|---|---|---|
$x = ""; |
string | true |
false |
true |
false |
$x = null; |
NULL | true |
true |
false |
false |
var $x; |
NULL | true |
true |
false |
false |
$x is undefined | NULL | true |
true |
false |
false |
$x = []; |
array | true |
false |
true |
false |
$x = ['a', 'b']; |
array | false |
false |
true |
true |
$x = false; |
boolean | true |
false |
true |
false |
$x = true; |
boolean | false |
false |
true |
true |
$x = 1; |
integer | false |
false |
true |
true |
$x = 42; |
integer | false |
false |
true |
true |
$x = 0; |
integer | true |
false |
true |
false |
$x = -1; |
integer | false |
false |
true |
true |
$x = "1"; |
string | false |
false |
true |
true |
$x = "0"; |
string | true |
false |
true |
false |
$x = "-1"; |
string | false |
false |
true |
true |
$x = "php"; |
string | false |
false |
true |
true |
$x = "true"; |
string | false |
false |
true |
true |
$x = "false"; |
string | false |
false |
true |
true |
true |
false |
1 |
0 |
-1 |
"1" |
"0" |
"-1" |
null |
[] |
"php" |
"" |
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
true |
true |
false |
true |
false |
true |
true |
false |
true |
false |
false |
true |
false |
false |
false |
true |
false |
true |
false |
false |
true |
false |
true |
true |
false |
true |
1 |
true |
false |
true |
false |
false |
true |
false |
false |
false |
false |
false |
false |
0 |
false |
true |
false |
true |
false |
false |
true |
false |
true |
false |
false * |
false * |
-1 |
true |
false |
false |
false |
true |
false |
false |
true |
false |
false |
false |
false |
"1" |
true |
false |
true |
false |
false |
true |
false |
false |
false |
false |
false |
false |
"0" |
false |
true |
false |
true |
false |
false |
true |
false |
false |
false |
false |
false |
"-1" |
true |
false |
false |
false |
true |
false |
false |
true |
false |
false |
false |
false |
null |
false |
true |
false |
true |
false |
false |
false |
false |
true |
true |
false |
true |
[] |
false |
true |
false |
false |
false |
false |
false |
false |
true |
true |
false |
false |
"php" |
true |
false |
false |
false * |
false |
false |
false |
false |
false |
false |
true |
false |
"" |
false |
true |
false |
false * |
false |
false |
false |
false |
true |
false |
false |
true |
true
。
true |
false |
1 |
0 |
-1 |
"1" |
"0" |
"-1" |
null |
[] |
"php" |
"" |
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
true |
true |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
true |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
1 |
false |
false |
true |
false |
false |
false |
false |
false |
false |
false |
false |
false |
0 |
false |
false |
false |
true |
false |
false |
false |
false |
false |
false |
false |
false |
-1 |
false |
false |
false |
false |
true |
false |
false |
false |
false |
false |
false |
false |
"1" |
false |
false |
false |
false |
false |
true |
false |
false |
false |
false |
false |
false |
"0" |
false |
false |
false |
false |
false |
false |
true |
false |
false |
false |
false |
false |
"-1" |
false |
false |
false |
false |
false |
false |
false |
true |
false |
false |
false |
false |
null |
false |
false |
false |
false |
false |
false |
false |
false |
true |
false |
false |
false |
[] |
false |
false |
false |
false |
false |
false |
false |
false |
false |
true |
false |
false |
"php" |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
true |
false |
"" |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
false |
true |
It's interesting to note that 'empty()' and 'boolean : if($x)'
are paired as logical opposites, as are 'is_null()' and 'isset()'.
Note that php comparison is not transitive:
"php" == 0 => true
0 == null => true
null == "php" => false
A comparison table for <=,<,=>,> would be nice...
Following are TRUE (tested PHP4&5):
NULL <= -1
NULL <= 0
NULL <= 1
!(NULL >= -1)
NULL >= 0
!(NULL >= 1)
That was a surprise for me (and it is not like SQL, I would like to have the option to have SQL semantics with NULL...).
Be aware of the difference between checking the *value* of an array item, and checking the *existence* of an array item:
<?php
$arr = [
'x' => 0,
'y' => null,
];
isset($arr['x']); // true, same as isset(0)
isset($arr['y']); // false, same as isset(null)
array_key_exists('y', $arr); // true, though the value is null
array_key_exists('z', $arr); // false
Some function to write out your own comparisson table in tsv format. Can be easily modified to add more testcases and/or binary functions. It will test all comparables against each other with all functions.
<?php
$funcs = array(
/* Testing equality */
'eq' => '==',
'ne' => '!=',
'gt' => '>',
'lt' => '<',
'ne2' => '<>',
'lte' => '<=',
'gte' => '>=',
/* Testing identity */
'id' => '===',
'nid' => '!=='
);
class Test {
protected $a;
public $b;
public function __construct($a,$b){
$this->a = $a;
$this->b = $b;
}
public function getab(){
return $this->a.",". $this->b;
}
}
$tst1 = new Test(1,2);
$tst2 = new Test(1,2);
$tst3 = new Test(2,2);
$tst4 = new Test(1,1);
$arr1 = array(1,2,3);
$arr2 = array(2,3,4);
$arr3 = array('a','b','c','d');
$arr4 = array('a','b','c');
$arr5 = array();
$comp1 = array(
'ints' => array(-1,0,1,2),
'floats' => array(-1.1,0.0,1.1,2.0),
'string' => array('str', 'str1', '', '1'),
'bools' => array(true, false),
'null' => array(null),
'objects' => array($tst1,$tst2,$tst3,$tst4),
'arrays' => array($arr1, $arr2, $arr3, $arr4, $arr5)
);
$fbody = array();
foreach($funcs as $name => $op){
$fbody[$name] = create_function('$a,$b', 'return $a ' . $op . ' $b;');
}
$table = array(array('function', 'comp1', 'comp2', 'f comp1 comp2', 'type'));
/* Do comparisons */
$comp2 = array();
foreach($comp1 as $type => $val){
$comp2[$type] = $val;
}
foreach($comp1 as $key1 => $val1){
foreach($comp2 as $key2 => $val2){
addTableEntry($key1, $key2, $val1, $val2);
}
}
$out = '';
foreach($table as $row){
$out .= sprintf("%-20s\t%-20s\t%-20s\t%-20s\t%-20s\n", $row[0], $row[1], $row[2], $row[3], $row[4]);
}
print $out;
exit;
function addTableEntry($n1, $n2, $comp1, $comp2){
global $table, $fbody;
foreach($fbody as $fname => $func){
foreach($comp1 as $val1){
foreach($comp2 as $val2){
$val = $func($val1,$val2);
$table[] = array($fname, gettype($val1) . ' => ' . sprintval($val1), gettype($val2) .' => ' . sprintval($val2), gettype($val) . ' => ' . sprintval($val), gettype($val1) . "-" . gettype($val2) . '-' . $fname);
}
}
}
}
function sprintval($val){
if(is_object($val)){
return 'object-' . $val->getab();
}
if(is_array($val)){
return implode(',', $val);
}
if(is_bool($val)){
if($val){
return 'true';
}
return 'false';
}
return strval($val);
}
?>
The truth tables really ought to be colorized; they're very hard to read as they are right now (just big arrays of TRUE and FALSE).
Also, something to consider: clustering the values which compare similarly (like is done on qntm.org/equality) would make the table easier to read as well. (This can be done simply by hand by rearranging the order of headings to bring related values closer together).
In some languages, a boolean is promoted to an integer (with a value of 1 or -1, typically) if used in an expression with an integer. I found that PHP has it both ways:
If you add a boolean with a value of true to an integer with a value of 3, the result will be 4 (because the boolean is cast as an integer).
On the other hand, if you test a boolean with a value of true for equality with an integer with a value of three, the result will be true (because the integer is cast as a boolean).
Surprisingly, at first glance, if you use either < or > as the comparison operator the result is always false (again, because the integer as cast as a boolean, and true is neither greater nor less than true).
There is also 0.0 which is not identical to 0.
$x = 0.0;
gettype($x); // double
empty($x); // true
is_null($x); //false
isset($x); // true
is_numeric($x); // true
$x ? true : false; // false
$x == 0; // true
$x == "0"; // true
$x == "0.0"; // true
$x == false; // true
$x == null; // true
$x === 0; // false
$x === false; // false
$x === null; // false
$x === "0"; // false
$x === "0.0"; // false