PHP Composer 入门指南

PHP Composer 入门指南

Composer 是 PHP 的依赖管理工具,现在做 PHP 开发不用 Composer 几乎不可能。

1. 安装 Composer

# Linux/Mac
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

# Windows 直接下载安装包
# https://getcomposer.org/Composer-Setup.exe

验证安装:

composer -V

2. 换国内镜像(必须)

官方镜像太慢,一定要换国内镜像:

# 阿里云镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

# 腾讯云镜像
composer config -g repo.packagist composer https://mirrors.tencent.com/composer/

3. 初始化项目

# 进入项目目录
cd myproject

# 初始化 composer.json
composer init

或者手动创建 composer.json:

{
    "name": "my/project",
    "require": {
        "monolog/monolog": "^2.0"
    }
}

4. 常用命令

# 安装依赖
composer install

# 更新依赖
composer update

# 安装某个包
composer require monolog/monolog

# 卸载某个包
composer remove monolog/monolog

# 自动加载
composer dump-autoload

5. 自动加载

// 引入自动加载文件
require __DIR__ . '/vendor/autoload.php';

// 然后就可以直接用第三方库了
$log = new Monolog\Logger('name');

6. composer.json 详解

{
    "name": "项目名",
    "description": "项目描述",
    "type": "project",
    "require": {
        "php": ">=7.4",
        "monolog/monolog": "^2.0",
        "guzzlehttp/guzzle": "^7.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

7. 版本号说明

  • ^2.0:兼容 2.0 到 3.0(不包含 3.0)
  • ~2.0:兼容 2.0 到 2.1(不包含 2.1)
  • *:任意版本
  • 2.0.*:2.0.x 版本

总结

Composer 核心:

  • 安装:一行命令
  • 换镜像:必须换国内源
  • 常用:install / update / require / remove
  • 自动加载:require vendor/autoload.php

搞懂这些,Composer 日常开发就够用了。


emer 发布于  2026-10-4 11:06 

PHP 字符串处理技巧

PHP 字符串处理常用技巧

字符串处理是 PHP 开发最常用的操作,掌握这些函数,写代码效率翻倍。

1. 截取字符串

// 截取前 5 个字符
substr("hello world", 0, 5); // hello

// 截取从第 6 个开始到结尾
substr("hello world", 6); // world

// 中文字符串截取(用 mb_)
mb_substr("你好世界", 0, 2, "UTF-8"); // 你好

注意:中文要用 mb_substr,不能用 substr,否则会乱码。

2. 替换字符串

//  str_replace(替换所有)
str_replace("world", "PHP", "hello world"); // hello PHP

//  str_ireplace(不区分大小写)
str_ireplace("WORLD", "PHP", "hello world");

//  preg_replace(正则替换)
preg_replace("/\d/", "", "abc123def"); // abcdef

3. 查找字符串

// 查找位置(找不到返回 false)
strpos("hello world", "world"); // 6

// 查找最后出现位置
strrpos("hello world hello", "hello"); // 12

// 判断是否包含(PHP 8+)
str_contains("hello world", "world"); // true

// 判断开头
str_starts_with("hello world", "hello"); // true

// 判断结尾
str_ends_with("hello world", "world"); // true

4. 格式化字符串

// 去除首尾空格
trim("  hello  "); // hello

// 只去左边/右边
ltrim("  hello"); // hello
rtrim("hello  "); // hello

// 转小写/大写
strtolower("Hello"); // hello
strtoupper("hello"); // HELLO

// 首字母大写
ucfirst("hello"); // Hello

// 每个单词首字母大写
ucwords("hello world"); // Hello World

5. 字符串和数组转换

// 字符串转数组
explode(",", "a,b,c"); // ["a","b","c"]

// 数组转字符串
implode(",", ["a","b","c"]); // a,b,c

// 重复字符串
str_repeat("ab", 3); // ababab

// 字符串长度
strlen("hello"); // 5
mb_strlen("你好", "UTF-8"); // 2

6. 常用技巧

// 生成随机字符串
substr(md5(time()), 0, 8);

// 脱敏手机号
substr_replace("13812345678", "****", 3, 4); // 138****5678

// 截取摘要(带省略号)
mb_strlen($text) > 10 ? mb_substr($text, 0, 10) . "..." : $text;

// 清除 HTML 标签
strip_tags("<p>hello</p>"); // hello

总结

PHP 字符串处理核心函数:

  • 截取:substr / mb_substr
  • 替换:str_replace / preg_replace
  • 查找:strpos / str_contains
  • 格式化:trim / strtolower / ucwords
  • 转换:explode / implode

记住这些,日常开发基本够用了。


emer 发布于  2026-10-4 11:04 

PHP 数组操作技巧

PHP 数组操作技巧

数组是 PHP 最常用的数据结构,掌握这些技巧,写代码效率翻倍。

1. 数组合并

// 索引数组合并
$arr1 = [1, 2];
$arr2 = [3, 4];
$result = array_merge($arr1, $arr2); // [1,2,3,4]

// 关联数组合并,后面覆盖前面
$arr1 = ['a' => 1, 'b' => 2];
$arr2 = ['b' => 3, 'c' => 4];
$result = array_merge($arr1, $arr2); // ['a'=>1, 'b'=>3, 'c'=>4]

2. 数组去重

// 一维数组去重
$arr = [1, 2, 2, 3, 3, 3];
$result = array_unique($arr); // [1,2,3]

// 二维数组按字段去重
$users = [
    ['id' => 1, 'name' => '张三'],
    ['id' => 2, 'name' => '李四'],
    ['id' => 1, 'name' => '张三'],
];
$ids = array_column($users, 'id');
$unique = array_unique($ids);

3. 数组排序

// 升序
sort($arr);

// 降序
rsort($arr);

// 按键排序
ksort($arr);

// 按值排序,保留键
asort($arr);

4. 数组过滤

// 过滤空值
$arr = [1, 0, '', null, 'a'];
$result = array_filter($arr); // [1, 'a']

// 自定义过滤
$result = array_filter($arr, function($value) {
    return $value > 2;
});

5. 数组取值

// 取某一列
$names = array_column($users, 'name');

// 取交集
$arr1 = [1, 2, 3];
$arr2 = [2, 3, 4];
$result = array_intersect($arr1, $arr2); // [2,3]

// 取差集
$result = array_diff($arr1, $arr2); // [1]

6. 常用技巧

// 判断键是否存在
isset($arr['key']);
array_key_exists('key', $arr);

// 随机取一个
$value = array_rand($arr);

// 打乱数组
shuffle($arr);

// 数组合并成字符串
$str = implode(',', $arr);

// 字符串转数组
$arr = explode(',', $str);

总结

PHP 数组函数非常丰富,常用的就这些:合并、去重、排序、过滤、取值。把这些记熟,日常开发基本够用了。


emer 发布于  2026-10-4 10:48 

PHP 安全最佳实践

PHP 开发必须注意的安全问题

PHP 开发最容易出安全问题,几个常见坑一定要避开。

1. SQL 注入

最常见的安全漏洞。用户输入拼接到 SQL 里,被注入恶意 SQL。

解决方案:用预处理语句

// 不要这样
$sql = "SELECT * FROM users WHERE id = " . $_GET['id'];

// 要这样
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$_GET['id']]);

