← PHP数据类型:从松散类型到精准掌控 PHP注释:被低估的代码维护利器 →

PHP运算符全解:从基础运算到执行优先级

原创 2026-05-09 PHP 已有人查阅

运算符在任何编程语言里都扮演着核心角色,PHP自然也不例外。简单说,运算符就是用来对变量或值进行某种操作的符号。作的对象叫操作数,操作数和运算符组合起来就构成了表达式。

比如这行代码:

$total = 10 + 20;

这里面+是运算符,1020是操作数,$total是接收结果的变量。因为它作用于两个操作数,所以+在这里是一个二元运算符。

PHP的运算符家族相当庞大,按功能可以细分为十一大类。如果按操作数的数量来分,又可以归纳为三种形态:

  • 一元运算符:只操作一个操作数,比如++--!

  • 二元运算符:操作两个操作数,比如+-*/

  • 三元运算符:操作三个操作数,PHP里特指?:

下面我们按功能分类逐一拆解,每个类别都配上能直接运行的短示例,方便你在本地环境试验。

一、算术运算符

算术运算符处理的就是我们日常的数字运算。PHP支持标准四则运算,加上取模和幂运算。其中幂运算符**是从PHP 5.6.0才加入的,用老版本的话要注意兼容性。

运算符 名称 示例 说明
+ 加法 a+a+b 两数之和
- 减法 a−a−b 两数之差
* 乘法 a∗a∗b 两数之积
/ 除法 a/a/b 两数之商
% 取模 aab 两数相除的余数
** 幂运算 a∗∗a∗∗b a的a的b次方

示例:

<?php
$coursePrice = 299;      // 课程单价
$courseCount = 3;        // 购买数量
$discount = 80;          // 优惠金额

$subTotal = $coursePrice * $courseCount;  // 乘法:897
$finalPrice = $subTotal - $discount;      // 减法:817
$averagePrice = $finalPrice / $courseCount; // 除法:约272.33
$remainder = $finalPrice % $courseCount;  // 取模:817除以3余1

echo "小计:{$subTotal}元,实付:{$finalPrice}元,余数演示:{$remainder}\n";

// 幂运算:2的10次方
echo "2的10次方是:" . (2 ** 10);  // 输出:1024
?>

取模运算在判断奇偶数、分页计算等场景里非常实用。幂运算则省去了以前用pow()函数的麻烦,代码更直观。

二、赋值运算符

最基本的赋值运算符就是等号=,它把右边表达式的值赋给左边变量。PHP还提供了一组复合赋值运算符,把运算和赋值合并成一步,写起来更精炼。

运算符 名称 示例 等价于
= 赋值 a=a=b a=a=b
+= 加后赋值 a+=a+=b a=a=a + $b
-= 减后赋值 a−=a−=b a=a=a - $b
*= 乘后赋值 a∗=a∗=b a=a=a * $b
/= 除后赋值 a/=a/=b a=a=a / $b
%= 取模后赋值 aab a=a=a % $b

示例:

<?php
$score = 0;
echo "初始分数:{$score}\n";

$score += 10;  // 答对一题加10分
echo "第一题后:{$score}\n";

$score *= 2;   // 触发双倍积分卡
echo "双倍后:{$score}\n";

$score -= 5;   // 违规扣5分
echo "扣分后:{$score}\n";

$score /= 3;   // 均分给3个队友
echo "均分后:{$score}\n";
?>

个人见解:复合赋值运算符不仅仅是少写几个字符。在循环累加或者计数器场景里,$counter += 1$counter = $counter + 1更贴近思维惯性,读代码时一眼就知道是在“追加”而不是“重新计算”。我自己的编码习惯是,只要变量自身参与运算后还要存回自身,一律用复合赋值。

三、位运算符

位运算符直接操作整数的二进制位,属于偏底层但效率很高的操作。在权限系统、状态标记、加密算法等场景中经常能见到它们的身影。

运算符 名称 示例 说明
& 按位与 a & b 两数对应位都是1,结果位才是1
| 按位或 a∥a∥b 两数对应位有一个是1,结果位就是1
^ 按位异或 a ^ b 两数对应位不同,结果位才是1
~ 按位取反 ~$a 把每一位的0变1,1变0
<< 左移 a<<a<<b 把a的位向左移a的位向左移b位
>> 右移 a>>a>>b 把a的位向右移a的位向右移b位

按位与(&)示例:

<?php
$a = 6;  // 二进制:110
$b = 3;  // 二进制:011
echo $a & $b;  // 二进制010 = 十进制2
?>

只有两边都是1的位才保留1,其余归零,所以110 & 011得到010,也就是2。

按位或(|)示例:

<?php
$a = 6;  // 110
$b = 3;  // 011
echo $a | $b;  // 111 = 7
?>

只要有一边是1就置1,所以结果是111,即7。

按位异或(^)示例:

<?php
$a = 6;  // 110
$b = 3;  // 011
echo $a ^ $b;  // 101 = 5
?>

两边不同得1,相同得0,所以110 ^ 011 = 101,即5。

