PRQL PHP 绑定指南:使用 prql-php 通过 FFI 将 PRQL 编译为 SQL
后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载prql-php 是 PRQL 编译器在 PHP 生态中的官方绑定通过 PHP FFIForeign Function Interface直接调用 Rust 编写的prqlc核心库为 PHP 应用提供 PRQL → SQL 的编译能力。本文基于 prql-php 官方 README 及仓库源码讲解环境准备、Compiler 类四大核心 API、Options 与 Result 数据结构并结合源码级实现细节说明其底层工作原理帮助你在 PHP 8.1 项目中快速集成并正确处理编译结果与错误信息。一、prql-php 是什么prql-php是 PRQL 项目为 PHP 语言提供的官方编译器绑定位于 prqlc/bindings/php 目录。PRQLPipelined Relational Query Language是一种现代化的数据转换语言旨在作为 SQL 的可读替代品。在 PHP 中你可以用管道风格的 PRQL 语法编写查询再交由prql-php在运行时编译成目标数据库可执行的 SQL。从实现方式看prql-php走的是FFI 路线它不把编译器逻辑用 PHP 重写而是直接加载 Rust 编译产物libprqlc_c共享库通过 PHP 内置的 FFI 扩展调用 C ABI 导出的编译函数。这意味着 PHP 侧只负责参数编组、内存管理与结果封装核心编译能力与官方prqlc完全一致。需要注意的现状以当前仓库为准该绑定仍处于早期阶段README 明确说明 still at an early stage尚未发布到 Composer需要从仓库源码自行构建集成依赖 PHP FFI 扩展并要求 PHP 8.1见 composer.json 中php: ^8.1与ext-ffi: *声明支持通过 PSR-4 自动加载命名空间为Prql\Compiler\。在开始使用前建议先了解 PRQL 语言本身的语法可参考 语言文档以及prqlc编译器总体架构见 ARCHITECTURE.md。二、安装与运行环境准备2.1 启用 PHP FFI 扩展prql-php依赖 PHP 的 FFI 扩展。PHP 8 及以上版本默认内置该扩展但出于安全考虑FFI 默认处于禁用状态需要显式开启编辑php.ini将ffi.enable设置为true重启 PHP-FPM / CLI 进程使配置生效。以命令行快速验证扩展是否加载php -m | grep ffi # 或 php -r var_dump(extension_loaded(ffi));扩展未启用时实例化Compiler会直接失败因为类内部依赖\FFI::cdef()加载共享库见 Compiler.php 构造方法。仓库测试 CompilerTest.php 的第一步就是断言ffi扩展已加载。2.2 构建 libprqlc_c 共享库Compiler构造时会在lib目录中查找 C 头文件prqlc.h和平台对应的共享库操作系统期望文件WindowsPHP_OS_FAMILY Windowslib/libprqlc_c.dllmacOSPHP_OS_FAMILY Darwinlib/libprqlc_c.dylibLinux / 其他lib/libprqlc_c.so这个平台判断逻辑直接体现在 Compiler.php 中。若找不到库或头文件构造会抛出InvalidArgumentExceptionCannot load header file.。构建产物来自prqlc-ccrate其 C ABI 入口实现在 prqlc/bindings/prqlc-c/src/lib.rsC 头文件模板为 prqlc/bindings/prqlc-c/prqlc.h。仓库根目录的 Taskfile.yaml 提供了build-php任务一条命令即可完成整个构建流程task build-php该任务实际执行见 Taskfile.yamlcargo build --package prqlc-c --release # 1. 以 release 模式编译 Rust 库 mkdir -p prqlc/bindings/php/lib/ # 2. 创建 lib 目录 cp target/release/libprqlc_c.* prqlc/bindings/prqlc-c/prqlc.h prqlc/bindings/php/lib/ # 3. 复制共享库与头文件到 lib/ cd prqlc/bindings/php composer install # 4. 安装 PHP 依赖如果你不使用 Task也可以手动执行上述命令效果等同。2.3 使用 nix 搭建开发环境README 推荐使用 nix flake 快速获得带 ext-ffi 的 PHP 8.1 开发环境。首先启用 nix 的实验特性mkdir -p ~/.config/nix echo experimental-features nix-command flakes ~/.config/nix/nix.conf然后在prqlc/bindings/php/目录内进入开发 shellnix shell github:loophp/nix-shell#env-php81 --impure该 shell 会自动拉入 ext-ffi 扩展——因为 composer.json 中声明了ext-ffi: *依赖。三、快速上手第一个编译示例按照 README 的 Usage 示例最小可运行代码如下?php use Prql\Compiler\Compiler; $prql new Compiler(); $result $prql-compile(from employees); echo $result-output;这段代码的输出是一段等价 SQL例如SELECT * FROM employees把这段代码放到启用 FFI、且lib/中已具备共享库的环境中即可运行。下面我们深入剖析这个Compiler类。四、Compiler 类四个核心编译 APICompiler是prql-php的唯一入口类final class Compiler见 Compiler.php。它把prqlc的编译流水线暴露为四个方法对应 PRQL 编译管线的四个阶段compile()一步完成 PRQL → SQL 的完整编译prqlToPL()PRQL → PLPipeline Language解析后的抽象语法树JSON 序列化plToRQ()PL → RQRelational Query经过名称解析与类型推断的关系查询中间表示JSON 序列化rqToSQL()RQ → SQL 字符串。四个方法均以string接收输入返回Result对象。4.1 compile()PRQL 一步编译为 SQLpublic function compile(string $prql_query, ?Options $options null): Result$prql_queryPRQL 查询字符串为空字符串时抛出InvalidArgumentException(No query given.)见 Compiler.php$options可选的Options对象控制 SQL 输出格式与方言返回Result其中output为编译出的 SQL。从 C 侧看compile对应prqlc-c的compile导出函数。源码注释明确指出它是prql_to_pl、pl_to_rq、rq_to_sql三个步骤的封装且中间不经过 JSON 序列化见 prqlc-c/src/lib.rs因此在语义上等价于把下游三个方法串起来但性能更优。4.2 prqlToPL()查看解析树public function prqlToPL(string $prql_query): Result把 PRQL 源码解析为 PL AST并以 JSON 形式放入Result-output。对应 C 侧prql_to_pllib.rs内部调用prqlc::prql_to_pl后经prqlc::json::from_pl序列化。$pl $prql-prqlToPL(from employees | select first_name); // $pl-output 为 PL 的 JSON 表示4.3 plToRQ()PL 中间表示转 RQpublic function plToRQ(string $pl_json): Result接收上一步输出的 PL JSON执行变量引用解析、函数调用校验、frame 推断等语义处理见 lib.rs 注释输出 RQ 的 JSON。$rq $prql-plToRQ($pl-output);4.4 rqToSQL()RQ 转 SQLpublic function rqToSQL(string $rq_json, ?Options $options null): Result接收 RQ JSON结合Options生成最终 SQL见 lib.rs。$sql $prql-rqToSQL($rq-output);4.5 分步管线与一步编译的一致性仓库测试 CompilerTest.php 专门验证了这一点先用prqlToPL → plToRQ → rqToSQL分步编译一个含let绑定的查询再用compile一步编译同一查询最后断言两者输出完全相等assertEquals($via_json, $direct)。这证明四条 API 共享同一条编译流水线你可以在一步到位与逐步检查中间产物之间自由选择。五、Options控制 SQL 输出Options类Options.php封装了 SQL 后端的编译选项三个公共属性与 C 侧Options结构体一一对应属性类型默认值含义$formatbooltrue是否将生成的 SQL 通过格式化器拆分多行并美化缩进与间距$target?stringnull编译目标方言如sql.mssqlnull表示使用默认方言$signature_commentbooltrue是否在生成的 SQL 末尾追加编译器签名注释典型用法use Prql\Compiler\Options; $options new Options(); $options-format false; // 关闭 SQL 美化输出单行紧凑 SQL $options-signature_comment false; // 去掉签名注释 $options-target sql.mssql; // 指定 SQL Server 方言 $result $prql-compile(from employees | take 10, $options);当$options为null时Compiler会内部 new 一个默认Options见 Compiler.php 的optionsInit因此不传参数也能工作。5.1 内存管理细节Options从 PHP 对象映射到 C 结构体时$target字符串需要复制为 C 字符串缓冲区\FFI::new(char[$len], false)\FFI::memcpy编译结束后由optionsDestroy显式\FFI::free释放见 Compiler.php。这是 FFI 绑定中典型的手动内存管理也解释了为什么$target不能为null时跳过分配。5.2 方言示例SQL Server测试 CompilerTest.php 给出了一个可复现的方言示例将from employees | take 10以sql.mssql目标编译formatfalse、signature_commentfalse得到SELECT * FROM employees ORDER BY (SELECT NULL) OFFSET 0 ROWS FETCH FIRST 10 ROWS ONLY这展示了take在 SQL Server 方言下如何被翻译为标准的OFFSET ... FETCH FIRST语法。支持的具体目标方言可在 prqlc 的 Target 定义 与 方言文档 中进一步查阅。六、Result、Message 与错误处理6.1 Result 结构编译结果统一封装为ResultResult.phpfinal class Result { public string $output; // 编译输出SQL 或中间表示 JSON public array $messages; // Message 对象数组错误/警告/提示 }注意compile不会因为 PRQL 语法错误而抛异常——错误信息放在$messages数组中$output在出错时通常为空。因此正确用法是先检查$messages再使用$output。6.2 Message结构化错误信息每个MessageMessage.php包含属性类型含义$kindMessageKind消息类型Error/Warning/Lint$code?string机器可读的错误标识符$reasonstring错误的纯文本描述$hint?string修复建议列表$span?Span源码中的字符偏移范围start/end$display?string带原因和提示的源码标注文本$location?SourceLocation源码中的行列位置start_line/start_col/end_line/end_colMessageKind是 PHP 8.1 枚举MessageKind.php包含Error、Warning、Lint三个 case。C 侧返回的kind字段为整数0Error、1Warning、2LintPHP 侧在convertMessage中做映射见 Compiler.php。需要注意的是目前消息只完整实现了Error一类Message.php 注释 Currently only Error is implemented。SpanSpan.php以字符偏移标识错误来源范围SourceLocationSourceLocation.php进一步给出行列号便于在编辑器中定位。6.3 错误处理示例$prql new Compiler(); $res $prql-compile(invalid); // 故意传入非法查询 foreach ($res-messages as $msg) { if ($msg-kind MessageKind::Error) { printf([%s] %s\n, $msg-code ?? error, $msg-reason); if ($msg-location ! null) { printf( at line %d, col %d\n, $msg-location-start_line, $msg-location-start_col); } if ($msg-hint ! null) { printf( hint: %s\n, $msg-hint); } } }测试 CompilerTest.php 中compile(invalid)会得到一个包含 1 条 message 的结果正是这一行为的验证。七、开发与测试7.1 构建与测试README 给出的两条命令即可完成构建与测试task build-php task test-php其中test-php任务在prqlc/bindings/php目录下执行vendor/bin/phpunit tests见 Taskfile.yaml。PHPUnit 测试套件覆盖了以下场景CompilerTest.phpFFI 扩展已加载lib/libprqlc_c.so|.dylib|.dll共享库存在lib/prqlc.h头文件存在非法查询返回错误消息而非崩溃指定方言编译take得到预期 SQL分步管线与一步compile输出一致。运行测试前记得先执行composer installbuild-php已包含该步骤以获取 PHPUnit 等开发依赖。7.2 代码规范代码风格遵循 PSR-12可用 phpcs 校验./vendor/bin/phpcs --standardPSR12 src tests此外仓库还配置了 phpstan.neon 用于静态分析。八、在 PHP 项目中集成由于绑定尚未发布到 Composer集成方式为源码引入将prqlc/bindings/php/目录纳入项目vendor 或子模块方式均可执行composer install其 PSR-4 自动加载配置会将Prql\Compiler\映射到src/见 composer.json按第二节步骤构建libprqlc_c并放入lib/Compiler默认从__DIR__ . /../lib查找也可通过构造函数参数$lib_path指定自定义路径见 Compiler.php确保运行环境ffi.enabletrue且 PHP ≥ 8.1。一个更完整的示例?php require vendor/autoload.php; use Prql\Compiler\Compiler; use Prql\Compiler\Options; use Prql\Compiler\MessageKind; $prql new Compiler(); // 或 new Compiler(/absolute/path/to/lib) $options new Options(); $options-format true; $options-target sql.postgres; $result $prql-compile(from employees | filter age 30 | select {name, age}, $options); if (count($result-messages) 0) { echo $result-output; // 得到 PostgreSQL 方言的 SQL } else { foreach ($result-messages as $msg) { if ($msg-kind MessageKind::Error) { fwrite(STDERR, $msg-display ?? $msg-reason . PHP_EOL); } } }九、总结与限制prql-php以极薄的 FFI 封装让 PHP 应用获得与官方编译器完全一致的 PRQL 编译能力。其 API 设计围绕Compiler类的四个方法展开compile面向日常使用其余三个方法面向需要逐阶段检查中间表示的调试与集成场景Options控制方言与格式ResultMessage提供结构化的错误信息与源码定位。使用前请留意以下限制绑定仍处于早期阶段未发布至 ComposerAPI 可能随prqlc演进而变化需要手动构建并放置libprqlc_c共享库各平台文件名不同依赖 FFI 扩展需在php.ini中显式开启ffi.enable错误消息目前主要支持Error类型Warning与Lint的枚举已定义但未完全实现。如果你希望深入了解编译流水线本身PL/RQ 中间表示、SQL 方言生成建议继续阅读 prqlc 架构文档、C 绑定实现 prqlc-c/src/lib.rs 以及 PHP 绑定源码目录。赞分享后端【免费下载链接】prqlPRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement项目地址https://gitcode.com/gh_mirrors/pr/prql点击查看免费下载相关推荐使用 prql-php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL使用 prql php通过 PHP FFI 调用 PRQL 编译器将 PRQL 查询编译为 SQL PRQLPipelined Relational Que后端PRQL 官方 minimal-cpp 示例解析在 C 中通过 prqlc-c FFI 编译 PRQL 查询PRQL 官方 minimal cpp 示例解析在 C 中通过 prqlc c FFI 编译 PRQL 查询 PRQLPipelined Relatio后端PRQL Elixir Bindings在 Elixir 中编译 PRQL 查询为 SQL 的完整指南PRQL Elixir Bindings在 Elixir 中编译 PRQL 查询为 SQL 的完整指南 PRQLPipelined Relational Q后端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考