我是靠谱客的博主 忧伤玉米,这篇文章主要介绍PHP学习笔记6:表达式和运算符PHP学习笔记6:表达式和运算符,现在分享给大家,希望可以做个参考。

PHP学习笔记6:表达式和运算符

image-20211129162010327

图源:php.net

表达式

php官方手册对表达式的定义是“任何有值的东西”。不同的语言对于表达式的定义是区别很大的,比如Python中很著名的“lamda表达式”,很多人觉得其本质就是个匿名函数,用处不大,这是因为他们不明白匿名函数无法嵌入表达式中使用,而lamda表达式可以。

基础数据

基础类型的数据本身就是一个表达式:

复制代码
1
2
3
4
5
echo 'hello'.PHP_EOL; echo (1).PHP_EOL; // hello // 1

需要注意的是,echo 1.PHP_EOL;会产生语法错误,因为整形值1是不能和字符串连接的,但如果用()将其包围,则(1)就是一个明确的表达式,而表达式的结果虽然依然是整形值,但php解释器会将其隐式转换为字符串后进行字符串连接。

赋值语句

php中赋值语句也是表达式,换句话说,赋值语句的作用不仅是将一个值赋给一个变量,同时作为表达式,它本身还会产生一个值:

复制代码
1
2
3
4
5
echo ($a=123).PHP_EOL; echo $a.PHP_EOL; // 123 // 123

并非所有语言的赋值语句都可以作为表达式使用,比如Python就不行,因此Python还在之前的某个版本加入了新特性——“赋值表达式”,有兴趣的可以阅读PEP 572 – Assignment Expressions

因为赋值语句是个表达式,所以可以在赋值语句中嵌入赋值语句:

复制代码
1
2
3
4
5
6
$a = ($b = 123); echo $a.PHP_EOL; echo $b.PHP_EOL; // 123 // 123

其实示例中的()是不必要的:

复制代码
1
2
3
4
5
6
$a = $b = 123; echo $a.PHP_EOL; echo $b.PHP_EOL; // 123 // 123

这是因为表达式解析是从左到右的,且=操作符是右结合的,所以php解释器自然而然会先执行$b=123,然后将值代入表达式,执行$a=123

$a = $b = 123这种写法也可以被称作“级联赋值”。

运算赋值

运算赋值是对赋值语句的一种简略写法,这广泛存在于几乎所有的编程语言:

复制代码
1
2
3
4
5
6
<?php $a = 1; $a += 5; echo $a.PHP_EOL; // 6

示例中$a += 5本质上等同于$a = $a + 5,不过在写法上更为简洁。

赋值语句是表达式,同样的,运算赋值语句也是表达式:

复制代码
1
2
3
4
$a = 5; echo ($a += 6) . PHP_EOL; // 11

函数调用

函数调用也是表达式,其值是返回值:

复制代码
1
2
3
4
5
6
function test(){ return 5; } echo test().PHP_EOL; // 5

自增、自减

可以看得出,php在语法上很多地方都参考了C/C++/Java这一系语言。php中存在自增和自减语句,且同样有前后的区别:

复制代码
1
2
3
4
5
6
7
8
9
<?php $num = 0; echo (++$num).PHP_EOL; // 1 echo ($num++).PHP_EOL; // 1 echo $num.PHP_EOL; // 2

用表达式解释前自增和后自增的区别就是:前自增是在表达式执行前让变量完成自增,后自增则是让自增发生在表达式执行之后。

三元运算符

类C语言中有一种奇怪的东西——“三元运算符”:

复制代码
1
2
3
4
5
6
<?php $a = 10; $b = $a > 5 ? 1 : 0; echo $b; // 1

三元运算符?:构成的其实也是一个表达式:

复制代码
1
2
3
echo ($a > 5 ? 1 : 0) . PHP_EOL; // 1

所以也会将其称之为“条件表达式”。

