PHP 内置函数字典:按类别分组,每组给函数签名、可运行示例、常见坑与边界。覆盖日常 90% 的场景。
1. 字符串判断:str_contains / starts_with / ends_with(8.0+)
描述
三个语义直白的判断函数,取代 strpos !== false 的老写法。
语法和示例
<?php
str_contains('hello world', 'world'); // true
str_contains('hello', ''); // true(空串恒含!)
str_starts_with('hello', 'he'); // true
str_ends_with('hello', 'lo'); // true
// 大小写不敏感:先规范化
str_contains(strtolower($s), strtolower($needle));
// 老写法(7.x 及以前)
strpos('hello', 'ell') !== false;注意事项
- 空 needle 恒返回 true——用前判空
- 三者都区分大小写,且不支持正则
- strpos 返回 0 时 if (strpos(…)) 会误判为 false——必须 !== false
- 多字节安全:这些函数按字节比较,UTF-8 中文比较通常没问题(除非大小写变换)
- 7.4 及以下无此函数,升级兼容层需注意
2. 字符串截取:substr / mb_substr
描述
substr(string $s, int $offset, ?int $length = null): string 按字节截取;mb_substr 按字符截取(中文必须用它)。负偏移从尾部算。
语法和示例
<?php
substr('hello', 1, 3); // 'ell'
substr('hello', -2); // 'lo'
substr('hello', 0, -1); // 'hell'(负长度=去掉末尾 n 个)
mb_substr('你好世界', 1, 2); // '好世'(按字符)
// 截取摘要(中文安全)
function excerpt(string $s, int $n = 60): string {
return mb_strlen($s) > $n ? mb_substr($s, 0, $n) . '…' : $s;
}
// 按分隔符取段
explode(',', 'a,b,c')[1];注意事项
- substr 按字节切中文会切碎字符(产生乱码)——中文一律 mb_substr
- 负 length 表示「去掉末尾 n 个字节」,与负 offset 语义不同
- mb_substr 需要 mbstring 扩展(默认启用)
- 偏移超出长度返回空字符串,不报错
- 长度参数为 null 时取到末尾(8.0 起可为 null,7.x 用省略参数)
3. 字符串替换:str_replace / preg_replace
描述
str_replace 字面替换(可数组批量);preg_replace 正则替换(支持回调与后向引用)。第四参返回替换次数。
语法和示例
<?php
str_replace('a', 'b', 'banana'); // 'bbnbnb'
str_replace(['a','b'], 'x', $s); // 多对一
str_replace(['a','b'], ['x','y'], $s); // 成对(按序对应)
$n = 0;
str_replace('a', 'b', $s, $n); // $n 是替换次数
// 正则替换 + 后向引用
preg_replace('/(\d{4})-(\d{2})/', '$2/$1', '2026-10');
// 回调替换
preg_replace_callback('/\w+/', fn($m) => strtoupper($m[0]), $s);
preg_replace('/\s+/', ' ', trim($s));注意事项
- str_replace 按顺序替换,可能产生二次替换(替换结果又含被替换串时)
- preg_replace 后向引用用 $1 或 \\1,注意 PHP 字符串里 $ 会被插值——用单引号
- preg_replace 支持 /e 修饰符已是历史(7.0 移除),计算用 callback
- 第四参计数对数组替换时统计总次数
- 正则替换失败返回 null(需检查 preg_last_error)
4. 字符串修剪与大小写:trim / ucfirst / mb_strtolower
描述
trim 去首尾空白(或指定字符集);大小写函数中 strtoupper 只处理 ASCII,Unicode 用 mb_ 系。
语法和示例
<?php
trim(' x '); // 'x'
trim('/a/b/', '/'); // 'a/b'(指定字符集)
ltrim($s, " \t"); // 只去左侧
rtrim($s); // 只去右侧
strtoupper('hello'); // 'HELLO'
ucfirst('hello'); // 'Hello'
ucwords('hello world'); // 'Hello World'
mb_strtolower('HÉLLO'); // 'héllo'(Unicode 正确)
// 中文无大小写概念,mb_ 主要处理带音标/希腊/西里尔字母注意事项
- trim 第二参是「字符集」不是「字符串」——trim($s, ‘ab’) 会去掉任意 a 或 b
- strtoupper 对非 ASCII 无效(é 不变),需 mb_strtoupper
- trim 默认去 \\t\\n\\r\\0\\x0B 与空格,不含全角空格(需显式指定)
- ucwords 按空格分词,中文/连字符分隔的词不会大写
- str_pad 可用于补零/对齐,不是 trim 的反向操作
5. 字符串分割与拼接:explode / implode / str_pad
描述
explode 按分隔符拆成数组(可限次);implode 数组转字符串;str_pad 补齐定长。
语法和示例
<?php
explode(',', 'a,b,c'); // ['a','b','c']
explode(',', 'a,b,c', 2); // ['a','b,c'](最多 2 段)
implode('-', ['a','b']); // 'a-b'(也可 implode($arr) 直接连)
implode(',', array_map('trim', $arr));
// 补齐
str_pad('7', 3, '0', STR_PAD_LEFT); // '007'
str_pad('ab', 5, '*', STR_PAD_BOTH); // '*ab**'
// 换行转 <br>
nl2br("a\nb"); // a<br />b
// 数字格式化
number_format(1234567.891, 2); // '1,234,567.89'注意事项
- explode 的 limit 为负时表示「去掉末尾 N 个元素」
- implode 参数顺序两种都支持,但统一用 implode($glue, $array) 更清晰
- explode 遇空分隔符抛 ValueError(8.0+;旧版返回 false)
- str_pad 是字节对齐——中文补齐长度会算错(用 mb 方案或按字符计算)
- number_format 默认四舍五入,参数变化会改变小数位与分隔符
6. 数组增删:array_push / pop / shift / unshift / splice
描述
push/pop 操作尾部,shift/unshift 操作头部,splice 任意位置插删。均原地修改并可能重排键。
语法和示例
<?php
$q = [];
$q[] = 'a'; // push(更快,无函数调用)
array_push($q, 'b', 'c'); // 一次加多个
array_pop($q); // 'c'(尾部弹出)
array_shift($q); // 'a'(头部弹出,O(n) 重排)
array_unshift($q, 'head'); // 头部插入
// splice:任意位置删除/插入
array_splice($arr, 1, 2); // 删下标 1 起 2 个,返回被删的
array_splice($arr, 1, 0, ['x']); // 在 1 处插入(0 表示不删)
// 删除键
unset($arr['k']);注意事项
- array_shift/unshift 是 O(n)(要重排所有数字键),大数组频繁头部操作很慢——用 SplQueue
- $arr[] = x 比 array_push 快很多(无函数调用开销)
- array_splice 会重排数字键,字符串键保留
- unset 不重排键,json_encode 会变对象——用 array_values 重建
- splice 的替换参数可以是单值也可数组
7. 数组检索:in_array / array_search / array_key_exists
描述
in_array 查值(默认松散,务必传 true);array_search 返回值对应的键;array_key_exists 只查键(null 值也返回 true)。
语法和示例
<?php
in_array(1, ['1', 1]); // true(松散,坑)
in_array(1, ['1', 1], true); // true(严格命中 1)
in_array('1', ['1', 1], true); // true(命中字符串 '1')
in_array('2', ['1', 1], true); // false
array_search('b', ['a','b','c']); // 1(键)
array_search('x', $arr, true); // false 或键 0(须 !== false)
array_key_exists('k', $map); // 键存在(值 null 也 true)
isset($map['k']); // 键存在且值非 null
array_keys($map); array_values($map);注意事项
- in_array 默认松散比较,’1′ 与 1 会被认为是同一值——永远传第三个参 true
- array_search 未找到返回 false,但找到下标 0 也是 falsy——必须 !== false
- array_key_exists 与 isset 的区别在 null 值:isset 对 null 返回 false
- in_array 是 O(n) 线性扫描,大数组频繁查值应改用键查找(isset/array_key_exists)
- 多维数组的 in_array 不做递归比较(要 array_search 配回调或用 array_filter)
8. 数组排序:sort / asort / ksort / usort
描述
排序函数族按「排序依据 + 是否保键」交叉:sort/rsort 按值重排键,asort/arsort 按值保键,ksort/krsort 按键,usort/uasort/uksort 自定义比较。
语法和示例
<?php
$arr = [3, 1, 2];
sort($arr); // [1,2,3] 重排键
rsort($arr); // [3,2,1]
$map = ['b' => 2, 'a' => 1];
asort($map); // 按值升序,保键
ksort($map); // 按键升序
// 自定义
usort($items, fn($a, $b) => $a['age'] <= > $b['age']);
usort($items, fn($a, $b) => $b['score'] <=> $a['score']); // 降序
uasort($map, fn($a, $b) => $a <=> $b); // 保键
uksort($map, 'strcmp'); // 按键自定义注意事项
- sort 系列是原地修改且返回 bool(不是排序后的数组)
- usort 的比较函数必须返回整数:用 飞船操作符最简洁
- 比较函数里不要做 IO/重计算——它会被调用 O(n log n) 次
- natsort/strnatcasecmp 用于「自然排序」(file2 在 file10 前)
- 保存键的排序(asort/uasort)是关联数组最常用,sort 只适合索引数组
9. 数组集合运算:merge / +/ intersect / diff
描述
array_merge 数字键重排、字符串键后者覆盖;+ 保留左侧优先;intersect/diff 按值比较,带 key 变体按「键值对」比较。
语法和示例
<?php
$a = ['x' => 1, 'y' => 2];
$b = ['y' => 20, 'z' => 30];
array_merge($a, $b); // x=1, y=20(后者覆盖), z=30
$a + $b; // x=1, y=2(左侧优先), z=30
// 索引数组差异
array_merge([1,2], [3]); // [1,2,3](数字键重排)
[1,2] + [3]; // [1,2](右侧被覆盖丢弃)
// 集合运算
array_intersect($a, $b); // 值交集
array_diff($a, $b); // 在 a 不在 b
array_intersect_key($a, $b); // 键交集
array_diff_key($a, $b);
array_intersect_assoc($a, $b); // 键值都要相同注意事项
- array_merge 对数字键重排编号(追加),对字符串键覆盖——行为不对称
- + 运算符不是「并集」,是「左优先合并」,右侧相同键被丢弃
- array_intersect 只比值不比键,array_intersect_assoc 才比值+键
- 多维数组的 diff/intersect 按「数组相等」比较,不递归
- array_merge_recursive 遇重复字符串键会变成数组(不是覆盖)
10. 数组映射过滤归约:array_map / filter / reduce
描述
array_map 对每个元素应用回调(支持多数组并行);array_filter 按回调筛选(默认去 falsy);array_reduce 归约为单值。
语法和示例
<?php
array_map(fn($x) => $x * 2, [1,2,3]); // [2,4,6]
array_map(null, [1,2], ['a','b']); // [[1,'a'], [2,'b']] 拉链
array_map(fn($a,$b) => $a + $b, [1,2], [10,20]); // [11,22]
// filter 保留原键!
array_filter([0, 1, '', 2]); // [1 => 1, 2 => 2]
array_values(array_filter($arr, fn($x) => $x > 0)); // 重排键
array_filter($arr, 'is_string'); // 回调可用函数名
// reduce
array_reduce([1,2,3], fn($c, $x) => $c + $x, 0); // 6
array_sum([1,2,3]); array_product([2,3]);注意事项
- array_filter 保留原键,前端 JSON 会变成对象——几乎都要 array_values 包一层
- array_map 回调为 null 时是「拉链」模式,不是恒等映射
- array_map 多数组时以最长为准,短数组补 null(注意空指针)
- array_reduce 初始值给了才安全(不给时首元素当初始值,空数组返回 null)
- 这些函数都不递归,多维数组需 array_walk_recursive
11. 数组切片与重组:slice / chunk / column / flip
描述
slice 取片段(可保键);chunk 分批;column 抽列建映射;flip 键值互换;combine 两数组配对。
语法和示例
<?php
array_slice($arr, 1, 2); // 偏移 1 取 2(数字键重排)
array_slice($arr, 1, 2, true); // 保键
array_slice($arr, -2); // 最后两个
array_chunk($arr, 100); // 分批处理大数据
array_column($rows, 'name'); // ['a','b']
array_column($rows, 'name', 'id'); // [1 => 'a', 2 => 'b']
array_flip(['a' => 1]); // [1 => 'a'](值必须可作键)
array_combine(['a','b'], [1,2]); // ['a' => 1, 'b' => 2]
array_reverse($arr, true); // 保键反转
array_unique($arr); // 去重(保首个键)注意事项
- array_slice 默认重排数字键;要保键传第四参 true
- array_column 第二参可为 null(整个子数组),第三参做索引键
- array_flip 要求值都是 int/string——对象或数组会警告并跳过
- array_combine 两数组长度不等会抛 ValueError(8.0+)
- array_unique 用松散字符串比较,’1′ 与 1 会判重——复杂场景自己实现
12. 数学函数:intdiv / fmod / round / bc*
描述
整数除法 intdiv 避免浮点;fmod 取余(浮点);round 四舍五入(PHP 与多数语言不同,.5 向远离零);bc 系任意精度。
语法和示例
<?php
intdiv(7, 2); // 3
7 % 2; // 1(符号跟被除数:-7 % 2 = -1)
fmod(7.5, 2); // 1.5
round(2.5); // 3(四舍五入,不是银行家舍入)
round(-2.5); // -3
round(1.955, 2); // 1.96
ceil(1.2); floor(1.8); abs(-3);
max(1, 5, 3); min([2, 8]);
pow(2, 10); sqrt(16); log(100, 10);
mt_rand(1, 100); random_int(1, 100); // 后者密码学安全
// 任意精度(算钱)
bcadd('0.1', '0.2', 2); // '0.30'
bcmul('19.99', '3', 2); // '59.97'
bcdiv('1', '3', 4); // '0.3333'注意事项
- PHP 的 round 是「四舍五入远离零」,与 Python 的银行家舍入不同
- 算钱不要用 float(0.1 + 0.2 得到 0.30000000000000004)——用 bcmath 或整数分
- intdiv 遇除数为 0 抛 DivisionByZeroError(% 也是)
- mt_rand 不是密码学安全,令牌/盐用 random_int / random_bytes
- bc 系返回字符串,比较要用 bccomp 不是 ==
13. 日期时间:date / strtotime / DateTimeImmutable
描述
date 格式化时间戳;strtotime 解析人类可读时间;DateTimeImmutable 面向对象不可变(推荐)。
语法和示例
<?php
date('Y-m-d H:i:s'); // 当前
date('Y-m-d', strtotime('+30 days'));
strtotime('next Monday');
strtotime('2026-10-29 15:00:00');
time(); microtime(true);
// 面向对象(推荐)
$dt = new DateTimeImmutable('2026-10-29 15:00');
$dt->format('Y年m月d日');
$dt->modify('+1 month'); // 返回新实例
$dt->getTimestamp();
$dt->setTimezone(new DateTimeZone('UTC'));
// 差值
$a = new DateTimeImmutable('2026-01-01');
$a->diff(new DateTimeImmutable('2026-12-31'))->days;
// 时区
date_default_timezone_set('Asia/Shanghai');注意事项
- strtotime(‘+1 month’) 遇月末会溢出(1 月 31 日 +1 月 → 3 月 3 日),用 modify(‘last day of next month’) 更稳
- date() 依赖 date_default_timezone_set 或 php.ini,跨环境不一致是常见 bug
- date(‘Y-m-d’) 的 m 是补零月份,n 是不补零;容易写混
- 日期比较不要用字符串比较(时区/格式不一致),用时间戳或 DateTime 比较
- DateTimeImmutable 的 modify 返回新对象,别以为改了原对象
14. 文件系统函数:file_get_contents / fopen / glob
描述
读文件四件套:file_get_contents(整读)、file(按行入数组)、fopen+fgets(流式)、readfile(直接输出)。写用 file_put_contents。
语法和示例
<?php
$txt = file_get_contents('a.txt');
file_put_contents('a.txt', $data, FILE_APPEND | LOCK_EX);
$lines = file('a.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// 流式处理大文件
$fh = fopen('big.log', 'r');
while (!feof($fh)) {
$line = fgets($fh); // 逐行
}
fclose($fh);
// 目录操作
mkdir('/tmp/x/y', 0755, true); // 递归
scandir('/etc');
glob('/tmp/*.log'); // 通配符
is_file($p); is_dir($p); file_exists($p);
filesize($p); filemtime($p);
copy($a, $b); unlink($a); // 复制/删除
rename($a, $b); // 重命名/移动注意事项
- file_get_contents 读超大文件会 OOM——必须用流式
- 写文件不加 LOCK_EX 在并发下可能写入交错(多进程日志场景)
- mkdir 的 recursive=true 才能建多级目录,权限参数受 umask 影响
- glob 返回 false 而非空数组(无匹配时),要判 is_array
- 文件路径含中文/空格时用绝对路径,避免编码与转义问题
15. JSON:json_encode / json_decode
描述
encode 推荐 UNESCAPED_UNICODE + THROW_ON_ERROR;decode 传 assoc=true 返回关联数组(否则 stdClass)。
语法和示例
<?php
json_encode($data,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR);
json_decode($json, true, 512, JSON_THROW_ON_ERROR); // 数组
json_decode($json); // stdClass
// 不抛异常时的错误检查
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException(json_last_error_msg());
}
// 8.3+ 只校验不转换
json_validate($str);
// 输出数组还是对象:连续数字键会被编码成数组
json_encode([0 => 'a', 2 => 'b']); // {"0":"a","2":"b"}(跳键变对象)注意事项
- 中文默认被转成 \\uXXXX,必须 JSON_UNESCAPED_UNICODE
- JSON_THROW_ON_ERROR 需要 PHP 7.3+,旧版只能检查 json_last_error
- json_decode 大整数会精度丢失(转 float),超范围数字用 JSON_BIGINT_AS_STRING
- 数组键非连续时 encode 成对象,前端会拿到 object 而非 array——用 array_values 修正
- 解码深度默认 512 层,恶意嵌套 JSON 可能耗尽内存(可传更小值)
16. 正则:preg_match / preg_match_all / preg_replace
描述
PCRE 系四个主力:match(首次)、match_all(全部)、replace(替换)、split(分割)。分隔符可自定义,常用 /。
语法和示例
<?php
preg_match('/(\d{4})-(\d{2})/', '2026-10', $m);
// $m[0] 整体,$m[1]/$m[2] 捕获组
preg_match_all('/#(\w+)/', '#a #b', $all);
// $all[1] = ['a','b'];PREG_SET_ORDER 按匹配分组
preg_match('/\d+/', $s, $m, PREG_OFFSET_CAPTURE); // 带偏移
preg_replace('/\s+/', ' ', $s);
preg_split('/[,;\s]+/', $s, -1, PREG_SPLIT_NO_EMPTY);
preg_grep('/^a/', $arr);
// 命名捕获
preg_match('/(?<year>\d{4})/', '2026', $m);
$m['year'];
// 错误检查
preg_match('/[/', $s, $m); // 语法错,返回 false
preg_last_error_msg();注意事项
- 模式要带分隔符(/pattern/modifiers),不能只写裸正则
- 中文匹配需 u 修饰符(/中文/u),否则按字节匹配出错
- preg_replace 的 $1 在双引号字符串里会被 PHP 插值——用单引号或 \\1
- preg_match 返回 0(不匹配)或 false(出错),区分两者要 preg_last_error
- 超长文本 / 灾难性回溯会让正则卡死,限制输入长度
17. 类型判断与变量函数:is_* / empty / isset / get_debug_type
描述
is_* 家族判断类型(严格);gettype 返回旧式类型名(8.0 用 get_debug_type);empty 判 falsy;isset 判存在且非 null。
语法和示例
<?php
is_int(1); is_float(1.0); is_string('a'); is_bool(true);
is_array([]); is_object(new stdClass); is_null(null);
is_numeric('1.5'); // true
is_numeric('0x1A'); // false(不认十六进制串)
is_callable('strlen');
function_exists('strlen'); class_exists('DateTime');
// 8.0+ 更精确的类型名
get_debug_type(1); // 'int'(gettype 给 'integer')
// 判空
empty($v); // '' 0 '0' [] null false 都为 true
isset($v); // 已定义且非 null
// 调试
var_dump($x); print_r($x); var_export($x);
// 序列化
serialize($obj); unserialize($str, ['allowed_classes' => false]);注意事项
- empty(‘0’) 为 true——判断「有内容」不能用 empty
- isset 对 null 返回 false;array_key_exists 才只看键是否存在
- is_numeric 接受 ‘1e3’、’ 42’、’+1.5’,不接受带单位的字符串
- unserialize 未限制 allowed_classes 有对象注入风险(只反序列化可信数据)
- is_callable 对私有方法/魔术方法 __call 的判断会返回 true,调不一定成功
18. 输出与响应头:header / http_response_code / setcookie
描述
header 发送原始 HTTP 头(必须在任何输出前);http_response_code 设状态码;setcookie 设 Cookie(8.0 支持数组参数)。
语法和示例
<?php
header('Content-Type: application/json; charset=utf-8');
header('Location: /login', true, 302);
http_response_code(404);
// Cookie(8.0+ 数组语法)
setcookie('token', $v, [
'expires' => time() + 3600,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
// 输出缓冲
ob_start();
echo 'x';
$buf = ob_get_clean();
// 下载文件
header('Content-Disposition: attachment; filename="a.csv"');
readfile('a.csv');注意事项
- header 前有任何输出(含 BOM、空格)都会报 headers already sent——用 ob_start 兜底
- setcookie 必须早于输出;新代码优先数组参数(可设 samesite/httponly)
- HTTP 状态码设置在 header 之前更稳;http_response_code 内部就是设 header
- CSV/中文文件名要用 RFC 5987 的 filename* 编码,否则浏览器乱码
- ob_start 后记得 ob_end_flush 或 ob_get_clean,否则缓冲泄漏到下一请求
19. 错误与日志:error_log / set_error_handler
描述
error_log 写错误日志(可选目标);trigger_error 产生用户级错误;set_error_handler 把 warning 转异常统一处理。
语法和示例
<?php
error_log((string) $e); // 对象要显式转字符串(strict 模式)
error_log($msg, 3, '/tmp/app.log'); // 追加到文件
trigger_error('自定义警告', E_USER_WARNING);
// 统一错误处理(入口处)
set_error_handler(function ($no, $msg, $file, $line) {
if (!(error_reporting() & $no)) return false; // 尊重 @ 抑制
throw new ErrorException($msg, 0, $no, $file, $line);
});
error_reporting(E_ALL);
set_exception_handler(function (Throwable $e) {
error_log("未捕获: " . $e->getMessage());
});
// ini
ini_set('log_errors', '1');
ini_set('error_log', '/var/log/php-error.log');注意事项
- strict_types 下 error_log($obj) 会报 TypeError,必须 (string) 转
- set_error_handler 捕不到 Fatal/Parse Error(那些走 shutdown function)
- 自定义 error handler 里要检查 error_reporting() 以尊重 @ 抑制符
- error_log 的 message_type 只有 0/1/3/4 四种,3 才是指定文件
- 生产必须关 display_errors(会泄露路径),开 log_errors
20. 密码学:password_hash / hash / hash_equals
描述
存密码只用 password_* 四件套(自动加盐 + 自适应);hash 用于摘要;hash_equals 做常量时间比较防时序侧信道。
语法和示例
<?php
// 密码存储(唯一正确姿势)
$hash = password_hash('明文', PASSWORD_DEFAULT); // bcrypt/argon2id
password_verify('明文', $hash); // 验证
password_needs_rehash($hash, PASSWORD_DEFAULT); // 需升级算法时
// 摘要
hash('sha256', $data);
hash_hmac('sha256', $data, $key); // 带密钥(防篡改)
hash_file('sha256', '/path/big');
// 常量时间比较
hash_equals($known, $userInput); // 防时序攻击
// 随机
random_bytes(16); random_int(1, 100);注意事项
- md5/sha1 已不适合安全(可碰撞),只用于校验和
- 不要自己 salt + hash,password_hash 已内置且配好迭代次数
- password_verify 第二个参数必须是 hash,顺序不能反
- hash_equals 只对字符串有效,两个参数长度不同时返回 false(不会崩)
- 比较 token/签名永远用 hash_equals,=== 有定时攻击风险