• This repository has been archived on 21/Nov/2020
  • Stars
    star
    143
  • Rank 256,193 (Top 6 %)
  • Language
    PHP
  • License
    MIT License
  • Created over 10 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Provides ability to run R scripts from PHP

php-r

PHPR (or php-r) is a library that provides ability to run R scripts from PHP. Composer package: kachkaev/php-r.

Optionally, the library is available as a bundle for Symfony2 users.

The idea is based on invoking a command-line version of R and exchanging messages with this external process. Integration with server-based implementation of R can be easily implemented on demand as the library architecture supports that.

It is possible to both run all R code in one batch and interactively exchange commands with R interpreter.

Usage

Option 1: all R code in one batch

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 output:

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

Method run() is always called in a clean scope of R variables, i.e. the following usage will result an R error:

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

PHP output:

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

Option 2: interactive exchange of data

To exchange commands with a single R process interactively, another approach should be used:

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 output:

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

The process is synchronous, i.e. if R code sent to write() implies some complex computations, PHP will wait until they are finished.

Multiple commands can be passed to R inside one write(); they can be multi-line too:

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

It is strictly necessary to keep commands complete. The following example will result a critical error, and R process will be terminated.

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

Separate access to input / output / errors for each R command

To avoid manual splitting of a mix of R input, output and errors, the result of script execution can be accessed separately:

$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();

Passing true to get(LastWrite|All)Input/get(LastWrite|All)Output/get(LastWrite|All)Result splits strings into arrays, where each element corresponds to a single command:

$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]
// ]

Sensitivity to R errors

If it is necessary to make sure that a sequence of R commands is running with no errors, and calling hasLastWriteErrors() after each write() is unreasonable, the process can be made sensible to errors. RErrorsException will be thrown on write():

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

This is the same as:

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

R-related errors and the exception thrown are not critical; the same instance of R process can be still used after they occur. If last input contains multiple commands, and several of them cause errors, RErrorsException will have the complete list. In any case all commands passed to write() will be attempted by R interpreter.

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

Parsing R output

To ease parsing of R output, ROutputParser can be used:

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)

See PHPdoc annotations to classes for more details.

License

MIT. See LICENSE.

Donate

More Repositories

1

njt

njt (npm jump to): a quick navigation tool for npm packages
TypeScript
312
star
2

KachkaevAssetsVersionBundle

Automates the process of updating assets version in Symfony2 & Symfony3 projects
PHP
57
star
3

tooling-for-how-old-is-this-house

Tooling for adding new cities to https://how-old-is-this.house/en
TypeScript
40
star
4

video-easter-eggs

A visual analytics tool for finding Easter eggs in videos
TypeScript
9
star
5

website

Personal mini-website built with Next.js, React, TypeScript, Tailwind and Playwright
TypeScript
9
star
6

aws-iot-button-logger-to-git

Lambda function that can be triggered by an AWS IoT device to log clicks in a git repository
TypeScript
7
star
7

suppress-exit-code

Cross-platform CLI wrapper that runs any command and exits with zero
JavaScript
6
star
8

special-internet-archive

Tooling to archive web pages
TypeScript
5
star
9

routine-npm-packages

A monorepo with npm packages commonly used in personal projects
JavaScript
5
star
10

KachkaevDropboxBackupBundle

[ABANDONED SINCE 2013] Allows backing up your mysql database to dropbox using symfony console
PHP
5
star
11

city4people-wiki

PHP
4
star
12

CICommandLineFaceDetector

A simple command line tool to detect faces in photographs using Apple’s Core Image Library
Objective-C
3
star
13

graph-plotter

TypeScript
3
star
14

graphql-type-regexp

RegExp scalar type for GraphQL.js, https://www.npmjs.com/package/graphql-type-regexp
JavaScript
2
star
15

react-boilerplate-react-map-gl-mwe

JavaScript
2
star
16

KachkaevPHPRBundle

Symfony2/3 bundle for integration with php-r library that provides ability to run R scripts from PHP
PHP
2
star
17

github-actions-color-ouput-bug

Missing space
1
star
18

styled-components-with-heavy-svgs-mwe

SVG Performance problem reproduction for iOS Safari / Chrome
JavaScript
1
star
19

kachkaev

meta
1
star
20

next-i18n

A simple yet powerful way of making your Next.js app multilingual (powered by i18next)
JavaScript
1
star
21

survey-glyphs

Photo Content Assessment tool for my PhD project. http://www.photoassessment.org/
JavaScript
1
star