有些文章会将包含比较操作符(>/<=等)的表达式称作条件表达式,但我更喜欢将其称作"bool表达式",将三元运算符构成的表达式称作条件表达式。

运算符

从概念上说,运算符是一种将多个表达式结合并构成一个更大表达式的符号。可以写作:

复制代码
1
2
exp : [exp1 + exp2]

也就是说加运算符+将两个子表达式exp1exp2连接起来,构成了一个更大的表达式exp

运算符根据连接的表达式数量的不同,被划分为“一元运算符”、“二元运算符”、“三元运算符”。其中一元和二元运算符广泛存在于所有编程语言中,而三元运算符部分语言中并不存在。

优先级和结合律

运算符的优先级决定了那些运算符先执行哪些运算符后执行,当然基本的算术运算符的优先级是兼容数学领域的,这样符合直觉:

复制代码
1
2
3
4
$a = 1 + 2 * 5; echo $a . PHP_EOL; // 11

和数学中一样,使用()可以人为指定优先级:

复制代码
1
2
3
4
$a = (1 + 2) * 5; echo $a . PHP_EOL; // 15

运算符的结合律则决定了使用同一运算符的情况下,要先执行运算符左边还是右边的运算:

复制代码
1
2
3
4
5
6
$a = $b = 2; echo $a.PHP_EOL; echo $b.PHP_EOL; // 2 // 2

这是一个前边举过的例子,赋值表达式是右结合律,所以其等价于$a = ($b = 2),即先执行=右侧的部分。

结合优先级和结合律的规则,就可以知道一个表达式中应该先执行哪些部分,后执行哪些部分。

并不是所有运算符都有明确的结合律,有的是没有的,比如从php8.0.0开始,三元运算符的结合律从左结合变成了无,在这种情况下使用嵌套的多个三元运算符是不被允许的:

复制代码
1
2
3
$a = true ? 0 : true ? 1 : 2; // (true ? 0 : true) ? 1 : 2 = 2 (PHP 8.0.0 前可用) // Fatal error: Unparenthesized `a ? b : c ? d : e` is not supported.

因为php解释器不知道要如何分组这种表达式,即将表达式解析为true ? 0 : (true ? 1 : 2)还是(true ? 0 : true) ? 1 : 2

当然这可以使用()来避免语法错误:

复制代码
1
2
3
4
$a = (true ? 0 : true) ? 1 : 2; echo $a.PHP_EOL; // 2

就像上面展示的那样,最好不要依赖于运算符的优先级和结合律来构建复杂的表达式,那样会产生一些潜在风险,更别说php随着版本更新多次改变了运算符的优先级和表达式定义。这样做最大的问题是代码的可读性很差。使用()来明确表达式的优先级是个良好习惯。

完整的优先级和结合律列表可以查阅官方手册运算符优先级

算术运算符

完整的算术运算符列表见算术运算符

和C++相比,php的除法运算符/并不区分整数和浮点数,即使除数和被除数都是整数,运算也是除法而非C++中的整除:

复制代码
1
2
3
4
5
$a = 1; $b = 5; echo ($a / $b) . PHP_EOL; // 0.2

所以php中一般的除法运算结果都是浮点数,除非两个操作数都是整数,且结果恰好也是整数:

复制代码
1
2
3
4
5
$a = 6; $b = 2; echo ($a / $b) . PHP_EOL; // 3

如果需要在php中进行整除,应当使用 intdiv() 函数。

如果对浮点数进行模运算,会将操作数转换为整数后进行运算:

复制代码
1
2
3
4
5
6
7
$a = 7.5; $b = 2.2; echo ($a % $b) . PHP_EOL; // Deprecated: Implicit conversion from float 7.5 to int loses precision in ... // Deprecated: Implicit conversion from float 2.2 to int loses precision in ... // 1

