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类型运算的,假如掺杂了字符串类型的,会隐式的转换其类型。

大概是下面这样的规则转换,具体还是得自己动手实践才行,学编程,我们就是要多动手练习,光靠理论的讲解是学不会的。

  1. 如果字符串中包含 e,E,会被当做是科学计数法,并转为一个浮点数。
  2. php会在字符串开始处,查找数字,并用这些数字当做该字符串的值。
  3. 如果字符串中找不到数字,则当成 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

  1. == , 判断两边的值,或表达式是否相等
    写代码时,要注意,它很容易和 = 混淆了,关键是执行起来,也不会报错,导致排错也不容易。
    比如:

    $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)
  2. === ,恒等,两边的数据类型和值都得相等,才返回true
    比如我们看下面这个例子

    var_dump(0 == '0');  // bool(true)
    var_dump(0 === '0'); // bool(false)
  3. != , 两边不等,才返回true

    $a = 5;
    $b = 7;
    var_dump($a != $b); // bool(true)
    ...
    $a = 5;
    $b = '5';
    var_dump($a != $b); // bool(false)
  4. !== , 不恒等
    上面的 5 和 ‘5’ 是相等的,再看下面的

    $a = 5;
    $b = '5';
    var_dump($a !== $b); // bool(true) , 数据类型和值都是不等于,才返回true,上面值都是5,但是 $b的数据类型是字符串,所以还是不等的
  5. < , 小于
    $a < $b, $a 小于 $b , 就返回true

  6. > , 大于
    $a > $b , $a 大于 $b,就返回true

  7. <= ,小于等于

  8. >= , 大于等于

逻辑运算符

最常用的就是 与 &&或 ||非 !

其实和电路里面的门电路差不多的意思。

我们也知道,二进制是程序的最最最底层语言,然后是机器码,再才是汇编,最后才是高级语言。

而为什么选择二进制呢,因为计算机本质是由一堆电子元器件组成的,电路只有两种状态,通电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中的逻辑符有以下几种

  1. , 非
    比如,!xxx , xxx 可以是表达式,变量,或值,如果xxx是true,则返回false,如果是false,则返回true;我举个例子:

    if ($name != 'php') { // 如果$name 的值 不是 php
     echo "this is java.";
    }
  2. &&
    两边的结果都是true,最终才是true

    if ($learnTime >= 8 && $learnConten == 'php') { // 如果学习时间大于等于8小时,并且 学习内容是php ,那么就是美好的一天
     echo "good day";
    }
  3. ||
    只要其中有一个为true,结果就是true。

    if ($drink == 'coke' || $player == 'lol') { // 我喝可乐,或者玩撸啊撸,都会使我快乐。
     echo "make me happy";
    }
  4. and ,也是与&&, 但是优先级低

  5. or , 也是或|| , 优先级低

  6. 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  0101010101010101  2*2*2*2*2*2*2*2 = 2^8 256种变化

由此,我们也知道了,为什么英文是一个字节了(8bit),因为英文26*2,再加上一些符号等,256种组合方式,足以表示完了,但是汉字有几万种,所以得加字节了,这又会产生一个新问题,各种地方的文字不一样,占用的字节也会不一样,其实我们的文字是有一套编码表的,文字与它的编码对照表,或者说字典。

那么不同地区都不一样,就会有多套字符编码表了,当然为了统一,后面出了 unicode,统一所有的,有点像秦统一六国后,实施的文字统一的意思。但是,很明显,它用的字节肯定更大了。不利于转换的性能,后面又出现了UTF-8

  1. &, 按位与
    比如$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了
  2. |, 按位或
    $a | $b, 将$a和$b的每一位,进行或运算,所得到的结果。

    var_dump(3 | 5); // int(7)
    // 3的二进制表示为  0000 ... 0000 0011
    // 5的二进制表示为  0000 ... 0000 0101
    // 按位或运算       0000 ... 0000 0111 , 转为十进制,就是7
  3. ~, 按位非
    ~$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

    关于数值在计算机中的保存方式,以及编码表,后面我会专门写文章,这里先不过多展开讲了。

  4. ^ , 按位异或
    $a ^ $b , 将$a 和 $b 的每一位进行 异或 运算。

    $a = 3;         // 0000 ... 0000 0011
    $b = 5;         // 0000 ... 0000 0101
    // 按位异或         0000 ... 0000 0110  转为十进制为6
    var_dump($a ^ $b); // int(6)
  5. << , 左位移
    $a << $b , 将$a左移$b位

    $a = 3; // 0000 ... 0000 0011
    $b = 5;
    var_dump($a << $b); //$a左移5位 0000 ... 0110 0000   int(96)
  6. >> , 右位移
    $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

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
Junwind
讨论数量: 0
发起讨论 只看当前版本


暂无话题~