本节课程知识要点:位运算里有个很实用的技巧——用异或来交换两个整数,不需要借助临时变量。当然现在PHP中可读性比炫技更重要,但理解这个原理对底层思维有帮助。另外左移一位等价于乘以2,右移一位等价于除以2并向下取整,处理大循环的性能优化时可以留意这一点。

按位取反(~)示例:

<?php
$num = 5;
echo ~$num;  // 输出:-6
// 公式:~n = -(n + 1)
?>

左移(<<)和右移(>>)示例:

<?php
$a = 6;
echo $a << 3;  // 6 * 2 * 2 * 2 = 48

$b = 24;
echo $b >> 3;  // 24 / 2 / 2 / 2 = 3
?>

四、比较运算符

比较运算符用来判断两个值之间的关系,结果是布尔值(truefalse)。它们是条件语句和循环的根基。

运算符 名称 示例 说明
== 等于 a==a==b 值相等即true(类型可不同)
=== 全等 a===a===b 值和类型都相等才true
!= 或 <> 不等于 a!=a!=b 值不相等即true
!== 不全等 a!==a!==b 值或类型不相等即true
< 小于 a<a<b  
> 大于 a>a>b  
<= 小于等于 a<=a<=b  
>= 大于等于 a>=a>=b  
<=> 太空船 a<=>a<=>b a<a<b返回-1,相等返回0,a>a>b返回1

示例:

<?php
$userAge = 20;
$Threshold = 18;

if ($userAge >= $Threshold) {
    echo "已成年,可进入\n";
}

// 太空船运算符(PHP 7+)
echo 5 <=> 10;  // 输出:-1
echo 10 <=> 10; // 输出:0
echo 15 <=> 10; // 输出:1
?>

为什么用===而不用====会做类型转换再比较,比如0 == '0'结果是true0 == ''也是true,这在很多业务场景里会埋下隐患。===要求两边类型也一致,杜绝了隐式转换带来的意外。我个人的原则是:除非你明确需要利用类型转换的宽松比较特性,否则一律用===!==。太空船运算符在写排序回调函数时特别简洁,尤其是usort()配合<=>能让代码少好几行。

五、递增/递减运算符

这两个一元运算符专门用来给变量加1或减1,分前缀和后缀两种形态。

运算符 名称 示例 说明
++$a 前缀递增 ++$a 先加1,再返回$a
$a++ 后缀递增 $a++ 先返回$a,再加1
--$a 前缀递减 --$a 先减1,再返回$a
$a-- 后缀递减 $a-- 先返回$a,再减1

示例:

<?php
$counter = 10;

$result = ++$counter;  // 先加到11,再赋给$result
echo "前缀递增:counter={$counter}, result={$result}\n";
// 输出:counter=11, result=11

$counter = 10;
$result = $counter++;  // 先把10赋给$result,再加到11
echo "后缀递增:counter={$counter}, result={$result}\n";
// 输出:counter=11, result=10
?>

前缀和后缀的差别只有在“赋值和递增同时发生”的表达式里才体现。单独一行写$i++;时,两者效果没区别。在循环中,for($i=0; $i<10; $i++)for($i=0; $i<10; ++$i)在PHP里性能差异微乎其微,选哪个主要看团队习惯,我个人倾向$i++,因为它更贴近“用过之后再递增”的直觉。

六、逻辑运算符

逻辑运算符用于组合多个条件表达式,构建更复杂的判断逻辑。

运算符 名称 示例 说明
&& 逻辑与 a && b 两边都为true才返回true
|| 逻辑或 a∥∥a∥∥b 任一边为true就返回true
! 逻辑非 !$a 取反
and 逻辑与 aandaandb 同&&,但优先级不同
or 逻辑或 aoraorb 同||,但优先级不同
xor 逻辑异或 axoraxorb 一真一假才返回true

示例:

<?php
$hasTicket = true;
$hasID = false;

if ($hasTicket && $hasID) {
    echo "可以入场\n";
} else {
    echo "禁止入场\n";  // 会输出这行
}

// 优先级差异演示
$result = true || false && false;
// 大多数人以为(false && false)先算,|| 优先级更高,实际||先算
var_dump($result);  // true
?>

本节课程知识要点&&and||or在逻辑功能上一样,但优先级不同&&的优先级高于and||高于or。这意味着$a = true or false这行代码,=的优先级比or高,所以$a会先被赋值为true,然后or false部分根本不执行。如果想用or做条件赋值,得加括号。这个坑我早年在写数据库连接$conn = mysql_connect(...) or die(...)时踩过,后来就统一只用&&||了,避免优先级带来的困惑。

七、字符串运算符

PHP里字符串拼接用的不是加号,而是点号.。这一点和JavaScript、Java等语言不同,初学PHP时要特别适应一下。

运算符 名称 示例 说明
. 连接 a.a.b 把a和a和b拼接成一个字符串
.= 连接后赋值 a.=a.=b 等价于a=a=a . $b

示例:

<?php
$firstName = "代码号";
$lastName = "学习编程";
$fullName = $firstName . " " . $lastName;
echo $fullName;  // 输出:代码号 学习编程