可以看到,虽然会正常执行并产生结果,但会产生两条Deprecated提醒,这意味着这种特性已经废弃,会在未来的php版本中删除,所以应当避免这种方式。如果要对浮点数取余,可以使用 fmod() 函数。

此外,模运算中如果涉及负数,结果的正负号是与被除数的正负号一致的:

复制代码
1
2
3
4
5
6
7
8
9
$a = -7; $b = 2; echo ($a % $b) . PHP_EOL; // -1 $a = 7; $b = -2; echo ($a % $b) . PHP_EOL; // 1

赋值运算符

特别的,因为php的字符串连接符是.而非常见的+,所以php的运算赋值符号中有一个独特的.=

复制代码
1
2
3
4
5
6
$a = 'hello'; $a .= ' world'; $a .= '!'; $a .= PHP_EOL; echo $a;

当然,这同样存在字符串连接中产生“中间字符串”过多,造成性能浪费的问题,所以构建长字符串通常使用下边的方式:

复制代码
1
2
3
4
5
6
7
8
9
$longStr = array(); $longStr[] = 'hello'; $longStr[] = ' world'; $longStr[] = '!'; $longStr[] = PHP_EOL; $a = implode('', $longStr); echo $a; // hello world!

php中没有指针,但存在引用赋值。对于对象以外的类型赋值,都是值拷贝:

复制代码
1
2
3
4
5
6
7
8
9
10
<?php require_once "../util/array.php"; $arr1 = array(1, 2, 3); $arr2 = $arr1; $arr2[0] = 99; print_arr($arr1); print_arr($arr2); // [0:1, 1:2, 2:3] // [0:99, 1:2, 2:3]

这里的工具函数print_arr是我为了缩减数组打印结果编写的一个函数:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php function print_arr(array $arr) { $ls = array(); $ls[] = '['; $index = 0; $len = count($arr); foreach ($arr as $key => $value) { $ls[] = "{$key}:{$value}"; if ($index < $len - 1) { $ls[] = ', '; } $index++; } $ls[] = ']'; echo implode('', $ls) . PHP_EOL; }

如果要在赋值后可以修改原始内容,则需要拷贝数据的引用,而不是值:

复制代码
1
2
3
4
5
6
7
8
9
require_once "../util/array.php"; $arr1 = array(1, 2, 3); $arr2 = &$arr1; $arr2[0] = 99; print_arr($arr1); print_arr($arr2); // [0:99, 1:2, 2:3] // [0:99, 1:2, 2:3]

特别的,对于对象的拷贝都是引用,而非值:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php class Student{ public $name; public $age; } $std = new Student; $std->name = 'Jack Chen'; $std->age = 20; $std2 = $std; $std2->name = 'Brus Lee'; echo "name:{$std->name}".PHP_EOL; echo "name:{$std2->name}".PHP_EOL;

更多的赋值运算符说明见官方文档赋值运算符

位运算

位运算,顾名思义就是对比特位进行的运算,也就是针对二进制整数的运算。

在php中,最常见的就是错误级别的相关内容:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$consts = get_defined_constants(); foreach ($consts as $constName => $constValue){ if (strpos($constName, 'E_')===0){ echo "name:{$constName} value:{$constValue}".PHP_EOL; } } // name:E_ERROR value:1 // name:E_RECOVERABLE_ERROR value:4096 // name:E_WARNING value:2 // name:E_PARSE value:4 // name:E_NOTICE value:8 // name:E_STRICT value:2048 // ...

仔细观察预定义的错误级别相关常量,E_ERROR1E_WARNING2E_PARSE4E_NOTICE8,它们都是二的倍数。之所以这么设计,是为了可以利用位运算来表示一些错误级别的“集合”,这也是位运算最实用的用途之一。

如果要让php程序只显示某种级别的错误,可以实用error_reporting

复制代码
1
2
error_reporting(E_ERROR);

如果要显示多种级别的错误:

复制代码
1
2
error_reporting(E_ERROR | E_NOTICE);