2. XSS 跨站脚本

用户输入直接输出到页面,被注入恶意 JS。

解决方案:输出时转义

echo htmlspecialchars($user_input);

3. CSRF 跨站请求伪造

别人伪造你的请求操作。

解决方案:加 Token 验证

// 表单里加 Token
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['token']; ?>">

// 后端验证
if ($_POST['csrf_token'] !== $_SESSION['token']) {
    die('CSRF 攻击');
}

4. 文件上传漏洞

用户上传 PHP 文件,直接拿到 webshell。

解决方案:

  • 限制文件类型
  • 重命名文件
  • 上传目录不执行 PHP

5. 密码明文存储

数据库被拖库,密码全泄露。

解决方案:用 password_hash

$hash = password_hash($password, PASSWORD_DEFAULT);

// 验证
password_verify($password, $hash);

6. 错误信息泄露

生产环境把报错直接展示给用户,暴露路径和代码。

解决方案:关闭 display_errors

display_errors = Off
log_errors = On

总结

PHP 安全的核心:用户输入都不可信,所有输出都要转义,数据库操作用预处理。安全开发意识比工具更重要。


emer 发布于  2026-10-4 10:37 

PHP 8.0 新特性

PHP 8.0 有哪些重磅更新

PHP 8.0 是一个大版本更新,带来了很多革命性的特性。

1. JIT 编译

PHP 8.0 引入了 JIT(即时编译),性能大幅提升,计算密集型场景性能翻倍。

2. 命名参数

array_filter(array: $array, callback: fn($x) => $x > 0);

不用按顺序传参,写参数名就行,可读性更好。

3. 枚举 Enum

enum Status: string
{
    case Pending = 'pending';
    case Active = 'active';
    case Rejected = 'rejected';
}

4. 构造函数属性提升

class User {
    public function __construct(
        public int $id,
        public string $name
    ) {}
}

不用再写 $this->id = $id 了,构造函数直接定义属性。

5. 空安全运算符

$user?->getAddress()?->city;

不用层层判断 null,有 null 直接返回 null。

6. Match 表达式

$result = match($status) {
    200 => '成功',
    404 => '未找到',
    default => '未知'
};

比 switch 更简洁,还能直接赋值。

7. 联合类型

function foo(int|string $input) {}

参数可以是多种类型。

总结

PHP 8.0 是现代 PHP 的起点,类型系统更完善,语法更现代。新项目强烈推荐用 PHP 8.0+。


emer 发布于  2026-10-4 10:34 

PHP 7.4 新特性

PHP 7.4 有哪些实用新特性

PHP 7.4 是 7.x 系列的最后一个版本,带来了不少语法糖和性能优化,至今还有很多项目在用。

1. 类型属性

类的属性可以声明类型了:

class User {
    public int $id;
    public string $name;
    public ?string $email;
}

之前属性不能写类型,只能靠 PHPDoc 注释,现在直接写在代码里,IDE 提示更准确。

2. 箭头函数

支持短闭包:

$users = array_map(fn($user) => $user['name'], $users);

比传统的 function ($user) use (...) {} 简洁多了,自动捕获外层变量。

3. 空合并赋值

$data['user'] ??= [];

相当于:

if (!isset($data['user'])) {
    $data['user'] = [];
}

4. 数组展开

$arr1 = [1, 2, 3];
$arr2 = [4, 5, 6];
$merged = [...$arr1, ...$arr2];

5. 数字字面量分隔

$amount = 1_000_000;
$price = 9_999.99;

大数字用下划线分隔,可读性提升。

6. 性能提升

