pmeth/php_repl

A command line REPL (Read-Evaluate-Print-Loop) for PHP written in PHP.

dev-master 2014-02-14 14:04 UTC

README

PHPRepl is a read-eval-print loop for PHP, written in PHP. It aims to be light, clean, modern, object-oriented, and to leverage the existing features of PHP wherever possible.

Installation

The library is available through Composer, so its easy to get it. Simply add this to your composer.json file:

"require": {
    "pmeth/php_repl": "dev-master"
}

And run composer install

Usage

When you fire up PHPRepl, you’re greeted with a prompt:

php>

Any PHP code you enter here is evaluated, and its result printed. You don’t need to include trailing semicolons.

php> 5+5
int(10)
php>

The return value of the last expression you evaluated is held in $_.

php> $_
int(10)
php>

The type of display varies depending on the return type. Numeric types and booleans are displayed with var_dump(). Strings and arrays are printed with var_export(), and anything else uses print_r().

php> "123"
'123'
php> "don't"
'don\'t'
php> 5.5
float(5.5)
php> false
bool(false)
php> null
NULL
php>

Uncaught Exceptions are caught and dumped:

php> throw new Exception("Test 123", 123)
exception 'Exception' with message 'Test 123' in /Users/ieure/Projects/php_repl/PHP/Repl.php(143) : eval()'d code:1
Stack trace:
#0 /Users/ieure/Projects/php_repl/PHP/Repl.php(143): eval()
#1 /Users/ieure/Projects/php_repl/PHP/Repl.php(62): PHPRepl->run()
#2 /Users/ieure/Projects/php_repl/testrepl(20): PHPRepl->__construct(Array)
#3 {main}
php>

If an exception is caught, it’s stored in $_, since there won’t be a meaningful return value from the executed code.

If the last character of the entered line is a backslash, the REPL will accumulate lines until a line not ending in a backslash is found; the block of lines will then be evaluated. When the REPL is accumulating lines, the prompt changes to >.

php> $foo = array('one', \
> 'two', \
> 'three')
array (
  0 => 'one',
  1 => 'two',
  2 => 'three',
)
php>

Certain aspects of the input are altered before the code is evaluated. For example, return is prepended for most expressions, a semicolon is added if it was omitted, and so on. See Expansion, below.

When you’re done with the REPL, you can send ^D, die, or exit to quit.

Sugar

There are a few features to make your life easier. Sugar commands run a method in the REPL code to help you examine your code. They’re two characters, the first of which is always a comma, followed by a thing to examine.

Documentation

Doc blocks can be accessed with ,d:

php> ,d PHPRepl
/**
 * PHPRepl
 *
 * @package    PHPRepl
 * @author     Ian Eure <ieure@php.net>
 * @version    @package_version@
 */
'---'
php> ,d PHPRepl::read
/**
 * Read input
 *
 * @param
 *
 * @return string Input
 */
'---'
php>

Reflection

The REPL knows how to reflect classes, objects, and methods.

php> ,, sort
Function [ <internal:standard> function sort ] {

  - Parameters [2] {
    Parameter #0 [ <required> &$arg ]
    Parameter #1 [ <optional> $sort_flags ]
  }
}
'---'

Expansion

As mentioned, input is slightly altered before it is evaluated. Since this may produce unexpected effects, you can examine the expanded code with the ,e shortcut, or by running $this->cleanup():

php> 5+5
int(10)
php> ,e
'return 5+5;'
php> $this->cleanup('5+5')
'return 5+5;'
php> ,e 5+5
'return 5+5;'

Reuse

You can reuse PHPRepl in your own projects.

require_once 'PHPRepl.php';

function do_stuff()
{
    if ($debug_condition) {
        $repl = new PHPRepl();
        $repl->run();
    }
}

The REPL will have access to whatever scope your function does. If you invoke it from an object method, be aware that $this is always the PHPRepl instance, not your object.

Passing Scope

If you would like to pass additional variables into the REPL’s scope, you may include them in an array passed to run().

require_once 'PHPRepl.php';

class StuffDoer {
    function do_stuff()
    {
        if ($debug_condition) {
            $repl = new PHPRepl();
            $repl->run(array('_caller' => $this));
        }
    }
}

Configuration

PHPRepl stores its configuration in $HOME/.phpreplrc. A default file will be created for you if none exists. Any options you set while the REPL is running will be written out when you quit it.

The following options are recognized:

  • prompt. The prompt the REPL displays.
  • readline. Whether to use readline or not.
  • readline_hist. The path to the readline command history file.

Dangers

  1. The evaluated code is run in the same process as PHPRepl, so if you evaluate something which causes a fatal error, PHPRepl will terminate. Sorry.
  2. Output buffering is used to capture anything printed by eval’d code. If you have code which produces output over a long period of time, you may not see the results right away. Use flush().
  3. Certain settings are enforced by PHPRepl. You can’t change the values of:
    1. display_errors. It’s always on.
    2. html_errors. Always off.
    3. error_reporting. Always E_ALL | E_STRICT.
    4. Output buffering. It’s always enabled around the eval’d code.
    5. ob_implicit_flush. Always on.
    6. The output buffer’s callback method.

Alternatives

I looked at a few different projects which aim to provide similar functionality, but rejected them for various reasons.

  • php -a. Built-in, unusable. It filters code through PHP as if they were plain files, so if you want any code to actually execute, you need to wrap it in <?php ?> tags. No prompt, line editing, or history.

  • phpsh. Developed by Facebook, and unmaintained since 2006. It uses Python to wrap around PHP, and it doesn’t work with the Python shipped with OS X.

  • PHP_Shell. In PEAR, also unmaintained since 2006. Really, really big. Uses the Token API to parse the string before eval’ing. Rolls its own command language for the REPL, rather than leveraging the fact that it’s a mechanism for playing with a run environment.

  • phpa. The closest to what I wanted, but not quite there. It’s also moldy, and it’s procedural PHP 4 code. Requires readline, which is nice for a terminal, but useles for running in Emacs.

  • PHP Interactive. A webapp, rather than something which can be used from the commandline.