/php_repl

A REPL (Read-Eval-Print Loop) for PHP

Primary LanguagePHP

What is PHP_Repl?

PHP_Repl 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

$ git clone git://github.com/ieure/php_repl.git
$ cd php_repl
$ pear package
$ pear install PHP_Repl*tgz

Usage

When you fire up PHP_Repl, 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): PHP_Repl->run()
#2 /Users/ieure/Projects/php_repl/testrepl(20): PHP_Repl->__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 PHP_Repl
/**
 * PHP_Repl
 *
 * @package    PHP_Repl
 * @author     Ian Eure <ieure@php.net>
 * @version    @package_version@
 */
'---'
php> ,d PHP_Repl::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 PHP_Repl in your own projects.

require_once 'PHP/Repl.php';

function do_stuff()
{
    if ($debug_condition) {
        $repl = new PHP_Repl();
        $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 PHP_Repl 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 'PHP/Repl.php';

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

Configuration

PHP_Repl 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 PHP_Repl, so if you evaluate something which causes a fatal error, PHP_Repl 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 PHP_Repl. 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.

Emacs Integration

Because I really like Emacs, and enjoy the integration other languages (e.g. Common Lisp, Python, etc) have with it, I put together phprepl.el. It’s incomplete and may be buggy.

It provides run-php, which will fire up the PHP REPL of your choice (not just PHP_Repl, it should work with any interactive PHP tool). It has the beginnings of a minor-mode to send regions, buffers, etc to the REPL for evaluation, but this isn’t finished yet.

Installation

Drop php-repl.el somewhere in your load-path and (require 'php-repl).

Configuration

It’s customizable; M-x customize-group RET phprepl RET. Point php-repl-program at PHP/Repl.php.

Usage

M-x run-php will fire PHP_Repl up in a *php* buffer. Type and be happy.

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.