之所以可以这样,是因为位运算E_ERROR | E_NOTICE的结果本身包含了两个二进制位,分别表示E_ERRORE_NOTICE这两个错误级别:

复制代码
1
2
3
4
5
6
7
8
9
<?php require_once "../util/int.php"; print_binary(E_ERROR); print_binary(E_NOTICE); print_binary(E_ERROR | E_NOTICE); // 0000000001 // 0000001000 // 0000001001

这里的print_binary是我编写的一个用于输出二进制形式数字的辅助函数:

复制代码
1
2
3
4
5
6
7
8
9
/** * 以二进制形式打印数字(10位,0填充) * @param int $binaryNum */ function print_binary(int $binaryNum): void { echo sprintf("%'.010b", $binaryNum) . PHP_EOL; }

将结果用二进制表示就很容易理解了,E_ERRORb0001E_NOTICEb1000,经过位或运算后的结果是b1001,其第四位1表示结果中包含E_NOTICE,第一位1表示包含E_ERROR。这种用不同进位的0和1来表示多种信息的效果是相当巧妙的。

事实上这属于离散数学领域的内容,想详细了解理论方面知识的可以查阅相关资料。

同样,我们可以利用位运算的原理从一个包含多个信息的二进制数中"还原"信息:

复制代码
1
2
3
4
5
6
7
<?php require_once "../util/error.php"; test_error_include(E_ERROR | E_NOTICE); test_error_include(E_NOTICE | E_ERROR | E_STRICT); // E_ERROR,E_NOTICE // E_ERROR,E_NOTICE,E_STRICT

这里的test_error_include是一个检测错误级别经过位运算后包含的错误级别信息的工具函数:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php function test_error_include(int $multiErros) { $errors = array(); if ($multiErros & E_ERROR) { $errors[] = "E_ERROR"; } if ($multiErros & E_PARSE) { $errors[] = "E_PARSE"; } if ($multiErros & E_NOTICE) { $errors[] = "E_NOTICE"; } if ($multiErros & E_STRICT) { $errors[] = "E_STRICT"; } if ($multiErros & E_WARNING) { $errors[] = "E_WARNING"; } if ($multiErros & E_CORE_ERROR) { $errors[] = "E_CORE_ERROR"; } if ($multiErros & E_USER_ERROR) { $errors[] = "E_USER_ERROR"; } echo implode(',', $errors) . PHP_EOL; }

需要说明的是,这里仅包含了大多数常见错误级别,并非所有。还注意的是这里的多个if可能同时满足,所以它们之间的关系是顺序的,而非if..else if...

可以看出,利用二进制位运算,原本可能需要传递一个数组到test_error_include中,现在只需要直接传递位运算结果就能表示多个错误级别的集合。而内建函数error_reporting采用的是相同的原理。

除了使用位或,还可以使用其它位运算符表示各种含义,比如:

复制代码
1
2
3
4
5
6
// E_ERROR,E_NOTICE,E_STRICT test_error_include(E_ALL & ~E_NOTICE); //E_NOTICE以外的错误级别 // E_ERROR,E_PARSE,E_STRICT,E_WARNING,E_CORE_ERROR,E_USER_ERROR test_error_include(E_ALL ^ E_NOTICE); //E_NOTICE以外的错误级别 // E_ERROR,E_PARSE,E_STRICT,E_WARNING,E_CORE_ERROR,E_USER_ERROR

示例中的两种位运算其实是等价的,具体可以参考位运算原理和离散数学,这里不再详细说明。

按理来说其实也可以用下面来表示:

复制代码
1
2
3
test_error_include(~E_NOTICE); //不推荐 // E_ERROR,E_PARSE,E_STRICT,E_WARNING,E_CORE_ERROR,E_USER_ERROR

但这里的~E_NOTICEE_ALL ^ E_NOTICE的结果可能并不完全相同:

复制代码
1
2
3
4
5
6
require_once "../util/int.php"; print_binary(~E_NOTICE); // 1111111111111111111111111111111111111111111111111111111111110111 print_binary(E_ALL & ~E_NOTICE); // 111111111110111

这是因为E_ALL的高位会用0填充,它只会将“有意义”的低位(对应所有的错误级别)设置为1。

位运算还包含左移<<和右移>>运算,这里不再说明,具体可以阅读官方手册位运算符

比较运算符

如果你是先学习了其它语言,尤其是强类型语言,使用php进行比较运算时需要注意,php会在“需要”时进行一些类型转换后进行比较,所以某些其它语言中不可能相等的结果在php中却是相等的:

复制代码
1
2
3
4
5
6
7
8
9
var_dump(0 == "a"); // bool(false) var_dump("1" == "01"); // bool(true) var_dump("10" == "1e1"); // bool(true) var_dump(100 == "1e2"); // bool(true)

因为这里的"1""01""1e1"等都会被当做数字字符串来对待,在比较时会先转化为数字,然后比较。

而且这种结果还会因php版本的不同而不同,所以只要类型确定,应当使用===而非==进行比较:

复制代码
1
2
3
4
5
6
7
8
9
var_dump(0 === "a"); // bool(false) var_dump("1" === "01"); // bool(false) var_dump("10" === "1e1"); // bool(false) var_dump(100 === "1e2"); // bool(false)

很多开发者喜欢“引战”,会比较不同语言的差异评论优劣,其实语言特性往往是开发团队因为某些原因取舍的结果,这只是语言的一种“特性”,作为语言的使用者而言,其实是不存在优劣的。

就上面的相等运算来说,你可以认为这是一种php的缺陷,但也可以认为这是php灵活性的体现,可以实现一些别的语言中无法实现的效果。

这其中的重点在于你需要搞懂其中的细微差别,并时刻清楚你的代码会产生哪些后果。

如果你足够谨慎,还可以使用strcmp函数来比较字符串:

复制代码
1
2
3
4
5
var_dump(strcmp("1", "01") == 0); // bool(false) var_dump(strcmp("10", "1e1") == 0); // bool(false)

php还有一个相当“花哨”的比较运算符<=>,叫做“太空船”运算符,这个名字和“海象运算符”有的一拼。该运算符的描述是对于$a<=>$b,如果$a大于$b,会返回一个大于0的数,如果$a等于$b,会返回一个小于0的数,如果$a等于$b,则会返回0。

其实这种规则和一些用于比较的函数的返回值很像,比如我们可以利用它来创建一个用于比较对象的函数:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php class Student { public $name = ""; public $age = 0; } /** * 比较两个student的大小 * @param Student $std1 * @param Student $std2 * @return int 如果std1大于std2,返回值大于0,如果... */ function compare_student(Student $std1, Student $std2): int { return $std1->age <=> $std2->age; } $std1 = new Student; $std2 = new Student; $std1->age = 20; $std2->age = 15; var_dump(compare_student($std1, $std2)); // int(1)

当然,对待“花哨”的运算符的最好方式是——不要使用。

同样的,想了解完整比较运算符列表,请移步官方手册比较运算符

错误控制运算符

php存在一个错误控制运算符@,其作用是添加在表达式头部后,可以屏蔽其后表达式可能出现的错误提示。

这里用打开文件作为示例,当试图打开一个不存在的文件时:

复制代码
1
2
3
4
<?php $lines = file("file_no_exists"); // Warning: file(file_no_exists): Failed to open stream: No such file or directory in ...

使用@屏蔽warning信息,并在失败时打印自定义信息并退出:

复制代码
1
2
3
4
<?php $lines = @file("file_no_exists") || die("file is not exists, exit."); // file is not exists, exit.

在php8.0以前,使用@可能会屏蔽一些导致程序中断运行的致命错误提示,在8.0之后不会了。