PHP 7.4 比 7.3 性能提升约 10%,内存占用也更少。

总结

PHP 7.4 虽然不是大版本,但实用特性很多,尤其是类型属性和箭头函数,写起来舒服不少。新项目建议直接上 PHP 8+,老项目升级到 7.4 也很稳妥。


emer 发布于  2026-10-4 10:27 

PHP Session 与 Cookie:会话管理实战指南

前言

HTTP 是无状态的,你每次请求服务器都不认识你。Session 和 Cookie 就是用来解决这个问题的。本文讲清楚 PHP 中 Session 和 Cookie 的用法。

一、Cookie 是什么

Cookie 是存在浏览器里的小数据,每次请求自动带给服务器。

设置 Cookie

setcookie("username", "张三", time() + 3600, "/");

参数说明:

  • 第一个参数:名称
  • 第二个参数:值
  • 第三个参数:过期时间(时间戳)
  • 第四个参数:路径

读取 Cookie

echo $_COOKIE['username'];

删除 Cookie

setcookie("username", "", time() - 3600, "/");

把过期时间设成过去就行。

二、Session 是什么

Session 是存在服务器上的数据,通过 Session ID 识别用户。

启动 Session

session_start();

注意:必须在输出之前调用,不然会报错。

存数据

$_SESSION['user_id'] = 1;
$_SESSION['username'] = '张三';

读数据

echo $_SESSION['username'];

删除单个数据

unset($_SESSION['user_id']);

销毁 Session

session_destroy();

三、Session 和 Cookie 的区别

对比 Cookie Session
存储位置 浏览器 服务器
大小限制 4KB 无限制
安全性 低(用户能改) 高
生命周期 可设置 默认浏览器关闭就没

四、登录功能示例

登录页

<?php
session_start();

if ($_POST) {
    $username = $_POST['username'];
    $password = $_POST['password'];

    // 验证用户名密码
    if ($username == 'admin' && $password == '123456') {
        $_SESSION['user_id'] = 1;
        $_SESSION['username'] = $username;
        header('Location: dashboard.php');
        exit;
    } else {
        echo "用户名或密码错误";
    }
}
?>

判断是否登录

<?php
session_start();

if (!isset($_SESSION['user_id'])) {
    header('Location: login.php');
    exit;
}
?>

退出登录

<?php
session_start();
session_destroy();
header('Location: login.php');
exit;
?>

五、Session 配置

修改 Session 有效期

ini_set('session.gc_maxlifetime', 3600); // 1小时
session_start();

修改 Session 存储路径

session_save_path('/tmp/sessions');
session_start();

用 Redis 存储 Session

生产环境推荐用 Redis 存 Session,默认文件存储性能差。

php.ini 配置:

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

六、安全问题

1. Session 劫持

别人拿到你的 Session ID,就能冒充你。

防护:

  • 用 HTTPS
  • Session ID 定期更换
  • 绑定 IP(不太推荐,IP 会变)

2. Cookie 劫持

别人拿到你的 Cookie,就能冒充你。

防护:

  • 设置 HttpOnly,JS 读不到
  • 设置 Secure,只在 HTTPS 下传
  • 设置 SameSite,防止 CSRF
setcookie("token", $token, [
    'expires' => time() + 3600,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Strict'
]);

3. CSRF 攻击

别人伪造你的请求。

防护:

  • 表单加 CSRF Token
  • 验证 Referer

七、常见坑

  1. session_start() 在输出之后:报错 headers already sent
  2. Session 没销毁:退出登录后还能访问
  3. Cookie 大小限制:别存太多东西,超过 4KB 就丢
  4. Session 文件太多:默认文件存储,大了要清理

八、最佳实践

  1. 敏感数据用 Session,别存 Cookie
  2. Cookie 加 HttpOnly 和 Secure
  3. 生产环境用 Redis 存 Session
  4. 登录成功后重新生成 Session ID,防止固定攻击
// 登录成功后
session_regenerate_id(true);

总结

Session 和 Cookie 的核心要点:

  1. Cookie 存在浏览器,Session 存在服务器
  2. session_start() 必须在输出之前调用
  3. Session 更安全,Cookie 更轻量
  4. 生产环境用 Redis 存 Session
  5. Cookie 加 HttpOnly 和 Secure,防劫持

登录、权限、购物车,都离不开 Session 和 Cookie。搞懂这俩,PHP 后端才算入门。


emer 发布于  2026-10-4 10:21 

PHP Composer 入门:依赖管理完全指南

前言

Composer 是 PHP 的依赖管理工具,就像 Node 的 npm、Python 的 pip。现在写 PHP 项目,不会 Composer 根本没法干活。本文讲清楚 Composer 的核心用法。

一、安装 Composer

Linux / Mac

curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

Windows

去官网下载安装包,一路下一步就行。

验证安装

composer -V

二、初始化项目

# 在项目目录下
composer init

会问你几个问题,一路回车就行,然后会生成 composer.json 文件。

composer.json 长什么样

{
    "name": "yourname/project",
    "description": "项目描述",
    "require": {
        "monolog/monolog": "^2.0"
    }
}

三、安装依赖

1. 安装所有依赖

composer install

会根据 composer.lock 文件安装指定版本的依赖。

2. 添加新依赖

composer require monolog/monolog

会自动加到 composer.json 里,然后安装。

3. 安装指定版本

composer require monolog/monolog:^2.0