// 追加内容
$breadcrumb = "首页";
$breadcrumb .= " > 课程中心";
$breadcrumb .= " > PHP基础";
echo $breadcrumb;  // 输出:首页 > 课程中心 > PHP基础
?>

拼接大量字符串时,用.直接连比用双引号内嵌变量效率高一些,因为PHP不需要解析整个字符串去寻找变量。不过在模板输出场景,双引号内嵌变量可读性好很多,这个取舍要根据实际情况来定。

八、数组运算符

数组运算符主要用来合并和比较数组。

运算符 名称 示例 说明
+ 联合 a+a+b 把b中不重复的键追加到b中不重复的键追加到a后面
== 相等 a==a==b 键值对相同即true
=== 全等 a===a===b 键值对相同且顺序和类型也相同
!= 或 <> 不等 a!=a!=b  
!== 不全等 a!==a!==b  

示例:

<?php
$frontEnd = ["html" => "结构", "css" => "样式"];
$backEnd  = ["php" => "逻辑", "css" => "也能写样式"];

// 联合:重复键保留左边数组的值
$fullStack = $frontEnd + $backEnd;
print_r($fullStack);
/* 输出:
Array (
    [html] => 结构
    [css] => 样式      // 保留了$frontEnd的
    [php] => 逻辑
)
*/
?>

个人建议:数组联合+array_merge()的行为不一样,前者保留左边数组的重复键值,后者用右边数组的覆盖左边。不少人在需要合并数组时顺手用+,结果发现数据没变,就是因为这个差异。要先搞清楚自己是要“保留原始值”还是“后者覆盖前者”,再选对应的操作方式。

九、类型运算符

PHP里只有一个类型运算符:instanceof。它用来检测一个对象是否属于某个类,或者该类的子类,或者实现了某个接口。

示例:

<?php
class Student {}
class VipStudent extends Student {}

$xiaoming = new VipStudent();

var_dump($xiaoming instanceof VipStudent);  // true
var_dump($xiaoming instanceof Student);     // true,子类对象也是父类的实例
var_dump($xiaoming instanceof Teacher);     // false,没有继承关系
?>

instanceof在大型项目里经常配合依赖注入使用。比如接收一个参数时,先检查它是不是指定接口的实例,不是就直接抛异常,比运行时才发现方法不存在要安全得多。

十、执行运算符

PHP用反引号`(键盘上~那个键,不是单引号)来执行服务器上的shell命令,效果等同于shell_exec()函数。

示例:

<?php
// 在Windows上列出当前目录的php文件
$output = `dir *.php`;
echo $output;
?>

这个运算符在开发环境快速调用系统命令很方便,但在生产环境要极其谨慎。任何用户输入拼接到反引号里都可能造成命令注入漏洞,所以涉及表单输入的场景,不要用执行运算符。

十一、错误控制运算符

@符号放在表达式前,可以抑制该表达式产生的错误信息。

示例:

<?php
// 不加@,打开不存在文件会报Warning
$handle = @fopen("不存在的文件.txt", "r");
// 加了@,错误信息被吞掉,$handle为false
if (!$handle) {
    echo "文件打开失败,已静默处理\n";
}
?>

个人见解@是一把双刃剑。表面上看代码没报错了,但问题并没解决,只是被藏起来了。而且@会拖慢执行速度,因为PHP需要临时关闭错误报告再恢复。与其用@,不如花一点时间写if (file_exists(...))做前置检查,或者用try...catch做异常处理。我自己的代码里几乎不用@,只在某些遗留系统维护时为了避免改不动老逻辑才偶尔用它兜底。

PHP运算符优先级

当一个表达式里有多种运算符时,PHP按照固定的优先级顺序来决定先算谁。这里列出主要几个优先级层级,从高到低:

优先级 运算符 结合方向
最高 clone, new
  **
  ++ -- ~ (类型转换) @
  instanceof
  !
  * / %
  + - .
  << >>
  < <= > >=
  == != === !== <> <=>
  &
  ^
  |
  &&
  ||
  ?:
  = += -= 等赋值运算符
  and
  xor
最低 or

示例:

<?php
// 下面表达式按什么顺序算?
$result = 20 + 8 * 16 / 4 - 9 % 4;

/*
 * 步骤拆解:
 * 8 * 16 = 128      (*和/同级,从左到右)
 * 128 / 4 = 32      (继续左到右)
 * 9 % 4 = 1         (%和*/同级)
 * 20 + 32 = 52      (+和-同级)
 * 52 - 1 = 51       (最终结果)
 */
echo $result;  // 51
?>

本节课程知识要点:不要靠记忆来排查优先级问题,合理的括号才是正道。哪怕你知道*+先算,写(8 * 16) / 4也比裸写8 * 16 / 4让后来看代码的人更舒服。尤其在&&||andor混用或者和赋值运算符一起出现时,多加括号能省去大量调试时间。这也是为什么很多团队的PHP编码规范里会直接要求“涉及两个以上不同运算符时,必须用括号明确优先级”。

← PHP数据类型:从松散类型到精准掌控 PHP注释:被低估的代码维护利器 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号