Skip to content

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 -aPHP 内置基本交互,无需额外安装一般
Boris第三方 REPL实时显示返回值,已不再维护不推荐

选择建议

  • 日常开发和代码实验:PsySH(功能丰富,体验优秀)
  • 临时环境或受限环境:php -a(PHP 内置,随时可用)

php -a 交互模式

基本使用

bash
# 启动 PHP 交互模式
php -a

# 输出示例:
# Interactive shell
# php >
bash
# 在交互模式中执行 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)有以下限制:

  1. 不支持多行输入自动执行:必须输入完整的语句(包括结束的分号 ;),PHP 才会执行
  2. 不显示返回值:需要手动使用 echovar_dump 来查看表达式的值
  3. 不支持代码补全:没有自动补全和历史搜索功能
  4. 不支持自动加载:无法使用 Composer 的自动加载功能
  5. 不支持命令历史搜索:按上下方向键可以浏览历史,但无搜索功能

Interactive Shell vs Interactive Mode

PHP 有两种交互模式:

  • Interactive Shellphp -a):支持变量状态保持、函数定义跨行等
  • Interactive Mode(通过 php 直接运行,无 -a):每行独立执行,变量不保持

如果 php -a 只显示 Interactive mode enabled 而没有 php > 提示符,说明 PHP 编译时启用了 readline,但当前终端不支持。尝试使用 rlwrap 包裹:

bash
rlwrap php -a

使用技巧

bash
# 执行单行 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:8000

PsySH(第三方 REPL)

PsySH 是 PHP 生态中最强大的 REPL 工具,提供了远超 PHP 内置交互模式的功能。

安装 PsySH

bash
# 方式 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 启动

基本使用

bash
# 启动 PsySH
psysh

# PsySH v0.12.0 (PHP 8.2.x)
# >
bash
# 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",
   ]
bash
# PsySH 支持多行输入
>>> function factorial(int $n): int
... {
...     if ($n <= 1) {
...         return 1;
...     }
...     return $n * factorial($n - 1);
... }
=> null

>>> factorial(5)
120

>>> factorial(10)
3628800

核心功能

自动补全

bash
# 按 Tab 键自动补全
>>> array_ma<Tab>
array_map     array_merge  array_merge_recursive

# 补全变量名
>>> $myVaria<Tab>
>>> $myVariable

# 补全方法名
>>> $redis->ge<Tab>
>>> $redis->get(    # 自动补全并添加括号

历史搜索

bash
# Ctrl+R 打开反向搜索
# 输入关键词后,PsySH 会在历史命令中搜索匹配的命令

# 例如搜索之前执行过的 array_map 命令
(reverse-i-search)`array': array_map(fn($x) => $x * 2, [1, 2, 3]);

异常处理

bash
# 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 ...

退出和中断

bash
# 退出 PsySH
>>> exit

# 或
>>> quit

# 中断当前执行
Ctrl + C

# 清除当前输入
Ctrl + C(在输入过程中)

详细配置

PsySH 配置文件

PsySH 支持通过配置文件自定义行为:

bash
# PsySH 配置文件位置
~/.config/psysh/config.php    # 全局配置
/.psysh.php                   # 项目级配置(项目根目录)
php
<?php
declare(strict_types=1);

// ~/.config/psysh/config.php

return [
    // 设置默认的提示符
    // 'prompt' => '>>> ',

    // 设置历史记录文件
    'historySize' => 1000,

    // 启用或禁用特定命令
    // 'commands' => [...],

    // 自定义 Tab 补全
    // 'tabCompletionMatchers' => [...],
];

自动加载 Composer 项目

PsySH 可以自动加载项目的 Composer 依赖:

bash
# 方式 1:在项目目录中启动 PsySH
cd /path/to/your/project
psysh

# PsySH 会自动检测 composer.json 并加载 autoload

# 方式 2:手动指定自动加载文件
psysh --bootstrap vendor/autoload.php

# 方式 3:在 PsySH 中手动加载
>>> require 'vendor/autoload.php';
bash
# 验证自动加载是否生效
>>> \App\Models\User::class
"App\Models\User"

>>> class_exists(\App\Models\User::class)
true

查看文档

PsySH 内置了 PHP 函数和类的文档查看功能:

bash
# 查看函数文档
>>> 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 在线获取。你也可以下载离线文档:

bash
# 下载 PHP 手册(用于离线文档查看)
mkdir -p ~/.local/share/psysh
cd ~/.local/share/psysh
curl -LO http://psysh.org/manual/zh/php_manual.sqlite

运行时变量检查

bash
# 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:快速验证代码逻辑

bash
# 验证正则表达式是否正确
>>> 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 新特性

bash
# 实验 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,
   ]
bash
# 实验 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 响应

bash
# 在 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
<?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_limitphp -d memory_limit=512M
历史记录丢失PsySH 配置文件中设置 historySize
无法加载项目依赖使用 --bootstrap 参数或 cd 到项目目录

注意事项

  1. 不要在生产环境使用 REPL:REPL 可以执行任意 PHP 代码,存在安全风险
  2. 变量状态保持:REPL 中的变量在会话期间保持状态,注意变量的影响
  3. 大文件处理:REPL 不适合处理大文件或长时间运行的任务
  4. 多行输入:PsySH 支持多行输入,注意使用 ... 续行符

最佳实践

  1. 日常使用 PsySH:PsySH 的自动补全、返回值显示和文档查看功能大大提升了代码实验效率。

  2. 项目级配置:在项目根目录创建 .psysh.php 配置文件,自动加载 Composer 依赖和常用命名空间。

  3. 代码实验:在编写正式代码前,先在 PsySH 中验证逻辑和 API 行为,避免反复修改文件。

  4. 学习 PHP 特性:使用 PsySH 来实验和学习 PHP 的新特性,直观地观察代码行为。

  5. 结合调试使用:PsySH 可以作为调试的辅助工具,在 REPL 中重现问题场景。

  6. TDD 辅助:在编写测试之前,先在 PsySH 中验证被测试的函数或方法的行为。

下一节

PHP REPL 是日常开发中非常实用的工具。建议你同时了解以下工具以构建完整的开发环境:

参考链接