版本号说明

  • ^2.0:2.0 到 3.0 之前(不包括 3.0)
  • ~2.0:2.0 到 2.1 之前(不包括 2.1)
  • *:任意版本
  • 2.0.*:2.0 开头的版本

四、自动加载

Composer 最爽的就是自动加载,不用自己写 require。

引入自动加载

<?php
require 'vendor/autoload.php';

// 直接用类,不用 require
$log = new Monolog\Logger('name');

PSR-4 自动加载

在 composer.json 里配置:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

然后执行:

composer dump-autoload

这样 App\User 类就会从 src/User.php 加载。

五、常用命令

命令 作用
composer install 安装所有依赖
composer update 更新所有依赖
composer require 包名 添加依赖
composer remove 包名 删除依赖
composer dump-autoload 重新生成自动加载
composer show 查看已安装的包
composer self-update 更新 Composer 本身

六、开发环境依赖

有些包只在开发时用,比如测试工具:

composer require --dev phpunit/phpunit

线上部署的时候,不安装开发依赖:

composer install --no-dev

七、中国镜像

国外源太慢,换中国镜像:

# 阿里云镜像
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/

# 腾讯云镜像
composer config -g repo.packagist composer https://mirrors.tencent.com/composer/

换完之后速度飞起来。

八、composer.lock 的作用

  • 记录当前安装的依赖版本
  • 团队成员 install 的时候,装的版本一模一样
  • 一定要提交到 Git
git add composer.json composer.lock
git commit -m "update composer"

九、常见坑

  1. 没装 composer.lock:团队成员装的版本不一样,出 bug
  2. 自动加载不生效:改了 autoload 配置,忘了 dump-autoload
  3. 版本冲突:两个包依赖同一个库的不同版本
  4. 国内太慢:不换镜像,下载半天

十、最佳实践

  1. composer.json 和 composer.lock 都提交 Git
  2. 线上用 install --no-dev,不要用 update
  3. 用中文镜像,加速下载
  4. 改了自动加载配置,记得 dump-autoload

总结

Composer 的核心要点:

  1. require 添加依赖,install 安装依赖
  2. vendor/autoload.php 是自动加载入口
  3. composer.lock 要提交 Git,保证版本一致
  4. 换国内镜像,速度快很多
  5. 开发依赖用 --dev,线上不装

学会 Composer,PHP 开发效率提升一倍。


emer 发布于  2026-10-4 10:20 

PHP 数组常用操作:从排序到过滤的完整指南

前言

数组是 PHP 里最常用的数据结构,没有之一。PHP 提供了 100 多个数组函数,很多人只知道其中几个。本文整理最常用的数组操作。

一、创建数组

<?php
// 索引数组
$arr1 = [1, 2, 3, 4, 5];

// 关联数组
$arr2 = ['name' => '张三', 'age' => 18];

// 空数组
$arr3 = [];

二、添加元素

<?php
$arr = [1, 2, 3];

// 末尾添加
$arr[] = 4; // [1, 2, 3, 4]
array_push($arr, 5); // [1, 2, 3, 4, 5]

// 开头添加
array_unshift($arr, 0); // [0, 1, 2, 3, 4, 5]

// 关联数组添加
$user = ['name' => '张三'];
$user['age'] = 18; // ['name' => '张三', 'age' => 18]

三、删除元素

<?php
$arr = [1, 2, 3, 4, 5];

// 删除末尾元素
array_pop($arr); // [1, 2, 3, 4]

// 删除开头元素
array_shift($arr); // [2, 3, 4]

// 删除指定元素
unset($arr[1]); // [0 => 2, 2 => 4],注意索引不连续

四、查找元素

<?php
$arr = ['a', 'b', 'c'];

// 值是否存在
in_array('b', $arr); // true

// 键是否存在
$user = ['name' => '张三', 'age' => 18];
array_key_exists('name', $user); // true

// 查找值的键
array_search('b', $arr); // 1

五、数组长度

<?php
$arr = [1, 2, 3];
count($arr); // 3
sizeof($arr); // 3(count 的别名)

六、排序

索引数组排序

<?php
$arr = [3, 1, 2, 5, 4];

sort($arr); // [1, 2, 3, 4, 5] 升序
rsort($arr); // [5, 4, 3, 2, 1] 降序

关联数组排序

<?php
$age = ['张三' => 20, '李四' => 18, '王五' => 25];

asort($age); // 按值升序,保持键名
ksort($age); // 按键升序
arsort($age); // 按值降序
krsort($age); // 按键降序

自定义排序

<?php
$users = [
    ['name' => '张三', 'age' => 20],
    ['name' => '李四', 'age' => 18],
    ['name' => '王五', 'age' => 25],
];

// 按 age 升序
usort($users, function ($a, $b) {
    return $a['age'] <=> $b['age'];
});

七、数组过滤

array_filter()

<?php
$arr = [1, 2, 3, 4, 5, 6];

// 过滤出偶数
$even = array_filter($arr, function ($n) {
    return $n % 2 == 0;
});
// [2, 4, 6]

array_map()

<?php
$arr = [1, 2, 3, 4, 5];

// 每个元素乘以 2
$doubled = array_map(function ($n) {
    return $n * 2;
}, $arr);
// [2, 4, 6, 8, 10]

array_walk()

<?php
$arr = ['a' => 1, 'b' => 2];

array_walk($arr, function (&$value, $key) {
    $value = $value * 10;
});
// ['a' => 10, 'b' => 20]

