PHP REPL
REPL(Read-Eval-Print Loop,读取-求值-输出循环)是一种交互式编程环境,允许你逐行输入代码并立即看到执行结果。PHP 自带了基本的交互模式(php -a),同时也有功能更强大的第三方 REPL 工具如 PsySH。REPL 是快速验证代码片段、实验 API 行为和学习 PHP 特性的绝佳工具。
前置知识
- 已完成 PHP 的基本安装(参考 Unix/macOS 安装)
- 了解 PHP 的基本语法和运行方式
- 熟悉命令行操作
基础概念
什么是 REPL
REPL 是一种交互式编程环境,其工作流程如下:
┌─────────────────────────────────┐
│ REPL 循环 │
│ │
│ 1. Read — 读取用户输入的代码 │
│ ↓ │
│ 2. Eval — 执行代码 │
│ ↓ │
│ 3. Print — 输出执行结果 │
│ ↓ │
│ 4. Loop — 等待下一次输入 │
│ ↓ │
│ 回到第 1 步 │
└─────────────────────────────────┘PHP REPL 工具对比
| 工具 | 类型 | 特点 | 推荐度 |
|---|---|---|---|
| PsySH | 第三方 REPL | 功能最全面,支持自动加载、文档查看 | 强烈推荐 |
| php -a | PHP 内置 | 基本交互,无需额外安装 | 一般 |
| Boris | 第三方 REPL | 实时显示返回值,已不再维护 | 不推荐 |
选择建议
- 日常开发和代码实验:PsySH(功能丰富,体验优秀)
- 临时环境或受限环境:
php -a(PHP 内置,随时可用)
php -a 交互模式
基本使用
# 启动 PHP 交互模式
php -a
# 输出示例:
# Interactive shell
# php ># 在交互模式中执行 PHP 代码
php > echo "Hello, World!\n";
Hello, World!
php > $name = "PHP";
php > echo "Hello, {$name}!\n";
Hello, PHP!
php > $numbers = [1, 2, 3, 4, 5];
php > echo array_sum($numbers);
15
php > function greet(string $name): string
php > {
php > return "Hello, {$name}!";
php > }
php > echo greet("World");
Hello, World!
# 退出交互模式
php > exit
# 或按 Ctrl+C
# 或按 Ctrl+D限制与注意事项
PHP 内置的 php -a 交互模式(也称 Interactive Shell)有以下限制:
- 不支持多行输入自动执行:必须输入完整的语句(包括结束的分号
;),PHP 才会执行 - 不显示返回值:需要手动使用
echo或var_dump来查看表达式的值 - 不支持代码补全:没有自动补全和历史搜索功能
- 不支持自动加载:无法使用 Composer 的自动加载功能
- 不支持命令历史搜索:按上下方向键可以浏览历史,但无搜索功能
Interactive Shell vs Interactive Mode
PHP 有两种交互模式:
- Interactive Shell(
php -a):支持变量状态保持、函数定义跨行等 - Interactive Mode(通过
php直接运行,无-a):每行独立执行,变量不保持
如果 php -a 只显示 Interactive mode enabled 而没有 php > 提示符,说明 PHP 编译时启用了 readline,但当前终端不支持。尝试使用 rlwrap 包裹:
rlwrap php -a使用技巧
# 执行单行 PHP 代码(不需要 -a)
php -r 'echo "Hello, PHP " . PHP_VERSION . "\n";'
# 执行 PHP 文件中的代码
php -f script.php
# 从 stdin 读取代码
echo '<?php echo PHP_VERSION;' | php
# 设置 php.ini 中的临时配置
php -d memory_limit=512M -r 'echo ini_get("memory_limit");'
# 显示内置 Web 服务器
php -S localhost:8000PsySH(第三方 REPL)
PsySH 是 PHP 生态中最强大的 REPL 工具,提供了远超 PHP 内置交互模式的功能。
安装 PsySH
# 方式 1:全局安装(推荐)
composer global require psy/psysh
# 确保 Composer 的全局 bin 目录在 PATH 中
export PATH="$PATH:$HOME/.composer/vendor/bin"
# 永久添加
echo 'export PATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc
# 验证安装
psysh --version
# PsySH v0.12.0 (PHP 8.2.x)
# 方式 2:下载 PHAR 文件
curl -LO https://psysh.org/psysh
chmod +x psysh
sudo mv psysh /usr/local/bin/psysh
# 方式 3:项目中安装
composer require --dev psy/psysh
# 然后通过 vendor/bin/psysh 启动基本使用
# 启动 PsySH
psysh
# PsySH v0.12.0 (PHP 8.2.x)
# ># PsySH 会自动显示表达式的返回值
>>> 2 + 3
5
>>> "Hello" . " " . "PHP"
"Hello PHP"
>>> $array = ['a' => 1, 'b' => 2, 'c' => 3];
=> [
"a" => 1,
"b" => 2,
"c" => 3,
]
>>> count($array)
3
>>> array_keys($array)
=> [
"a",
"b",
"c",
]# PsySH 支持多行输入
>>> function factorial(int $n): int
... {
... if ($n <= 1) {
... return 1;
... }
... return $n * factorial($n - 1);
... }
=> null
>>> factorial(5)
120
>>> factorial(10)
3628800核心功能
自动补全
# 按 Tab 键自动补全
>>> array_ma<Tab>
array_map array_merge array_merge_recursive
# 补全变量名
>>> $myVaria<Tab>
>>> $myVariable
# 补全方法名
>>> $redis->ge<Tab>
>>> $redis->get( # 自动补全并添加括号历史搜索
# Ctrl+R 打开反向搜索
# 输入关键词后,PsySH 会在历史命令中搜索匹配的命令
# 例如搜索之前执行过的 array_map 命令
(reverse-i-search)`array': array_map(fn($x) => $x * 2, [1, 2, 3]);异常处理
# PsySH 会优雅地处理异常和错误
>>> new RuntimeException("test error")
RuntimeException with message 'test error' in Psy Shell code on line 1
# 显示完整的堆栈跟踪
>>> throw new Exception("error")
Exception with message 'error' in Psy Shell code:1
Stack trace:
#0 Psy Shell code:1
#1 ...退出和中断
# 退出 PsySH
>>> exit
# 或
>>> quit
# 中断当前执行
Ctrl + C
# 清除当前输入
Ctrl + C(在输入过程中)详细配置
PsySH 配置文件
PsySH 支持通过配置文件自定义行为:
# PsySH 配置文件位置
~/.config/psysh/config.php # 全局配置
/.psysh.php # 项目级配置(项目根目录)<?php
declare(strict_types=1);
// ~/.config/psysh/config.php
return [
// 设置默认的提示符
// 'prompt' => '>>> ',
// 设置历史记录文件
'historySize' => 1000,
// 启用或禁用特定命令
// 'commands' => [...],
// 自定义 Tab 补全
// 'tabCompletionMatchers' => [...],
];自动加载 Composer 项目
PsySH 可以自动加载项目的 Composer 依赖:
# 方式 1:在项目目录中启动 PsySH
cd /path/to/your/project
psysh
# PsySH 会自动检测 composer.json 并加载 autoload
# 方式 2:手动指定自动加载文件
psysh --bootstrap vendor/autoload.php
# 方式 3:在 PsySH 中手动加载
>>> require 'vendor/autoload.php';# 验证自动加载是否生效
>>> \App\Models\User::class
"App\Models\User"
>>> class_exists(\App\Models\User::class)
true查看文档
PsySH 内置了 PHP 函数和类的文档查看功能:
# 查看函数文档
>>> doc array_map
function array_map($callback, $array, ...$arrays)
Applies the callback to the elements of the given arrays
Returns: array
# 查看类文档
>>> doc DateTime
class DateTime implements DateTimeInterface
Representation of date and time.
Methods: __construct, __set_state, __wakeup, add, ...
# 查看方法文档
>>> doc DateTime::format
public DateTime::format(string $format): string|false
Returns date formatted according to given format
# 查看源代码
>>> show DateTime::format
function format(string $format): string|false
{
// ...
}PsySH 文档离线下载
PsySH 的文档默认从 php.net 在线获取。你也可以下载离线文档:
# 下载 PHP 手册(用于离线文档查看)
mkdir -p ~/.local/share/psysh
cd ~/.local/share/psysh
curl -LO http://psysh.org/manual/zh/php_manual.sqlite运行时变量检查
# PsySH 提供了强大的变量检查功能
>>> $user = ['name' => 'John', 'age' => 30, 'email' => 'john@example.com'];
# ls 命令:列出当前作用域的所有变量
>>> ls
>>> Variables: $user
# 查看变量详细信息
>>> $user
=> [
"name" => "John",
"age" => 30,
"email" => "john@example.com",
]
# 查看对象属性
>>> $obj = new DateTime();
>>> $obj
=> DateTime @1734012345 {
date: "2024-12-13 10:30:45.000000",
timezone_type: 3,
timezone: "Asia/Shanghai",
}
# wtf 命令:显示上一个异常的堆栈跟踪
>>> wtf使用场景
场景 1:快速验证代码逻辑
# 验证正则表达式是否正确
>>> preg_match('/^\d{4}-\d{2}-\d{2}$/', '2024-01-15')
1
>>> preg_match('/^\d{4}-\d{2}-\d{2}$/', '2024-1-15')
0
# 验证数组函数行为
>>> $data = [3, 1, 4, 1, 5, 9, 2, 6];
>>> array_unique($data)
=> [3, 1, 4, 5, 9, 2, 6]
>>> sort($data)
true
>>> $data
=> [1, 1, 2, 3, 4, 5, 6, 9]场景 2:实验 PHP 新特性
# 实验 PHP 8.1 新特性:枚举
>>> enum Status: string
... {
... case Active = 'active';
... case Inactive = 'inactive';
... case Pending = 'pending';
... }
>>> Status::Active->value
"active"
>>> Status::cases()
=> [
PsyShell closure_global namespace{closure}():Status::Active,
PsyShell closure_global namespace{closure}():Status::Inactive,
PsyShell closure_global namespace{closure}():Status::Pending,
]# 实验 PHP 8.2 新特性:只读类
>>> readonly class Point
... {
... public function __construct(
... public float $x,
... public float $y,
... ) {}
... }
>>> $p = new Point(3.14, 2.71);
>>> $p->x
3.14
>>> $p->x = 1.0;
Error: Cannot modify readonly property Point::$x场景 3:调试 API 响应
# 在 PsySH 中测试 API 调用
>>> require 'vendor/autoload.php';
>>> $client = new GuzzleHttp\Client();
>>> $response = $client->get('https://api.example.com/users/1');
>>> $data = json_decode($response->getBody(), true);
>>> print_r($data);
# 检查数据结构
>>> isset($data['user']['name'])
true
>>> $data['user']['name']
"John Doe"场景 4:数据库查询测试
<?php
declare(strict_types=1);
// 在 PsySH 中测试 PDO 查询
$dsn = 'mysql:host=localhost;dbname=test_db';
$pdo = new PDO($dsn, 'root', 'password');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 执行查询
$stmt = $pdo->query('SELECT * FROM users WHERE id = 1');
$user = $stmt->fetch(PDO::FETCH_ASSOC);
print_r($user);
// 测试预处理语句
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = :email');
$stmt->execute(['email' => 'john@example.com']);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
count($results);注意事项
常见问题
| 问题 | 解决方案 |
|---|---|
php -a 只显示 Interactive mode | 安装 rlwrap 并使用 rlwrap php -a |
| PsySH 无法补全项目类 | 确保 Composer autoload 已加载 |
| PsySH 启动报内存错误 | 增加 memory_limit:php -d memory_limit=512M |
| 历史记录丢失 | PsySH 配置文件中设置 historySize |
| 无法加载项目依赖 | 使用 --bootstrap 参数或 cd 到项目目录 |
注意事项
- 不要在生产环境使用 REPL:REPL 可以执行任意 PHP 代码,存在安全风险
- 变量状态保持:REPL 中的变量在会话期间保持状态,注意变量的影响
- 大文件处理:REPL 不适合处理大文件或长时间运行的任务
- 多行输入:PsySH 支持多行输入,注意使用
...续行符
最佳实践
日常使用 PsySH:PsySH 的自动补全、返回值显示和文档查看功能大大提升了代码实验效率。
项目级配置:在项目根目录创建
.psysh.php配置文件,自动加载 Composer 依赖和常用命名空间。代码实验:在编写正式代码前,先在 PsySH 中验证逻辑和 API 行为,避免反复修改文件。
学习 PHP 特性:使用 PsySH 来实验和学习 PHP 的新特性,直观地观察代码行为。
结合调试使用:PsySH 可以作为调试的辅助工具,在 REPL 中重现问题场景。
TDD 辅助:在编写测试之前,先在 PsySH 中验证被测试的函数或方法的行为。