kachkaev/php-r

该包已被废弃且不再维护。未建议替代包。

提供从PHP运行R脚本的能力

v1.0.1 2017-12-08 10:23 UTC

This package is not auto-updated.

Last update: 2020-11-29 00:09:16 UTC


README

PHPR (或 php-r) 是一个库,提供从PHP运行R脚本的能力。Composer包: kachkaev/php-r

可选地,对于Symfony2用户,该库作为一个提供。

该理念基于调用R的命令行版本,并与外部进程交换消息。由于库架构支持,可以轻松实现与基于服务器的R实现的集成。

可以批量运行所有R代码,也可以与R解释器进行交互式命令交换。

使用方法

选项1:批量运行所有R代码

use Kachkaev\PHPR\RCore;
use Kachkaev\PHPR\Engine\CommandLineREngine;

$r = new RCore(new CommandLineREngine('/path/to/R'));

$result = $r->run(<<<EOF
x = 1
y = 2
x + y
x + z
x - y
EOF
    );

echo $result;

PHP输出

> x = 1
> y = 2
> x + y
[1] 3
> x + z
Error: object 'z' not found 
> x - y
[1] -1

方法 run() 总是在R变量的干净作用域内调用,即以下用法将导致R错误

echo $r->run("x = 100")
echo "\n=====\n"
echo $r->run("x * x")

PHP输出

> x = 100
=====
> x * x
Error: object 'x' not found

选项2:交互式数据交换

要交互式地与单个R进程交换命令,应使用另一种方法

use Kachkaev\PHPR\RCore;
use Kachkaev\PHPR\Engine\CommandLineREngine;

$r = new RCore(new CommandLineREngine('/path/to/R'));
$rProcess = $r->createInteractiveProcess();
$rProcess->start();
$rProcess->write('x = 100');
// Do something else
$rProcess->write('x * x');

echo $rProcess->getAllResult();

PHP输出

> x = 100
> x * x
[1] 10000

该过程是同步的,即如果发送到 write() 的R代码包含一些复杂的计算,PHP将等待它们完成。

可以在一个 write() 内部传递多个命令给R;它们也可以是多行的

$rProcess->write(<<<EOF
x = 1
y = 10 + (x 
+ x / 2)
z = 42
EOF
    );

必须严格保持命令完整。以下示例将导致关键错误,并且R进程将被终止。

$rProcess->write('x = 1 + (');
// IncompleteRCommandException

为每个R命令单独访问输入/输出/错误

为了避免手动拆分R输入、输出和错误的混合,可以单独访问脚本执行的结果

$rProcess = $r->createInteractiveProcess();
$rProcess->start();
$rProcess->write(<<<EOF
x = 1
y = 2
x
y
EOF
    );
    
$rProcess->write(<<<EOF
x + 41
x + xxx
x + y
EOF
    );
    
echo $rProcess->getLastWriteInput();
// x + 41
// x + xxx
// x + y

echo $rProcess->getLastWriteOutput();
// 42
// 
// [1] 3

echo $rProcess->hasLastWriteErrors();
// true

echo $rProcess->getLastWriteErrorCount();
// 1

$errors = $rProcess->getLastWriteErrors();
echo $errors[0]->getErrorMessage()
// object 'xxx' not found
echo $errors[0]->getCommand()
// x + xxx

$rProcess->getAllInput();
$rProcess->getAllOutput();
$rProcess->hasErrors();
$rProcess->getErrorCount();
$rProcess->getErrors();

true 传递给 get(LastWrite|All)Input/get(LastWrite|All)Output/get(LastWrite|All)Result 将字符串拆分为数组,其中每个元素对应于单个命令

$rProcess = $r->createInteractiveProcess();
$rProcess->start();
$rProcess->write(<<<EOF
x = 
1 + 1
y
x
EOF
    );
$inputAsArray = $rProcess->getAllInput(true);
// ['x ={newline}1 + 1', 'y', 'x']
$outputAsArray = $rProcess->getAllOutput(true);
// ['', null, '2']
$resultAsArray = $rProcess->getAllResult(true);
// [
//   ['x ={newline}1 + 1', '', null],
//   ['y', null, 'Error: object \'y\' not found'],
//   ['x', '2', null]
// ]

R错误敏感性

如果需要确保一系列R命令无错误地运行,并且每次调用 write() 后调用 hasLastWriteErrors() 不合理,则可以使过程对错误敏感。在 write() 上抛出 RErrorsException

$rProcess->setErrorSensitive(true);
$rProcess->write('x = 1 + missingVariable');
// RErrorsException 

这等同于

$rProcess->setErrorSensitive(false);
$rProcess->write('x = 1 + missingVariable');
if ($rProcess->hasLastWriteErrors()) {
    throw new RErrorsException($rProcess->getLastWriteInput(true), $rProcess->getLastWriteOutput(true), $rProcess->getLastWriteErrors());
}

R相关的错误和抛出的异常不是关键的;发生错误后,仍然可以使用相同的R进程实例。如果最后一个输入包含多个命令,并且其中几个导致错误,则 RErrorsException 将包含完整的列表。在任何情况下,都会尝试将传递给 write() 的所有命令交给R解释器。

$allErrors = $rErrorsException->getErrors();
if (count ($allErrors) > 1) {
    $secondError = $allErrors[1];
    echo $secondError->getErrorMessage();
}

R输出解析

为了简化R输出的解析,可以使用 ROutputParser

use Kachkaev\PHPR\ROutputParser;

$rOutputParser = new ROutputParser();
$rProcess->write('21 + 21');
var_dump($rProcess->getLastWriteOutput());
// string(6) "[1] 42"
var_dump($rOutputParser->singleNumber($rProcess->getLastWriteOutput()));
// int(42)

请参阅类中更详细的PHPdoc注释。

许可

MIT。请参阅 LICENSE

Donate