Say Hello to Boris: A Better REPL for PHP

Share this article

As web developers, we know the importance of the JavaScript console provided by the browser in testing out code snippets. We don’t need to write an entire HTML page and JavaScript code just to verify the functioning or logic of a small routine we wrote. Instead, we simply run the expressions in the console and immediately see the results. Similarly, a REPL (Read-Eval-Print Loop) is the console of a programming language in which we can write code line-by-line and see what it does. PHP has a REPL; if you haven’t used it yet, run php –a in a terminal. This will take you to the interactive PHP prompt at which you can enter your code.

$ php -a
Interactive shell

php > echo "Hello REPL";
Hello REPL
All programming language REPLs work essentially the same way. There is an infinite loop which essentially processes three tasks: a read task that reads in an expression entered at the prompt, an eval function that parses and executes the expression, and an print function to display the results of the action. PHP’s REPL is very good in what it does, although it does have some limitations. For example, it doesn’t handle errors very well; the REPL exits back to console whenever a fatal occurs. Another drawback of PHP’s default REPL compared to other languages’ is that it doesn’t output the result of an expression to the console; we have to explicitly tell it to echo or print the result. Most other REPLs always output the result of an expression to the console. And so, Boris tries to solve these problems and other concerns as well. Boris is a tiny PHP REPL library written in PHP by Chris Corbyn. It handles fatal errors more efficiently in that it won’t exit the console when an error occurs. Instead, it reports the error details and stack trace in the console. Boris also outputs the results of evaluating an expression.

Installation

Boris is hosted on GitHub, so it’s easy to install using Git. Note that Boris requires the PCNTL extension, so if it’s not already available on your machine then you can follow these steps to get it installed. Then, clone Boris to your machine.
$ git clone git://github.com/d11wtq/boris.git
This will clone the entire Boris library into a new directory boris in your current location, which contains an executable PHP script to load and run Boris. (Boris can be installed using Composer as well, which I’ll show you later.) To start using Boris, step inside the directory and run the script.
$ cd boris
$ ./bin/boris
This will take you to the Boris prompt. Just as with the default PHP prompt, we can enter the code here and run. Let’s try some simple expressions.
[1] boris> $timezone = new DateTimeZone("America/New_York");
→ object(DateTimeZone)#5 (0) {
}

[2] boris> $date =  new DateTime("now", $timezone);
→ object(DateTime)#6 (3) {
  ["date"]=>
  string(19) "2013-03-29 23:56:25"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(16) "America/New_York"
}
The result of an expression is always returned back to the console which helps us to inspect values/objects as soon as they are created. For easier access, you can add the path to the Boris script in your .bashrc (or similar) and reloading your shell environment. Then you’ll be able to run boris from anywhere in your terminal and be taken to the Boris prompt.
export PATH="path/to/boris/bin:$PATH"

Customizing Boris

An important feature of Boris is the ability to customize its features. If you look at the content of the ./bin/boris file, you’ll find it’s just a PHP file that initializes a Boris instance. We can change the default prompt by passing it in the constructor.
$boris = new BorisBoris('app $ ');
$boris->start();
But customization is not just limited to the prompt. We can also define some default variables to be available inside the REPL, with something like this:
$boris->setLocal("myVar", "Value");
We can then refer to the value with $myVar, which would help us avoid defining various variables every time we use Boris. By default, Boris shows results using var_dump(), but we can use our own inspectors to customize the REPL’s output. If you prefer some other format, create a class that implements the Inspector interface, which has a method called inspect().
class MyInspector implements Inspector {
    public function inspect($variable) {
        ob_start();
        print_r($variable);
        return trim(ob_get_clean());
    }
}

$boris->setInspector(new MyInspector());

A REPL in your Application

Boris can easily be embedded into your standalone PHP application or library as well. As an example, let’s create a command-line web service client using Boris and Guzzle. Guzzle is a powerful library for creating Web service clients and provides a simple interface for making API requests programmatically. First, create a composer.json file to set up the required libraries.
{
    "require": {
        "d11wtq/boris": "dev-master",
        "guzzle/guzzle": "~3.1"
    }
}
Then install these dependencies using Composer. This will download Boris, Guzzle, and their dependencies to a vendor
folder in the current directory.
$ composer.phar install
Next, create an executable script (I’ve named it wsclient) that will launch our application.
#!/usr/bin/env php
<?php
// composer autoloader
require "vendor/autoload.php";
use GuzzleHttpClient;

// Initialize Boris with our own prompt.
$boris = new BorisBoris("wsclient > ");

// Guzzle client with our API base URL
$client = new Client("http://myapplication/api");

// We don't want to create the Client object every time.
$boris->setLocal("client", $client);

// Default inspectors are bit noisy. Let's override that.
$boris->setInspector(new GuzzleInspector());