需要注意的是,如果你设置了自定义的错误处理程序,@依然会触发:

复制代码
1
2
3
4
5
6
7
8
9
<?php function my_error_handle($err_no, $err_msg, $filename, $linenum){ echo $err_msg.PHP_EOL; } set_error_handler("my_error_handle"); $lines = @file("file_no_exists") || die("file is not exists, exit."); // file(file_no_exists): Failed to open stream: No such file or directory // file is not exists, exit.

要想让@对自定义错误处理程序同样生效,需要加入相应的判断:

复制代码
1
2
3
4
5
6
7
function my_error_handle($err_no, $err_msg, $filename, $linenum){ if (!(error_reporting() & $err_no)){ return false; } echo $err_msg.PHP_EOL; }

对于@,我个人建议是,不要使用,不要使用,不要使用。

执行运算符

执行运算符"``"的作用是执行shell命令:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php $result = `dir`; echo $result . PHP_EOL; // Volume in drive D is WorkSpace // Volume Serial Number is EE20-29FD // Directory of d:workspacehttpphp-notesch6 // 2021/12/04 15:26 <DIR> . // 2021/12/04 15:26 <DIR> .. // 2021/12/04 10:16 203 assignment.php // ... // 2021/12/04 11:25 317 priority.php // 2021/12/04 11:26 63 priority2.php // 2021/12/04 10:38 103 three.php // 25 File(s) 5,203 bytes // 2 Dir(s) 52,707,540,992 bytes free

这在某些时候很有用,比如编写一些运维使用的批处理脚本。但在大多数正规的Web开发中应当避免使用,因为shell命令都是平台相关的,不同的平台有不同的shell命令,且就算是同一平台,某些shell命令能否执行也取决于是否安装了某些必要的环境。

此外执行运算符也不是必须的,可以使用shell_exec函数代替:

复制代码
1
2
$result = shell_exec("dir");

我个人更推荐使用后者,过多“花哨”的运算符只会降低代码的可读性。

递增、递减运算符

前面已经讨论过递增、递减运算符,这里不再进行介绍。唯一需要说明的是,因为前自增后和自增结合复杂的表达式使用,往往会引起一些歧义和阅读困难,比如:

复制代码
1
2
3
4
5
6
7
8
<?php $a = 1; $b = $a + ++$a + $a++; echo $a.PHP_EOL; echo $b.PHP_EOL; // 3 // 6

编写这样的代码完全是自寻烦恼,应当尽量避免:

复制代码
1
2
3
4
5
6
7
8
9
10
<?php $a = 1; $a++; $b = $a + $a + $a; $a++; echo $a.PHP_EOL; echo $b.PHP_EOL; // 3 // 6

这大概是为什么有些语言(如Go)有后自增,但没有前自增。而另一些语言(如Python),没有任何自增运算符。

逻辑运算符