八、数组合并

<?php
$arr1 = [1, 2];
$arr2 = [3, 4];

// 数组合并
$merged = array_merge($arr1, $arr2); // [1, 2, 3, 4]

// + 运算符(保留第一个数组的键)
$result = $arr1 + $arr2;

九、数组切片

<?php
$arr = [1, 2, 3, 4, 5];

// 从第 2 个开始取 3 个
$slice = array_slice($arr, 1, 3); // [2, 3, 4]

// 从末尾取
$last = array_slice($arr, -2); // [4, 5]

十、键值操作

<?php
$user = ['name' => '张三', 'age' => 18];

// 所有键
array_keys($user); // ['name', 'age']

// 所有值
array_values($user); // ['张三', 18]

// 翻转键值
array_flip($user); // ['张三' => 'name', 18 => 'age']

十一、常用操作速查表

操作 函数
数组长度 count()
查找值 in_array()
查找键 array_key_exists()
排序 sort() / asort() / ksort()
过滤 array_filter()
映射 array_map()
合并 array_merge()
切片 array_slice()

十二、常见坑

  1. unset 后索引不连续:用 array_values() 重新索引
  2. array_merge 和 + 的区别:数字键 array_merge 会重新索引,+ 不会
  3. in_array 严格模式:加第三个参数 true 防止类型转换
  4. sort 会改变原数组:不是返回新数组

总结

PHP 数组操作的核心要点:

  1. 增删改查:array_push/pop/unshift/shift/unset
  2. 查找判断:in_array/array_key_exists/array_search
  3. 排序:sort/asort/ksort/usort
  4. 处理:array_filter/array_map/array_walk
  5. 合并切片:array_merge/array_slice

数组用好了,PHP 开发效率能提升一倍。


emer 发布于  2026-10-4 10:15 

PHP 字符串处理:常用函数和最佳实践指南

前言

字符串处理是 PHP 开发中最常用的操作之一。很多人写了很多年代码,却还是用错字符串函数。本文整理最常用的字符串处理函数和最佳实践。

一、字符串长度

strlen()

<?php
$str = "hello";
echo strlen($str); // 5

注意:strlen 按字节算,中文会出问题。

mb_strlen()

<?php
$str = "你好";
echo mb_strlen($str, 'UTF-8'); // 2
echo strlen($str); // 6(3个字节一个汉字)

记住:处理中文一定要用 mb_ 系列函数。

二、字符串查找

strpos()

查找字符串第一次出现的位置:

<?php
$str = "hello world";
$pos = strpos($str, "world");
echo $pos; // 6

坑: 如果没找到返回 false,如果找到的位置是 0,也返回 0。

<?php
// 错误写法
if (strpos($str, "hello")) {
    // 如果 hello 在第 0 位,这里不会执行
}

// 正确写法
if (strpos($str, "hello") !== false) {
    // 这样才对
}

strrpos()

查找字符串最后一次出现的位置。

stripos() / strripos()

不区分大小写的查找。

三、字符串替换

str_replace()

<?php
$str = "hello world";
echo str_replace("world", "PHP", $str); // hello PHP

数组替换:

<?php
echo str_replace(
    ["hello", "world"],
    ["hi", "PHP"],
    "hello world"
); // hi PHP

substr_replace()

替换字符串的一部分:

<?php
echo substr_replace("hello world", "PHP", 6); // hello PHP

preg_replace()

正则替换:

<?php
// 把多个空格变成一个
echo preg_replace('/\s+/', ' ', "hello   world"); // hello world

四、字符串截取

substr()

<?php
$str = "hello world";
echo substr($str, 0, 5); // hello
echo substr($str, 6); // world

中文截取要用 mb_substr():

<?php
$str = "你好世界";
echo mb_substr($str, 0, 2, 'UTF-8'); // 你好

五、字符串分割与连接

explode()

<?php
$str = "a,b,c,d";
$arr = explode(",", $str);
print_r($arr); // ['a', 'b', 'c', 'd']

implode() / join()

<?php
$arr = ['a', 'b', 'c'];
echo implode(",", $arr); // a,b,c

六、字符串去空格

trim()

<?php
$str = "  hello  ";
echo trim($str); // "hello",去掉两边空格
echo ltrim($str); // "hello  ",去掉左边空格
echo rtrim($str); // "  hello",去掉右边空格

七、大小写转换

<?php
$str = "Hello World";
echo strtolower($str); // hello world
echo strtoupper($str); // HELLO WORLD
echo ucfirst($str); // Hello world
echo ucwords($str); // Hello World

八、HTML 转义

htmlspecialchars()

输出到 HTML 时一定要转义,防止 XSS:

<?php
$str = "<script>alert('xss')</script>";
echo htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
// 输出 &lt;script&gt;alert(&#039;xss&#039;)&lt;/script&gt;

htmlentities()

更彻底的转义,把所有 HTML 都转义。

九、JSON 处理

json_encode()

<?php
$arr = ['name' => '张三', 'age' => 18];
echo json_encode($arr, JSON_UNESCAPED_UNICODE);
// {"name":"张三","age":18}

记住:加 JSON_UNESCAPED_UNICODE,不然中文会变成 \uXXXX。

json_decode()

<?php
$json = '{"name":"张三","age":18}';
$obj = json_decode($json); // 对象
$arr = json_decode($json, true); // 数组