// Start the REPL
$boris->start();
We’ve included the autoloader provided by Composer which makes things easier. Then we’ve initialized Boris and created a Guzzle client explicitly for our web service so that we don’t need to do this over and over again. The client object is made available inside the REPL by setting it as a local variable with setLocal(). We aren’t interested in inspecting the variables and objects here, so we’ve overridden the default inspector with GuzzleInspctor. You can create one that will help you to debug responses from server, but the one I’ve created for the example looks like this:
<?php
class GuzzleInspector implements BorisInspector
{
    public function inspect($var) {
        ob_start();
        echo (bool) $var;
        return trim(ob_get_clean());
    }
}
Make the script executable, and then start the REPL and try some things out.
$ chmod +x wsclient
$ ./wsclient

[1] wsclient > $request = $client->get("/user")->setAuth("user", "pass");
 → true
[2] wsclient > $response = $request->send();
 → true
[3] wsclient > echo $response->getBody();
//{"login":"user","id":123000,"avatar_url":"...

Conclusion

I don’t need to explain the real power of a REPL if you’ve ever used Python, Ruby, Scala, OCaml, or any other language that offers one. A REPL is a great tool when first learning a language, and also when testing and debugging various code snippets. Like many other mainstream languages, PHP has a REPL, but it has some drawbacks, especially in error handling. Boris is a tiny library, which tries to fill in its gap. More interestingly, you can easily create a CLI for your applications using Boris. Although Boris is really cool and pretty useful at times, it does have some limitations of it’s own, too. Boris depends on the forking capability of the operating system, so it can’t be used in Windows. Also, as of now it’s not a bulletproof application. There are some issues that need to be fixed, and some more features like auto-completion of function names and class methods would be handy. I hope you will find many other use cases of this library; feel free to share them in the comment section below. Image via Fotolia

Frequently Asked Questions (FAQs) about Boris, a Better REPL for PHP

What makes Boris a better REPL for PHP compared to other REPLs?

Boris is a better REPL for PHP because it offers a full-featured PHP Read-Eval-Print-Loop. Unlike other REPLs, Boris supports complex types, tab completion, and maintains a history of your previous inputs. It also has a built-in debugger, which allows you to step through your code and inspect variables. This makes it a powerful tool for debugging and testing PHP code.

How does Boris handle complex types?

Boris has a unique feature that allows it to handle complex types. It can handle arrays, objects, and closures, which are often difficult to manage in other REPLs. This makes it easier for developers to test and debug their code, as they can interact with these complex types directly in the REPL.

Can I use Boris for interactive PHP scripting?

Yes, Boris is an excellent tool for interactive PHP scripting. It allows you to write and execute PHP code in real-time, making it a great tool for prototyping and testing. You can also use it to explore new libraries or APIs, as you can interact with them directly in the REPL.

How does Boris compare to PHP’s built-in interactive mode?

While PHP’s built-in interactive mode is useful, Boris offers several additional features that make it a more powerful tool. For example, Boris supports tab completion, which can save you time when writing code. It also maintains a history of your previous inputs, allowing you to easily revisit and modify past commands.

Can I override default PHP functions in Boris?

Yes, Boris allows you to override default PHP functions. This can be useful when you want to change the behavior of a function for testing or debugging purposes. However, you should be careful when doing this, as it can lead to unexpected results if not done correctly.

How does Boris handle errors?

Boris has a robust error handling system. If an error occurs while executing your code, Boris will catch it and display a helpful error message. This makes it easier to identify and fix issues in your code.

Can I use Boris for web development?

While Boris is primarily designed for console use, it can also be used for web development. You can use it to test and debug your PHP code, and it can be a valuable tool for exploring new libraries or APIs.

Is Boris suitable for beginners?

Yes, Boris is a great tool for beginners. It provides a safe and interactive environment where you can experiment with PHP code and learn about the language. The built-in debugger and error handling features also make it a great tool for learning how to debug and fix issues in your code.

How does Boris handle PHP’s eval() function?

Boris uses PHP’s eval() function to execute your code. However, it wraps it in a try-catch block to handle any errors that may occur. This allows Boris to provide helpful error messages and makes it easier to debug your code.

Can I use Boris on my server?

Yes, Boris can be installed and used on any server that supports PHP. This makes it a versatile tool that can be used in a variety of environments, from your local development machine to a remote server.

Shameer CShameer C
View Author

Shameer is a passionate programmer and open-source enthusiast from Kerala, India. He has experience in web development using Scala, PHP, Ruby, MySQL, and JavaScript. While not working, Shameer spends his time coding personal projects, learning, watching screen casts, blogging, etc. His specific areas of interest include cloud computing, and system and database administration.

Advanced
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week