有的语言(如Python)使用单词作为逻辑运算符,有的语言(如C++)则使用符号,php都支持:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
<?php $a = 1; $b = 5; if ($a < $b && is_int($a)) { echo "a < b" . PHP_EOL; // a < b } if ($a < $b and is_int($a)) { echo "a < b" . PHP_EOL; // a < b }

所以在php中&&and是等价的,||or是等价的。不过逻辑异或xor并没有对应的符号表示的逻辑操作符:

复制代码
1
2
3
4
5
6
7
8
9
var_dump(true xor true); // bool(false) var_dump(false xor false); // bool(false) var_dump(true xor false); // bool(true) var_dump(false xor true); // bool(true)

完整的逻辑运算符列表见官方手册逻辑运算符

字符串运算符

用于字符串连接的运算符有两个:..=。在本文的前边已经有说明,所以不再阐述。

数组运算符

+运算符和+=运算符可以将两个数组进行合并:

复制代码
1
2
3
4
5
6
7
8
9
<?php require_once "../util/array.php"; $a = ['a1', 'a2', 'a3']; $b = ['b1', 'b2']; print_arr($a + $b); // [0:a1, 1:a2, 2:a3] print_arr($b + $a); // [0:b1, 1:b2, 2:a3]

对于非关联数组,合并结果只会包含“多出来的索引对应的键值对”。事实上这个特征并不仅仅限于非关联数组,队员关联数组同样适用:

复制代码
1
2
3
4
5
6
7
$a = ["banana" => "banana", "apple" => "apple"]; $b = ["banana" => "banana", "orange" => "orange"]; print_arr($a + $b); // [banana:banana, apple:apple, orange:orange] print_arr($b + $a); // [banana:banana, orange:orange, apple:apple]

一般来说,很少在实际开发中使用+操作符来合并数组,更常见的是使用数组函数:

复制代码
1
2
3
print_arr(array_unique(array_merge($a, $b))); // [banana:banana, apple:apple, orange:orange]

这种情况下可以不用考虑前后数组的key是否存在重叠的问题。

==可以比较两个数组是否相等:

复制代码
1
2
3
4
5
6
7
8
9
$a = ["banana" => "banana", "apple" => "apple"]; $b = ["apple" => "apple", "banana" => "banana"]; var_dump($a == $b); // bool(true) $a = [1,2]; $b = ["1","02"]; var_dump($a == $b); // bool(true)

像上面展示的那样,键值对顺序不对也会被认为相等,此外特别要注意的是,在比较数组时,php解释器同样会进行某些隐式转换后比较,比如上边的数字字符串"1""02"就被转换为数字后进行比较,所以两个数组也是相等的。

如果要严格比较两个数组是否相等,需要使用===

复制代码
1
2
3
4
5
6
7
8
9
$a = ["banana" => "banana", "apple" => "apple"]; $b = ["apple" => "apple", "banana" => "banana"]; var_dump($a === $b); // bool(false) $a = [1,2]; $b = ["1","02"]; var_dump($a === $b); // bool(false)

在这种情况下,数组的键值对不仅要内容一致、类型一致,同时顺序也要一致才会被认为是相等的。

此外,==的反面是!=,而===的反面是!==

类型运算符

使用类型运算符instanceof可以判断对象是否为类的实例:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php class MyClass { } class NotMyClass { } $a = new MyClass; var_dump($a instanceof MyClass); var_dump($a instanceof NotMyClass); // bool(true) // bool(false)

对继承关系也能很好的判断:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php class ParentClass { } class MyClass extends ParentClass { } $a = new MyClass; var_dump($a instanceof MyClass); var_dump($a instanceof ParentClass); // bool(true) // bool(true)

因为判断的结果是bool值,所以可以结合逻辑运算符使用:

复制代码
1
2
3
var_dump(!($a instanceof MyClass)); // bool(false)

也能判断接口:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php interface MyInterface{ } class MyClass implements MyInterface{ } $a = new MyClass; var_dump($a instanceof MyClass); var_dump($a instanceof MyInterface); // bool(true) // bool(true)

如果instanceof左边的操作数不是对象,结果是false

复制代码
1
2
3
4
5
6
7
8
<?php var_dump(1 instanceof stdClass); var_dump("hello" instanceof stdClass); var_dump(false instanceof stdClass); // bool(false) // bool(false) // bool(false)

以上就是php表达式和运算符的全部内容,谢谢阅读。

往期内容

  • PHP学习笔记5:常量
  • PHP学习笔记4:变量
  • PHP学习笔记3:其它类型和类型声明
  • PHP学习笔记2:数组
  • PHP学习笔记1:基础

最后

以上就是忧伤玉米最近收集整理的关于PHP学习笔记6:表达式和运算符PHP学习笔记6:表达式和运算符的全部内容,更多相关PHP学习笔记6内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(82)

评论列表共有 0 条评论

立即
投稿
返回
顶部