十、常见坑

  1. strpos 用 == 判断:位置 0 和 false 会混淆
  2. 中文用 strlen/substr:按字节算,中文会乱码
  3. 输出 HTML 不转义:XSS 漏洞
  4. json_encode 不加 JSON_UNESCAPED_UNICODE:中文变 \uXXXX
  5. 字符串拼接用 . 不用 +:PHP 是 . 号

总结

PHP 字符串处理的核心要点:

  1. 中文用 mb_ 系列函数,不要用 strlen/substr
  2. strpos 用 !== false 判断,不要用 ==
  3. 输出 HTML 一定要 htmlspecialchars 转义
  4. json_encode 加 JSON_UNESCAPED_UNICODE
  5. 字符串拼接用 . 号,不要用 + 号

掌握这些,字符串处理就不会出大问题了。


emer 发布于  2026-10-4 10:12 

PHP 错误与异常处理:从 die 到优雅的错误处理

前言

很多 PHP 新手处理错误就是 die() 或者 exit(),页面直接白屏,用户体验极差。本文讲清楚 PHP 的错误和异常处理机制,帮你写出更健壮的代码。

一、错误 vs 异常

很多人搞不清错误和异常的区别:

  • 错误:PHP 本身的问题,比如语法错误、调用不存在的函数
  • 异常:程序逻辑上的问题,比如数据库连不上、文件不存在

PHP 7 以后,很多错误也变成了异常,可以用 try-catch 捕获。

二、错误级别

PHP 有很多错误级别:

E_ERROR      致命错误,脚本停止运行
E_WARNING    警告,脚本继续运行
E_NOTICE     注意,一般不影响运行
E_PARSE      语法解析错误
E_DEPRECATED 过时提醒

开发环境和生产环境的配置不一样:

# 开发环境:显示所有错误
display_errors = On
error_reporting = E_ALL

# 生产环境:不显示错误,只记录日志
display_errors = Off
log_errors = On
error_reporting = E_ALL

三、异常处理基础

try-catch-finally

<?php
try {
    // 可能出错的代码
    $db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
} catch (PDOException $e) {
    // 捕获异常
    echo "数据库连接失败:" . $e->getMessage();
} finally {
    // 不管有没有异常都会执行
    echo "执行完毕";
}

抛出异常

<?php
function divide($a, $b)
{
    if ($b == 0) {
        throw new Exception("除数不能为 0");
    }
    return $a / $b;
}

try {
    echo divide(10, 0);
} catch (Exception $e) {
    echo "错误:" . $e->getMessage();
}

四、自定义异常类

<?php
class DbException extends Exception
{
    public function errorMessage()
    {
        return "数据库错误:" . $this->getMessage();
    }
}

class UserException extends Exception
{
    public function errorMessage()
    {
        return "用户错误:" . $this->getMessage();
    }
}

// 使用
try {
    if (!$user) {
        throw new UserException("用户不存在");
    }
} catch (UserException $e) {
    echo $e->errorMessage();
} catch (DbException $e) {
    echo $e->errorMessage();
} catch (Exception $e) {
    echo "其他错误:" . $e->getMessage();
}

五、错误处理器

把 PHP 错误转换成异常,统一处理:

<?php
// 自定义错误处理器
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
    // 把错误转换成异常抛出
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

try {
    // 这个本来是 warning,现在会被捕获
    $result = 10 / 0;
} catch (ErrorException $e) {
    echo "错误:" . $e->getMessage();
}

六、异常处理器

兜底处理,最后一道防线:

<?php
// 自定义异常处理器
set_exception_handler(function ($e) {
    echo "未捕获的异常:" . $e->getMessage();
    // 记录日志
    error_log($e->getMessage());
});

// 没有 try-catch 的异常会走这里
throw new Exception("爆炸了");

七、常见错误处理方式对比

方式 问题
die() / exit() 页面白屏,用户体验差
echo 错误信息 代码混在一起,不好维护
错误码返回 调用方需要判断错误码
异常处理 代码清晰,错误统一管理

八、最佳实践

  1. 生产环境不要显示错误:会暴露服务器信息
  2. 一定要记录日志:方便排查问题
  3. 用异常处理替代 die():代码更优雅
  4. 自定义异常类:区分不同类型的错误
  5. 兜底异常处理器:防止未捕获的异常白屏

九、日志记录

<?php
try {
    // 可能出错的代码
} catch (Exception $e) {
    // 记录日志
    error_log(
        date('Y-m-d H:i:s') . " 错误:" . $e->getMessage() . "\n",
        3,
        '/var/log/php/error.log'
    );

    // 给用户友好提示
    echo "系统繁忙,请稍后再试";
}

总结

PHP 错误处理的核心思路:

  1. 开发环境显示错误,生产环境隐藏错误
  2. 用 try-catch 捕获异常,不要用 die()
  3. 自定义异常类,区分不同错误类型
  4. 设置错误处理器,把错误转成异常
  5. 一定要记录日志,方便排查问题

掌握这些,你的 PHP 代码会健壮很多。


emer 发布于  2026-10-4 10:09 

PHP 设计模式:单例、工厂、观察者实战详解

前言

设计模式不是八股文,它是前人踩坑踩出来的最佳实践。PHP 开发中最常用的三个设计模式:单例、工厂、观察者。本文用最直白的方式讲清楚。

一、单例模式(Singleton)

什么时候用

全局只需要一个实例的对象,比如:

  • 数据库连接
  • 配置管理
  • 日志对象

代码实现

<?php
class Database
{
    private static $instance = null;
    private $conn;

