1.3. 运算符
持之以恒,方得始终!
上一篇我们就使用到了赋值符 =
, 和拼接符 .
算术运算符 + - * / %
error_reporting(E_ALL);
// 加法
$a = 10;
$b = 5;
var_dump($a + $b + 1.1); // float(16.1)
// 减法
var_dump($a - $b - 2); // int(3)
// 乘法
$c = $a * $b;
var_dump($c); // int(50)
// 除法
var_dump(0/10); // int(0)
var_dump(10/0); // 这样是错误的,被除数不能是0
var_dump($a / $b); // int(2)
// 取余
var_dump(37 % 10); // int(7)
var_dump($a % $b); // int(0)
算术运算符是针对int,float类型运算的,假如掺杂了字符串类型的,会隐式的转换其类型。
大概是下面这样的规则转换,具体还是得自己动手实践才行,学编程,我们就是要多动手练习,光靠理论的讲解是学不会的。
- 如果字符串中包含 e,E,会被当做是科学计数法,并转为一个浮点数。
- php会在字符串开始处,查找数字,并用这些数字当做该字符串的值。
- 如果字符串中找不到数字,则当成 0。
总得来说,如果有字符串参与数值运算,那就要小心了。
字符串拼接符 .
直接给例子
$a = "bob 's ";
$b = "auto parts ";
$result = $a . $b;
var_dump($result); // string(18) "bob 's auto parts "
赋值 =
下面都是赋值操作
$a = 10;
$b = $a;
$test = function (){ // 匿名函数,将其赋值给变量
return 111;
};
var_dump($test());
其实赋值操作,是先开辟一块内存空间,放入值,增加一个指针,将变量和指针关联,指针可以理解为内存地址,通过它找到具体的数据。
我们再看这一种 $b = 6 + ($a = 5)
, 执行过程是这样的:
- 根据运算符的优先级,先运算括号中的,赋值5给$a, 然后计算 6 + $a , 即 6 + 5,所以结果是 $b = 11;
复合赋值 += , -= , *= , /= , %= , .=
也可以理解为一种语法糖, 我举个例子,其它的都是一样的意思。
$a += 5; // 等价于 $a = $a + 5;
$a .= $b; // 等价于 $a = $a . $b;
前置递增递减,后置递增递减 ++$i , --$i , $i++ , $i--
也可以看做是语法糖,还是看例子
// 前置
$a = 4;
echo ++$a; // 执行过程:先将$a的值加1,然后赋值给$a, 最后输出,可以等价于 $a = $a + 1; echo $a;
// 后置
$b = 4;
echo $b++; // 等价于 echo $b; $b = $b + 1;
可以看到,前置是先加1,再做其它操作,后置是先做其它操作,再加1,当然如果我们是像下面这样用,就无所谓前置,后置了。
$a = 5;
$a++; // 这里不管是 $a++, 还是 ++$a, 到下面的语句执行时,$a的值都会是6,所以随便用哪种都可以
$a += 10;
var_dump($a); // int(16)
至于对应的减法,就是减1了,和加法用法一样,就不在举例了。
引用 &
我们先看代码
$a = 5;
$b = $a;
很简单,上面是一段赋值操作,我们看下在内存中是怎么样的
可以看到,$a 赋值给 $b时,又申请了一块内存空间来存放,内存地址也不一样的,当然了,内存地址不一定是连续的,此时,$a 和 $b 是独立的两个变量,互不干扰。比如我们改变 $a 的值,$a = 7
,
$b 还是5。
如果我们想,改变 $a的值同时,$b的值也被一起改变,该如何呢?
此时,指针的引用就派上用场了。
$a = 5;
$b = &$a;
我们依旧看下内存中的情况
可以看到,此时 $a 和 $b 的内存地址一样,所指向的内存空间当然也是同一个,因此,$a = 7,$a 的内存空间中的值改变了,$b 也是一样的。换句话说,它们是共享同一个内存空间的。
讲到这里,我就不得不提一下 unset()
了,它的作用是删除一个变量,说是这么说,但其实,并不是真的删除变量的值,而是断开了变量与内存空间的指针映射关系, 内存空间中的值还是存在的。先举个例子。
代码中的表现
$a = 5;
unset($a);
var_dump($a); // 会报 Undefined variable 错误,并且还是打印出了 null
内存中的表现
我们再看一下引用 & 中 使用 unset() 的表现
首先看代码表现
$a = 5;
$b = &$a;
$a = 7;
unset($a);
var_dump($a, $b);
// PHP Notice: Undefined variable: a in C:\Users\xqw\Desktop\code\index.php on line 11
// Notice: Undefined variable: a in C:\Users\xqw\Desktop\code\index.php on line 11
// NULL
// int(7)
可以看到,$a , $b 都是同一个指针,$a 断开了其指针与内存空间的联系,但是并没有影响 $b。
再看下内存中的表现
特别注意,我们一般开发中,引用& 并不是常用的,使用它时,一定要小心,中间哪些地方可能会引起变量值被改变了,导致程序不稳定。换句话说,能不用它就别用,因为之前项目中用它出现bug的次数,不是一次两次了。
比较
比较两边的值,根据比较结果,返回true或false
==
, 判断两边的值,或表达式是否相等
写代码时,要注意,它很容易和=
混淆了,关键是执行起来,也不会报错,导致排错也不容易。
比如:$a = 5; $b = 7; var_dump($a = $b ? true : false); // bool(true) , 等价于 7 ? true : false , 根据隐式转换,此时7可以看作是 true
如果是正常的写
$a == $b
, 5不等于7,返回false。$a = 5; $b = 7; var_dump($a == $b); // bool(false)
===
,恒等,两边的数据类型和值都得相等,才返回true
比如我们看下面这个例子var_dump(0 == '0'); // bool(true) var_dump(0 === '0'); // bool(false)
!=
, 两边不等,才返回true$a = 5; $b = 7; var_dump($a != $b); // bool(true) ... $a = 5; $b = '5'; var_dump($a != $b); // bool(false)
!==
, 不恒等
上面的 5 和 ‘5’ 是相等的,再看下面的$a = 5; $b = '5'; var_dump($a !== $b); // bool(true) , 数据类型和值都是不等于,才返回true,上面值都是5,但是 $b的数据类型是字符串,所以还是不等的
<
, 小于$a < $b
, $a 小于 $b , 就返回true>
, 大于$a > $b
, $a 大于 $b,就返回true<=
,小于等于>=
, 大于等于
逻辑运算符
最常用的就是 与 &&
, 或 ||
, 非 !
其实和电路里面的门电路差不多的意思。
我们也知道,二进制是程序的最最最底层语言,然后是机器码,再才是汇编,最后才是高级语言。
而为什么选择二进制呢,因为计算机本质是由一堆电子元器件组成的,电路只有两种状态,通电1,断电0,没别的,门电路,就是设计的一些包含简单的逻辑电路了,计算机本质就是由此简单的东西来支撑运算的。当然还有寄存器,为什么有寄存器,比如我让运算器,计算1 + 2,键盘按下1,这个1是不是得在运算之前保存一下。由此寄存器+运算器 就组成了cpu,内存呢,就是一个存储单元,存储运行得程序,暂时不执行的数据或指令,比如一个程序再后台运行,我们暂时不需要它,系统就会把它的数据,指令放入内存,正在执行的指令,关键数据,放到寄存器中,加快执行效率。也就是寄存器的读取速度 > 内存。先讲到这里,这是个大话题,不多扯了。
先举个例子,比如我要取 0~100 之间,为偶数, 并且包含0的数字?
我们先看下不用逻辑符的写法
for ($i=1; $i<=100; $i++) { // 我们用循环一个个筛选
if ($i % 2 == 0) {
if ($i % 10 == 0) {
echo $i . " ";
}
}
}
// 10 20 30 40 50 60 70 80 90 100
我们用逻辑符呢?
for ($i=1; $i<=100; $i++) { // 我们用循环一个个筛选
if ($i % 2 == 0 && $i % 10 == 0) { // && 并且
echo $i . " ";
}
}
// 10 20 30 40 50 60 70 80 90 100
很明显,能减少 if 的层级。
php中的逻辑符有以下几种
!
, 非
比如,!xxx
, xxx 可以是表达式,变量,或值,如果xxx是true,则返回false,如果是false,则返回true;我举个例子:if ($name != 'php') { // 如果$name 的值 不是 php echo "this is java."; }
&&
与
两边的结果都是true,最终才是trueif ($learnTime >= 8 && $learnConten == 'php') { // 如果学习时间大于等于8小时,并且 学习内容是php ,那么就是美好的一天 echo "good day"; }
||
或
只要其中有一个为true,结果就是true。if ($drink == 'coke' || $player == 'lol') { // 我喝可乐,或者玩撸啊撸,都会使我快乐。 echo "make me happy"; }
and
,也是与&&
, 但是优先级低or
, 也是或||
, 优先级低xor
, 异或true xor false
,false xor false
结果是true
如果是,true xor true
,false xor false
结果则是false。
要注意,and,or 比 && ,|| 的执行优先级要低。当然了实际项目中我们一般也用的少。用到了,就要小心优先级问题了。
位运算
我先说下什么是位,位其实就是 Bit,我们知道 一个字节byte = 8bit
, 一般我们的汉字是占3字节,英文占1个字节。
1bit 其实就是一个二进制的位,可以有0,1两种变化。如下
1bit 01 2 2种变化
2bit 01,01 2*2 = 2^2 4种变化
8bit 01,01,01,01,01,01,01,01 2*2*2*2*2*2*2*2 = 2^8 256种变化
由此,我们也知道了,为什么英文是一个字节了(8bit),因为英文26*2
,再加上一些符号等,256种组合方式,足以表示完了,但是汉字有几万种,所以得加字节了,这又会产生一个新问题,各种地方的文字不一样,占用的字节也会不一样,其实我们的文字是有一套编码表的,文字与它的编码对照表,或者说字典。
那么不同地区都不一样,就会有多套字符编码表了,当然为了统一,后面出了 unicode,统一所有的,有点像秦统一六国后,实施的文字统一的意思。但是,很明显,它用的字节肯定更大了。不利于转换的性能,后面又出现了UTF-8
&
, 按位与
比如$a & $b
, 将$a和$b的每一位进行 与 运算,所得到的结果, 我们还是看例子:var_dump(PHP_INT_SIZE); // int(8), 即int类型占8字节 var_dump(3 & 5); // int(1) // 3的二进制表示为 0000 ... 0000 0011 // 5的二进制表示为 0000 ... 0000 0101 // 按位与运算 0000 ... 0000 0001 , 转为十进制,就是1了
|
, 按位或$a | $b
, 将$a和$b的每一位,进行或运算,所得到的结果。var_dump(3 | 5); // int(7) // 3的二进制表示为 0000 ... 0000 0011 // 5的二进制表示为 0000 ... 0000 0101 // 按位或运算 0000 ... 0000 0111 , 转为十进制,就是7
~
, 按位非~$a
, 将$a的每一位进行 非 运算 ,所得到的结果。$a = 5; var_dump(~$a); // int(-6) // 5的二进制 0000 ... 0000 0101 // 按位非运算 1111 ... 1111 1010 因为第一位是符号位,那么这是一个负数,负数还需要减1,再取反,才能得到最终值 // 如果是负数-1 1111 ... 1111 1001 // 再取反 1000 ... 0000 0110 得出的结果为 -6
关于数值在计算机中的保存方式,以及编码表,后面我会专门写文章,这里先不过多展开讲了。
^
, 按位异或$a ^ $b
, 将$a 和 $b 的每一位进行 异或 运算。$a = 3; // 0000 ... 0000 0011 $b = 5; // 0000 ... 0000 0101 // 按位异或 0000 ... 0000 0110 转为十进制为6 var_dump($a ^ $b); // int(6)
<<
, 左位移$a << $b
, 将$a左移$b位$a = 3; // 0000 ... 0000 0011 $b = 5; var_dump($a << $b); //$a左移5位 0000 ... 0110 0000 int(96)
>>
, 右位移$a >> $b
, 将 $a 右移 $b 位$a = 3; // 0000 ... 0000 0011 $b = 5; var_dump($a >> $b); // 两个1移出边界,0补位 int(0)
三元运算符
condition ? 值1 : 值2
($grade >= 50) ? 'passed' : 'faild'; // 大于等于50的,为passed,否则faild
其实也可以理解为一种语法糖,等价于下面的if-else
if ($grade >= 50) {
$a = 'passed';
} else {
$a = 'faild';
}
错误抑制符 @
直接看例子:
$a = 57/0; // 被除数不能是0,运行会报错
$a = @(57/0); // 这样就不会直接报错了
如果php.ini中,启用了 track_errors
特性,那么错误信息会被保存到全局变量 $php_errormsg中。
一般不建议抑制,我们可以用自己方式返回一个更友好的信息给用户
error_reporting(E_ALL);
ini_set("track_errors", 1);
$b = 0;
$a = @(57/$b);
if (isset($php_errormsg) && !empty($php_errormsg)) {
echo "被除数不能是0";
} else {
var_dump($a);
}
``
, 执行linux命令
可以用它来执行linux上面的shell命令,直接看例子:
$out = `ls -la`;
echo "<pre> $out </pre>";
当然,除了这个,我们还有其它方法可以去执行linux上面的命令的。
数组相关的操作符
+
, 直接看例子
==
===
下面的就不一一举例说明了!=
不等<>
不等!==
不恒等
因为我们实际开发中,用的不多,数组的对比,联合是很复杂的,并且要根据具体业务去做,大概率要用到循环遍历去逐个处理。
instanceof
检查一个对象,是否是某个类的实例
class Bird {}
$mayue = new Bird();
if ($mayue instanceof Bird) {
echo "mayue 是 Bird类的一个实例";
} else {
echo "不是";
}
如有任何侵权行为,请通知我删除,谢谢大家!
个人邮箱:865460609@qq.com