PHP「标准库」= 默认启用的核心扩展集合。每条给扩展定位、高频 API、可用示例与坑。排序按日常使用频率。
1. PDO – 数据库统一抽象层
描述
跨数据库的统一接口(MySQL/PostgreSQL/SQLite 等)。三层:PDO 连接、PDOStatement 语句、PDOException 异常。预处理语句是防注入的根本。
语法和示例
<?php
$pdo = new PDO('mysql:host=db;dbname=app;charset=utf8mb4', $u, $p, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 真预编译
PDO::ATTR_STRINGIFY_FETCHES => false,
]);
// 查询
$stmt = $pdo->prepare('SELECT id, name FROM users WHERE id > :id');
$stmt->execute(['id' => 5]);
$rows = $stmt->fetchAll(); // 或 fetch() 单行
$id = $pdo->lastInsertId();
// 事务(异常必须回滚)
$pdo->beginTransaction();
try {
$pdo->exec("UPDATE ...");
$pdo->commit();
} catch (Throwable $e) {
$pdo->rollBack();
throw $e;
}注意事项
- EMULATE_PREPARES 为 true 时 LIMIT ? 会被当字符串,导致 SQL 语法错——生产设 false
- 拼接 SQL 字符串 = SQL 注入,永远用 prepare + execute 参数
- 事务里抛异常必须 rollBack,否则连接归还池时残留未提交事务
- fetchAll 大结果集会 OOM——大查询用 fetch 逐行 + 分批处理
- charset 必须写在 DSN 里(charset=utf8mb4),否则中文可能乱码/截断
2. SPL – 标准 PHP 库(数据结构与接口)
描述
内置的数据结构与通用接口:SplStack/SplQueue/SplFixedArray/SplObjectStorage 与 Countable/ArrayAccess/Iterator 等接口。
语法和示例
<?php
$stack = new SplStack();
$stack->push('a'); $stack->pop();
$queue = new SplQueue();
$queue->enqueue('a'); $queue->dequeue();
$fixed = new SplFixedArray(1000); // 定长,省内存
$fixed[0] = 'x';
$storage = new SplObjectStorage(); // 对象作键
$storage[$obj] = 'meta';
// 实现接口让对象可用内置函数
class Bag implements Countable, ArrayAccess, IteratorAggregate {
private array $items = [];
public function count(): int { return count($this->items); }
public function offsetExists($k): bool { return isset($this->items[$k]); }
public function offsetGet($k): mixed { return $this->items[$k] ?? null; }
public function offsetSet($k, $v): void { $this->items[$k] = $v; }
public function offsetUnset($k): void { unset($this->items[$k]); }
public function getIterator(): Iterator { return new ArrayIterator($this->items); }
}注意事项
- SplFixedArray 不能自动扩容(setSize 才改),适合固定长度缓冲
- SplObjectStorage 用对象身份(不是值)作键,等价性判断要注意
- 实现 Countable 后 count($obj) 才可用(否则 TypeError)
- ArrayAccess 只让 $obj[‘k’] 语法可用,不继承数组函数
- SPL 数据结构比数组快在特定场景,别盲目替换普通数组
3. mbstring – 多字节字符串
描述
处理 UTF-8 等多字节编码的字符串扩展。中文相关操作必须用 mb_ 系(str_ 系按字节处理会切碎字符)。
语法和示例
<?php
mb_internal_encoding('UTF-8'); // 全局默认
mb_strlen('中文'); // 2(字符数)
mb_substr('你好世界', 1, 2); // '好世'
mb_strpos('你好', '好'); // 1
mb_str_split('中文abc', 2); // 按字符切
mb_strtolower('HÉLLO'); // Unicode 正确
mb_convert_encoding($s, 'UTF-8', 'GBK');
mb_convert_case($s, MB_CASE_TITLE); // 标题化
// 字符集检测
mb_detect_encoding($s, ['UTF-8', 'GBK'], true);
// 宽度计算(终端对齐)
mb_strwidth('中文'); // 4(全角算 2)注意事项
- strlen/substr 按字节处理,中文会切碎产生乱码
- mb_strlen 第二参可指定编码,未指定用 mb_internal_encoding
- mb_detect_encoding 有误判可能,strict=true 只是更严格不足以保证
- GBK 转 UTF-8 是常见迁移需求,转前必须确认原编码
- 全角/半角混排对齐用 mb_strwidth 而非 mb_strlen
4. curl – HTTP 客户端
描述
发起 HTTP 请求的扩展(比 file_get_contents 可控)。四步:init → setopt → exec → close。支持 Cookie/代理/上传/超时。
语法和示例
<?php
$ch = curl_init('https://api.example.com/v1');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true, // 必须!否则直接输出
CURLOPT_TIMEOUT => 10, // 总超时
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_HTTPHEADER => ['Authorization: Bearer '.$token,
'Content-Type: application/json'],
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($data),
CURLOPT_SSL_VERIFYPEER => true, // 生产必须开
]);
$body = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($body === false) { error_log(curl_error($ch)); }
curl_close($ch);
// 并发(多句柄)
$mh = curl_multi_init(); curl_multi_add_handle($mh, $ch1);
curl_multi_exec($mh, $running); curl_multi_close($mh);注意事项
- 必须设 CURLOPT_RETURNTRANSFER 否则响应直接打印到页面
- CURLOPT_SSL_VERIFYPEER=false 会关闭证书校验(仅本地调试用,生产禁止)
- curl_exec 失败返回 false 而非抛异常,必须显式检查并读 curl_error
- 超时有两级:CONNECTTIMEOUT(建连)与 TIMEOUT(整体)
- PHP 8.0 起 curl_close 是空操作(句柄对象化),但仍建议显式调用
5. session – 会话管理
描述
服务端会话:session_start 生成/读取 session id(默认 Cookie 承载),$_SESSION 存数据。适合传统表单应用。
语法和示例
<?php
session_start(); // 必须在任何输出前
$_SESSION['user_id'] = 42;
$uid = $_SESSION['user_id'] ?? null;
session_regenerate_id(true); // 登录后换 ID 防固定
unset($_SESSION['otp']);
session_destroy(); // 登出(清空服务端)
// 安全配置
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);注意事项
- session_start 前有任何输出会失败(用 ob_start 或确保无白空格)
- 登录成功必须 session_regenerate_id(true),防止会话固定攻击
- session 文件默认存在 /tmp,多服务器部署要改共享存储(Redis/DB)
- session_destroy 只清服务端,客户端 Cookie 需另 setcookie 过期
- 大并发下 session 文件锁会阻塞同用户并发请求(改为 Redis 存储可解
6. filter – 输入校验与净化
描述
filter_input/filter_var 从外部输入安全取值;FILTER_VALIDATE_* 校验(失败返回 false),FILTER_SANITIZE_* 净化(已不推荐用于输出)。
语法和示例
<?php
// 校验(推荐)
$page = filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT,
['options' => ['default' => 1, 'min_range' => 1]];
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$ip = filter_var($candidate, FILTER_VALIDATE_IP,
FILTER_FLAG_IPV4);
$url = filter_var($u, FILTER_VALIDATE_URL);
$bool = filter_var('true', FILTER_VALIDATE_BOOLEAN);
// 数组输入
$ids = filter_input(INPUT_GET, 'ids', FILTER_VALIDATE_INT,
FILTER_REQUIRE_ARRAY);注意事项
- FILTER_SANITIZE_STRING 在 8.1 已废弃——输出转义用 htmlspecialchars
- filter_input 直接读原始输入,不受 $_GET 手动修改影响(更可靠)
- 校验失败返回 false,与合法值 0/” 需区分——先判断 !is_bool
- default 只在「未提供/校验失败」时生效,不等于「可接受任意值」
- 过滤器不替代业务校验(如「年龄必须 18-120」需自己判范围
7. openssl – 加解密与证书
描述
对称/非对称加解密、摘要、证书解析、签名验签。业务中最常用 AES-GCM 与 RSA 签名。
语法和示例
<?php
// AES-256-GCM(认证加密,推荐)
$key = random_bytes(32);
$iv = random_bytes(12);
$cipher = openssl_encrypt($plain, 'aes-256-gcm', $key,
OPENSSL_RAW_DATA, $iv, $tag);
$plainBack = openssl_decrypt($cipher, 'aes-256-gcm', $key,
OPENSSL_RAW_DATA, $iv, $tag);
// 摘要与签名
openssl_digest($data, 'sha256');
openssl_sign($data, $sig, $privateKey, OPENSSL_ALGO_SHA256);
openssl_verify($data, $sig, $publicKey, OPENSSL_ALGO_SHA256);
// 随机(openssl 版,弱于 random_bytes)
openssl_random_pseudo_bytes(16);注意事项
- AES-GCM 的 IV 每次加密必须唯一,复用会彻底破坏安全性
- random_bytes 比 openssl_random_pseudo_bytes 更推荐(CSPRNG 保证更强)
- 加密必须配认证(GCM 或 HMAC),纯 CBC 无认证易被篡改
- 私钥不要硬编码在代码里,从环境变量或密钥管理服务读
- openssl_encrypt 默认 base64 输出,要原始字节加 OPENSSL_RAW_DATA
8. ctype – 字符类型判断(ASCII)
描述
快速判断字符类型:digit/alpha/alnum/space/upper/lower/punct/xdigit。仅支持 ASCII,中文/Unicode 需 mb_ 或正则。
语法和示例
<?php
ctype_digit('123'); // true
ctype_digit('12.3'); // false(含小数点)
ctype_alpha('abc'); // true
ctype_alnum('a1'); // true
ctype_upper('ABC'); // true
ctype_space(" \n\t"); // true
ctype_xdigit('ff'); // true(十六进制)
// 负数/空串都是 false
ctype_digit('-1'); // false
ctype_digit(''); // false
// Unicode 场景
preg_match('/^\p{N}+$/u', $str); // 任意数字
mb_check_encoding($str, 'UTF-8');注意事项
- 空字符串对任何 ctype 都返回 false——需要「空也算通过」时先判空
- 只处理 ASCII,中文数字(如 ‘123’ 全角)不识别
- ctype_digit(‘0123’) 返回 true(不判前导零,与数值校验不同)
- 比正则快但功能单一;复杂规则用 filter_var 或正则
- 参数非字符串(如 int)会被转成字符串再判断,行为可能与预期不同
9. SimpleXML / DOM – XML 处理
描述
SimpleXML 属性访问式(简单场景);DOM 全功能 W3C API(复杂场景)。JSON 时代仍会在 RSS/SOAP/配置文件遇到 XML。
语法和示例
<?php
// SimpleXML
$xml = simplexml_load_string($rss);
foreach ($xml->channel->item as $item) {
echo (string) $item->title; // 必须转 string
echo $item->link['href']; // 属性
}
// DOM(更可控)
$doc = new DOMDocument();
$doc->loadXML($xmlString);
$xpath = new DOMXPath($doc);
foreach ($xpath->query('//item/title') as $node) {
echo $node->nodeValue;
}
// 生成 XML
$doc2 = new DOMDocument('1.0', 'UTF-8');
$root = $doc2->createElement('root');
$doc2->appendChild($root);
$doc2->saveXML();注意事项
- SimpleXML 的节点是对象,直接 echo 前要 (string) 转换,否则打印对象结构
- SimpleXML 不能处理命名空间复杂的文档,用 DOM/XPath
- loadXML 默认解析外部实体(XXE 漏洞)——用 LIBXML_NOENT 需谨慎,禁外部实体设 libxml_disable_entity_loader
- DOM 操作大量节点时内存开销大,超大 XML 用 XMLReader 流式
- CDATA 内容需 ->textContent 或 (string) 转换才不含标签
10. mysqli – MySQL 原生扩展
描述
MySQL 专用扩展:预处理、事务、异步查询、多语句。比 PDO 多的特性在特定场景有用,但新项目建议 PDO。
语法和示例
<?php
$db = new mysqli('host', 'user', 'pass', 'app');
$db->set_charset('utf8mb4');
// 预处理(类型字符串 i/d/s/b)
$stmt = $db->prepare('SELECT id FROM users WHERE id = ? AND name = ?');
$stmt->bind_param('is', $id, $name);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {}
// 事务
$db->begin_transaction();
$db->commit(); $db->rollback();
// 原生查询
$res = $db->query('SELECT 1');
$db->error;注意事项
- bind_param 的类型字符串必须精确:’i’ 整数、’d’ 浮点、’s’ 字符串、’b’ blob
- mysqli 只支持 MySQL,跨库需求用 PDO
- get_result 需要 mysqlnd 驱动(部分环境不可用,需 bind_result)
- 未 set_charset 会导致中文乱码(初始化连接后第一件事)
- 多语句查询(multi_query)有注入风险,避免拼接
11. pcntl / posix – 进程与信号
描述
CLI 下的多进程与信号处理(fork/wait/signal)。Web SAPI(FPM/Apache)下不可用,仅用于命令行脚本与常驻进程。
语法和示例
<?php
$pid = pcntl_fork();
if ($pid === -1) { exit(1); }
if ($pid === 0) {
// 子进程
work();
exit(0);
}
// 父进程
pcntl_wait($status); // 回收,防僵尸
pcntl_signal(SIGTERM, function () { exit(0); });
pcntl_async_signals(true); // 或循环内 pcntl_signal_dispatch
posix_getpid(); posix_kill($pid, SIGKILL);
// 守护化
posix_setsid();注意事项
- Web 环境(FPM)禁用 pcntl,会 fatal error——只用于 CLI
- 子进程退出必须 pcntl_wait,否则僵尸进程累积
- 信号处理需 pcntl_async_signals(true) 或每个循环显式 dispatch
- fork 后子进程继承父进程的文件句柄与数据库连接——注意连接复用问题
- 生产多进程任务建议用队列系统(Redis/SQS)而非手写 fork
12. zlib / ZipArchive – 压缩
描述
zlib 处理 gzip 流(透明压缩);ZipArchive 读写 zip 包(多文件归档)。
语法和示例
<?php
// gzip
$gz = gzopen('a.gz', 'wb9');
gzwrite($gz, $data); gzclose($gz);
$content = gzfile('a.gz'); // 按行读
// zip
$zip = new ZipArchive();
$zip->open('out.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE);
$zip->addFile('a.txt', 'name-in-zip.txt');
$zip->addFromString('b.txt', $content);
$zip->close();
// 解压
$zip->open('in.zip');
$zip->extractTo('/tmp/dir');
$zip->close();注意事项
- ZipArchive::open 失败返回错误码(非 false),要检查返回值
- 解压外部 zip 必须限制路径(zip slip:../../etc/passwd 逃逸)
- gzopen 的模式 ‘wb9’ 中 9 是最高压缩比(CPU 换体积)
- 大文件压缩用流式(gzopen + 分块读写),不要整读入内存
- zip 的 addFile 第二参是包内路径,可自定义目录结构
13. Reflection – 运行时反射
描述
读取类/方法/属性/参数的元数据,可动态调用与修改。依赖注入容器、ORM、序列化库的基石。
语法和示例
<?php
$r = new ReflectionClass(Service::class);
$r->hasMethod('run');
$m = $r->getMethod('run');
$m->getParameters();
foreach ($m->getParameters() as $p) {
$p->getName();
$p->getType()?->getName(); // 8.0 起 getType 返回 ReflectionType
$p->isOptional();
}
// 动态实例化与调用
$obj = $r->newInstance($arg);
$m->invoke($obj, 1, 2);
// 属性
$r->getProperty('x')->setValue($obj, 9);
// 函数
new ReflectionFunction('strlen');
new ReflectionNamedType();注意事项
- 反射有性能开销(比直接调用慢几倍),热路径避免
- 私有成员读取需 PHP 8.1+ 的 setAccessible 已无意义(默认可读),但写仍需注意
- 反射拿到的是编译期结构,运行时动态添加的属性不可见
- 内部类(如 Closure)的部分元数据受限
- 8.1 起 ReflectionType 改为返回 ReflectionNamedType/UnionType,判空写法要更新
14. Composer 生态常备包
描述
Composer 是 PHP 的依赖管理器。虽然这些不是「内置」,但已是事实标准库——生产项目几乎必装。
语法和示例
bash
1. 初始化
composer init
composer require guzzlehttp/guzzle # HTTP 客户端(比 curl 好用)
composer require monolog/monolog # 日志(PSR-3 实现)
composer require vlucas/phpdotenv # .env 配置加载
composer require ramsey/uuid # UUID 生成
composer require nesbot/carbon # 日期增强
composer require php-di/php-di # 依赖注入容器
composer require phpunit/phpunit --dev
composer dump-autoload -o # 生成优化后的自动加载
composer outdated # 检查可升级
// 代码里(自动加载)
require __DIR__ . '/vendor/autoload.php';
$client = new GuzzleHttp\Client();注意事项
- vendor 目录不要入库(.gitignore),用 composer.lock 保证版本一致
- 生产部署用 composer install(按 lock 装),不要用 update(会升级版本)
- composer require 会自动改 composer.json 并安装——注意它可能一次装很多传递依赖
- PSR 标准很重要:PSR-3 日志、PSR-7 HTTP 消息、PSR-11 容器、PSR-4 自动加载
- 包体积与维护活跃度都要看,久不维护的包有安全风险