    // 构造函数私有化,防止外部 new
    private function __construct()
    {
        $this->conn = mysqli_connect('localhost', 'user', 'pass', 'db');
    }

    // 禁止克隆
    private function __clone() {}

    // 禁止反序列化
    public function __wakeup()
    {
        throw new Exception("不能反序列化单例");
    }

    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function getConnection()
    {
        return $this->conn;
    }
}

// 使用
$db = Database::getInstance();
$conn = $db->getConnection();

为什么要私有化构造函数

如果构造函数是 public 的,外面就能 new Database(),那就不是单例了。

二、工厂模式(Factory)

什么时候用

需要根据不同条件创建不同对象的时候,比如:

  • 根据支付类型创建不同的支付对象(微信、支付宝、银行卡)
  • 根据数据库类型创建不同的数据库对象(MySQL、Redis)

简单工厂

<?php
interface Payment
{
    public function pay($amount);
}

class WechatPay implements Payment
{
    public function pay($amount)
    {
        echo "微信支付 {$amount} 元";
    }
}

class Alipay implements Payment
{
    public function pay($amount)
    {
        echo "支付宝支付 {$amount} 元";
    }
}

class PaymentFactory
{
    public static function make($type)
    {
        switch ($type) {
            case 'wechat':
                return new WechatPay();
            case 'alipay':
                return new Alipay();
            default:
                throw new Exception("不支持的支付方式");
        }
    }
}

// 使用
$pay = PaymentFactory::make('wechat');
$pay->pay(100);

工厂模式的好处

  1. 解耦:客户端不需要知道具体怎么创建对象
  2. 易扩展:新增支付方式只需要加一个类和工厂里的一个 case
  3. 统一管理:所有对象的创建都在工厂里,方便维护

三、观察者模式(Observer)

什么时候用

一个对象状态改变时,需要通知多个其他对象,比如:

  • 用户注册后:发邮件、发短信、送积分
  • 订单状态变更后:通知仓库、通知物流、通知客服

代码实现

<?php
// 事件接口
interface Observer
{
    public function update($eventData);
}

// 事件主体
class Event
{
    private $observers = [];

    public function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }

    public function trigger($eventData)
    {
        foreach ($this->observers as $observer) {
            $observer->update($eventData);
        }
    }
}

// 具体观察者
class SendEmail implements Observer
{
    public function update($eventData)
    {
        echo "发送邮件给 {$eventData['email']}\n";
    }
}

class SendSms implements Observer
{
    public function update($eventData)
    {
        echo "发送短信给 {$eventData['phone']}\n";
    }
}

class GivePoints implements Observer
{
    public function update($eventData)
    {
        echo "给用户送 100 积分\n";
    }
}

// 使用
$event = new Event();
$event->attach(new SendEmail());
$event->attach(new SendSms());
$event->attach(new GivePoints());

// 用户注册,触发事件
$event->trigger([
    'email' => 'user@example.com',
    'phone' => '13800138000'
]);

观察者模式的好处

  1. 解耦:事件主体不需要知道谁在监听
  2. 易扩展:新增监听者只需要加一个类,不需要改原来的代码
  3. 符合开闭原则:对扩展开放,对修改关闭

四、什么时候用什么模式

场景 用什么模式
全局只需要一个实例 单例
根据条件创建不同对象 工厂
一个动作触发多个后续操作 观察者

五、常见坑

  1. 单例用太多:单例用多了会变成全局变量,代码难维护
  2. 工厂过度设计:简单逻辑就别硬上工厂,会增加复杂度
  3. 观察者滥用:所有操作都做成观察者,调试会很痛苦

总结

设计模式是工具,不是目的。

  • 单例:保证全局只有一个实例
  • 工厂:统一管理对象创建
  • 观察者:一个事件,多个响应

用对了让代码更清晰,用错了让代码更复杂。记住:先解决问题,再考虑模式。


emer 发布于  2026-10-4 10:08 

PHP 性能优化:从代码到部署的完整指南

前言

PHP 性能优化是每个 PHP 开发者都绕不开的话题。很多人觉得 PHP 性能差,但实际上通过合理的优化,PHP 应用完全可以达到很高的性能水平。本文从代码层面到部署层面,带你完整梳理 PHP 性能优化的思路。

一、代码层面优化

1. 避免在循环中做数据库查询

// 慢:循环中查询数据库
foreach ($users as $user) {
    $order = $db->query("SELECT * FROM orders WHERE user_id = {$user['id']}");
}

// 快:一次性查询,然后用数组映射
$userIds = array_column($users, 'id');
$orders = $db->query("SELECT * FROM orders WHERE user_id IN (" . implode(',', $userIds) . ")")->fetchAll();
$orderMap = array_column($orders, null, 'user_id');

2. 用生成器处理大数据

// 慢:一次性加载所有数据到内存
$users = $db->query("SELECT * FROM big_table")->fetchAll();

// 快:用生成器逐行处理
function getUsers() {
    $stmt = $pdo->query("SELECT * FROM big_table");
    while ($row = $stmt->fetch()) {
        yield $row;
    }
}

3. 字符串拼接 vs implode

// 慢:频繁拼接字符串
$str = '';
foreach ($items as $item) {
    $str .= $item . ',';
}

// 快:用数组收集最后拼接
$parts = [];
foreach ($items as $item) {
    $parts[] = $item;
}
$str = implode(',', $parts);

二、PHP 配置优化

1. OPcache 必开

OPcache 是 PHP 性能提升最大的一个扩展,没有之一。

; php.ini
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.revalidate_freq=60
opcache.fast_shutdown=1

开启 OPcache 后,PHP 脚本会被编译成字节码缓存起来,避免每次请求都重新编译。性能提升通常在 2-5 倍。

2. 合理设置内存限制

memory_limit = 256M

不要设置太大,也不要太小。根据你的应用实际情况调整。

三、数据库优化

1. 开启慢查询日志

slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1

找出慢查询,然后针对性优化。

2. 使用持久化连接要谨慎

// 不一定更快,可能反而更慢
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass', [
    PDO::ATTR_PERSISTENT => true
]);

持久化连接在高并发场景下可能导致连接耗尽,要根据实际情况测试。

四、部署层面优化

1. 使用 PHP-FPM 优化

; php-fpm/www.conf
pm = dynamic
pm.max_children = 50
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 30

根据服务器内存调整 max_children,每个 PHP-FPM 进程大约占用 20-40MB 内存。

2. Nginx 开启 gzip

gzip on;
gzip_types text/plain text/css application/json application/javascript;
gzip_min_length 1000;

3. 静态文件 CDN 加速

把图片、CSS、JS 等静态资源放到 CDN 上,减轻服务器压力。

五、性能监控工具

  • Xdebug:代码性能分析,找出瓶颈函数
  • Blackfire:更专业的性能分析工具
  • New Relic:APM 应用性能监控
  • ab / wrk:压力测试工具

总结

PHP 性能优化的核心思路:

  1. 先找出瓶颈在哪里,不要盲目优化
  2. 代码层面:减少数据库查询、减少内存占用
  3. 配置层面:OPcache 必开
  4. 部署层面:PHP-FPM、Nginx、数据库都要调优
  5. 用工具量化优化效果

性能优化是一个持续迭代的过程,不要指望一次性优化到位。每次做一点,慢慢积累。


emer 发布于  2026-10-4 09:55 

PHP 8.3 新特性详解:类型类获取、动态常量获取和更多实用功能

前言

PHP 8.3 于 2023 年 11 月正式发布,作为 PHP 8.x 系列的第四个版本,它带来了一系列实用的语法增强和性能优化。本文将深入介绍 PHP 8.3 中最值得关注的几个新特性。

1. 类型类获取(Typed class constants)

在 PHP 8.3 之前,类常量无法声明类型。从 PHP 8.3 开始,类常量可以指定类型,这有助于提高代码的类型安全性。

class Foo
{
    const string BAR = 'bar';
    const int MAX_COUNT = 100;
}

声明了类型的常量必须与声明的类型匹配,否则会抛出 TypeError。支持的类型包括:标量类型、array、object、static、self、parent、类名/接口名以及 iterable。

2. 动态类常量获取

PHP 8.3 新增了 constant() 函数的增强,允许通过表达式动态获取类常量:

class Status
{
    const DRAFT = 'draft';
    const PUBLISHED = 'published';
    const ARCHIVED = 'archived';
}

$status = 'PUBLISHED';
echo constant(Status::class . "::$status"); // 输出: published

这在需要根据变量动态选择常量时非常有用,避免了大量的 switch 或 match 分支。

3. #[\Override] 注解

PHP 8.3 引入了 #[\Override] 注解,用于显式标记一个方法是重写父类的方法:

abstract class Controller
{
    abstract public function handle(): void;
}

class UserController extends Controller
{
    #[\Override]
    public function handle(): void
    {
        echo "Handling user request...";
    }
}

如果使用了 #[\Override] 注解,但方法实际上并没有重写任何父类方法(比如方法名拼错了),PHP 会在编译时报错。这在大型项目中非常有价值,可以防止因为方法名不一致导致的隐蔽 bug。

4. Readonly 深拷贝

PHP 8.3 改进了 readonly 属性的处理。在 PHP 8.2 中,readonly 属性不能通过克隆来修改。PHP 8.3 允许在克隆时修改 readonly 属性:

class Point
{
    public function __construct(
        public readonly int $x,
        public readonly int $y
    ) {}
}

$p1 = new Point(10, 20);
$p2 = clone $p1;
$p2->x = 30; // PHP 8.3 中允许,PHP 8.2 会报错

这个特性在值对象模式中特别有用,可以创建修改后的副本而不影响原始对象。

5. 其他实用改进

json_validate() 函数

PHP 8.3 新增了 json_validate() 函数,用于验证 JSON 字符串是否有效,而不需要解码:

$json = '{"name": "Alice", "age": 30}';
if (json_validate($json)) {
    echo "Valid JSON";
}

这比 json_decode() 更高效,因为它不需要分配内存来存储解码后的结果。

随机浮点数

PHP 8.3 的 Random\Randomizer 类新增了 getFloat() 方法:

$r = new Random\Randomizer();
$float = $r->getFloat(0, 10, \Random\IntervalBoundary::ClosedOpen);

总结

PHP 8.3 虽然不是一个大版本更新,但它带来的每一个新特性都直击开发者的日常痛点。类型类常量和 #[\Override] 注解增强了代码的可维护性,动态常量获取简化了代码逻辑,readonly 深拷贝则让值对象模式更加实用。

建议正在使用 PHP 8.x 的项目尽快升级到 8.3,既能获得这些新特性的好处,也能享受性能上的小幅提升。


emer 发布于  2026-10-4 09:48