PHPackages                             emacros/emacros - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. emacros/emacros

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

emacros/emacros
===============

The Extensible Macros Library for PHP

1.1.1(11y ago)52311BSD 2-Clause LicensePHPPHP &gt;=5.4.0

Since Feb 28Pushed 11y ago1 watchersCompare

[ Source](https://github.com/emaphp/eMacros)[ Packagist](https://packagist.org/packages/emacros/emacros)[ RSS](/packages/emacros-emacros/feed)WikiDiscussions master Synced 3w ago

READMEChangelog (5)DependenciesVersions (6)Used By (1)

eMacros
=======

[](#emacros)

The Extensible Macros Library for PHP

[![Build Status](https://camo.githubusercontent.com/2f043f1ecc610f583bdce51b5798c384c3fc31c237233dd087355e784f38abff/68747470733a2f2f7472617669732d63692e6f72672f656d617068702f654d6163726f732e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/emaphp/eMacros)

**Author**: Emmanuel Antico
**Last Modification**: 07/01/2015

\##About

*eMacros* is a PHP library based on \[lisphp\] ( "") that features a customizable LISP dialect interpreter.

\##Requirements

An updated version of PHP 5.4 is required tu run this library.

\##Installation

*eMacros* installation is performed via Composer. Add the following file to your project folder and perform the usual installation which is \[described here\] ( # installation-nix "").

**composer.json**

```
{
    "require": {
        "emacros/emacros": "1.1.*"
    }
}
```

\##Introduction

The following example shows the implementation of a simple program that calculates the sum of 2 numbers.

```
include 'vendor/autoload.php';

use eMacros\Program\Program;
use eMacros\Environment\DefaultEnvironment;

//create program instance
$program = new Program('(+ 3 7)');

//run program
$result = $program->execute(new DefaultEnvironment);

//show results
echo $result; //prints 10
```

This script begins by creating a new instance of a program which receives the code to be interpreted. For being able to run a program an environment instance is required. The *execute* method performs the execution of a program using the environment provided as an argument. The obtained value is then returned.

There are several types of programs, each one of these can generate different types of results based on its instructions. The class *Program* defines the simplest type of program. This class returns the result of the last executed instruction. The following program includes 2 instructions but only one value is returned.

```
$program = new Program('(+ 3 7)(- 6 3)');
```

Since *Program* always returns the last generated value, instead of 10 we would have obtained 3, that is, the result of subtracting 3 to 6.

To store all the results obtained from each expression we can use the \*ListProgram\* class. This class works by storing each generated value in an array. ```
include 'vendor/autoload.php';

use eMacros\Program\ListProgram;
use eMacros\Environment\DefaultEnvironment;

$program = new ListProgram('(+ 3 7)(- 6 (+ 1 2))');
$result = $program->execute(new DefaultEnvironment);

echo $result[0]; //prints 10
echo $result[1]; //prints 3
```

The *TextProgram* class returns the result of concatenating each evaluated expression in a program. This example generates a message by using the concatenation operator.

```
include 'vendor/autoload.php';

use eMacros\Program\TextProgram;
use eMacros\Environment\DefaultEnvironment;

$program = new TextProgram('(. "Hel" "lo" " ")(. "Wo" "rld")');
$result = $program->execute(new DefaultEnvironment);

echo $result; //prints "Hello World"
```

\##The DefaultEnvironment class

The *DefaultEnvironment* class defines a default execution environment where applications can run. An environment defines the list of symbols and operations that the program will be able to interpret. This ranges from simple operations such as arithmetic (+, -, \*, /) to more complex ones (if, or, @name, Array::reverse). Symbols and operations are added to an environment by *importing packages*. Current implementation of the *DefaultEnvironment* class looks like the following:

```
namespace eMacros\Environment;

use eMacros\Package\CorePackage;
use eMacros\Package\StringPackage;
use eMacros\Package\ArrayPackage;
use eMacros\Package\RegexPackage;
use eMacros\Package\DatePackage;

class DefaultEnvironment extends Environment {
	public function __construct() {
		$this->import(new StringPackage);
		$this->import(new ArrayPackage);
		$this->import(new RegexPackage);
		$this->import(new DatePackage);
		$this->import(new CorePackage);
	}
}
```

*CorePackage*, *StringPackage*, *ArrayPackage*, etc are classes that define a list of symbols and operations to be used within a program. By importing a package to an environment we enable the use of symbols and operations defined within that package.

The *DefaultEnvironment* class comes with a fair amount of functions, which makes it ideal for start experimenting on our own. The rest of the packages can be found in the *eMacros\\Package* namespace.

\##Running programs from files

Programs can also be loaded from files. Having the application code in another file turns useful for adding comments, which improves readability. This program is similar to the previous example, except that it also returns the version of PHP running on the system.

```
; hello_world.em
; This is a comment
(. "Hello" " World!" "\n") ; Another comment
(. "This script is running under PHP " PHP_VERSION "\n")
; END
```

This example uses the *file\_get\_contents* function to obtain the contents of a source file.

```
include 'vendor/autoload.php';

use eMacros\Program\TextProgram;
use eMacros\Environment\DefaultEnvironment;

$program = new TextProgram(file_get_contents('hello_world.em'));
$result = $program->execute(new DefaultEnvironment);

echo $result;
```

\##The CorePackage class

The *CorePackage* class is extremely important when building a program execution environment. Among the elements that are contained on this package are:

- The *null*, *true* and *false* symbols.
- Arithmetic, comparison and logic operators.
- Variables and symbols functions.
- Class/objects functions.
- Argument functions.
- Type handling functions.
- Etc.

As noted, the functionality of this package is very critical so it is recommended to have it included whenever we create a customized environment. Below is a brief overview of the capabilities of this package.

\#####Comparison operators

```
; comparison.em
; Comparison operators always return a boolean value

; equal
(== 1 "1") ; equal to
(!= 1 2) ; not equal to

; identical
(=== 1 1) ; identical to
(!== 1 "1") ; not identical to

; greater than
(> 6 4) ; greater than
(>= 4 4) ; greater than or equal to

; lesser than
(name = "GNU/Linux"
(#= "family" _os "Unix-like") ; _os->family = "Unix-like"

; get key/property value (#)
(. "System " (# "name" _os) " is a " (# "family" _os) " OS")

; check if key/property exists (#?)
(if (not (#? "company" _os)) " and is libre")
```

Same functions can be used with array keys.

```
; keys.em
(:= _arr (array ("program" "keys.em") ("language" "eMacros")))
(. "Program" (# "program" _arr) " is written in " (# "language" _arr))

; stores status in array
(#= "status" _arr "Running")

; check key existence
(if (#? "status" _arr) (. "Program status: " (# "status" _arr)) "Unknown status")
```

The *CorePackage* class also defines an abbreviated way for obtaining key/properties through *macros*.

```
; short_keys.em

;; OBJECTS

; create instance
(:= _os (new stdClass))

; assign value (#PROPERTY=)
(#name= _os "GNU/Linux") ; _os->name = "GNU/Linux"
(#family= _os "Unix-like") ; _os->family = "Unix-like"

; get value (#PROPERTY)
(. "System " (#name _os) " is a " (#family _os) " OS")

; check property (#PROPERTY?)
(if (not (#company? _os)) " and is libre")

;; ARRAYS
(:= _arr (array ("program" "keys.em") ("language" "eMacros")))
(. "Program " (#program _arr) " is written in " (#language _arr))

; stores program status
(@status= _arr "Running")

; check key existence
(if (#status? _arr) (. "Program status: " (#status _arr)) "Unknown status")
```

This operator supports numeric indexes as well.

```
; numeric_keys.em
(:= _arr (array))
(#0= _arr "First element")
(#-2= _arr "Index -2")

(if (not (#1? _arr)) "No element available on index 1")

(. "Array first element " (#0 _arr))
```

\#####Class/Object functions

```
; class_functions.em
(:= _song (new stdClass))
(#name= _song "Meditango")
(#artist= _song "Astor Piazzolla")
(#genre= _song "Tango")

; get-object-vars
(get-object-vars _song) ; ["name" => "Meditango", "artist" => "Astor Piazzolla", "genre" => "Tango"]

; get-class
(get-class _song) ; "stdClass"

; instance-of
(instance-of _obj stdClass) ; true
(instance-of _obj ArrayObject) ; false

; is-a
(is-a _obj "stdClass") ; true
(is-a _obj "ArrayObject") ; false

; property-exists
(property-exists "eMacros\\Symbol" "package") ; true

; method-exists
(method-exists "ArrayObject" "count") ; true

; is-subclass-of
(is-subclass-of "eMacros\\Environment\\DefaultEnvironment" "eMacros\\Scope") ; true

; get-parent-class
(get-parent-class "eMacros\\Environment\\DefaultEnvironment") ; "eMacros\Environment\Environment"

; get-class-vars
(get-class-vars "eMacros\\Literal") ; ["value" => NULL]

; get-class-methods
(get-class-methods "eMacros\\Expression") ; ["evaluate"]

; class-alias
(class-alias "eMacros\\Symbol" "symbol")
(:= _song (new symbol "song"))
```

\#####Method invocation

```
; methods.em
(:= _name (new ArrayObject (array "john" "charles" "peter")))
(-> "count" _names) ; 3

; abbreviated
(->count _nombres)

; parameters
; (now) obtains a DateTime instance with the current time
(->format (now) "Y-m-d H:i") ; get current date
```

\##Arguments

A program can accept an arbitrary number of arguments. These must be specified right after the environment instance.

```
; arguments.em
; This program obtains the number of passed arguments

; argument counter (%#)
(. (%#) " parameters have been found\n")

; obtain arguments as array (%_)
(. "Arguments: " (implode "," (%_)))
```

This script performs the execution of the previous program with 3 arguments.

```
include 'vendor/autoload.php';

use eMacros\Program\TextProgram;
use eMacros\Environment\DefaultEnvironment;

//create program instance
$program = new TextProgram(file_get_contents('arguments.em'));

//add arguments
$result = $program->execute(new DefaultEnvironment, 1, "hello", 5.5);

//print results
echo $result;
```

The obtained output is the following:

```
3 parameters have been found
Parameters: 1,hello,5.5
```

We can access each argument individually with the corresponding functions:

```
; arg_functions.em

; get argument by index (%)
(+ 5 (% 0)) ; 5 + 1

; check argument existence (%?)
(if (%? 1) (. (% 1) " mundo")) ; "hola mundo"

; abbreviated form (%ARGN) (%ARGN?)
(if (%1?) (. (%1) " world")) ; "hello mundo"
```

\#####The *executeWith* method

The \*executeWith\* method can be used to send a list of arguments as an array. Using this method we can rewrite the previous example in the following way. ```
include 'vendor/autoload.php';

use eMacros\Program\TextProgram;
use eMacros\Environment\DefaultEnvironment;

//create program instance
$program = new TextProgram(file_get_contents('arguments.em'));

//run program
$result = $program->executeWith(new DefaultEnvironment, [1, "hello", 5.5]);

//print results
echo $result;
```

\##Packages

*eMacros* has several packages available organized by type within the *eMacros\\Package* namespace. The following script demonstrates the use of some functions that are available in the 'String' package.

```
; string_functions.em
; len (strlen)
(len "hello") ; 5

; explode
(explode "." "198.123.12.45") ; ["198", "123", "12", "45"]

; reverse (strrev)
(reverse "Hello") ; "olleH"

; str (strstr)
(str "email@example.com" "@") ; "@example.com"
```

Sometimes two packages define the same symbol, so that the use of a function or value becomes ambiguous. This is the case of *shuffle* and *reverse*, both declared in *StringPackage* and *ArrayPackage*. This problem can be solved using the package name as a symbol prefix.

```
; ambiguos.em

; reverse
(reverse "abcde") ; "edcba"
(Array::reverse (array "one" "two" "three")) ; ["three" "two" "one"]
(String::reverse "xyz") ; "zyx"

; aux array
(:= _arr (array 1 2 3))

; shuffle
(shuffle "abcde") ; shuffle in String package
(Array::shuffle _arr) ; shuffle in Array package
(String::shuffle "xyz") ; shuffle in String package
```

\##Function invocation

The *call* and *apply* functions allow to invoke a function passed as argument.

```
; call_func.em
; shows some examples of call
(call "strtoupper" "hello world") ; returns "HELLO WORLD"

(call Array::range 2 5) ; returns [2, 3, 4, 5]
```

The *apply* function expects an array containing the list of arguments as a second parameter. This code uses *apply* to sum all arguments ​​passed to a program.

```
; sigma.em
; calculates the sum of all arguments passed
(apply + (%_))
```

\##Use and Import

The \*use\* and \*import\* functions allow importing functions directly from PHP or from other packages to the current symbol table. ```
; use_example.em
; usage examples of use function

; import utf8_encode
(use utf8_encode)
(:= _encoded (utf8_encode (%0)))

; using an alias
(use (utf8_decode utf8dec))
(:= _decoded (utf8dec _encoded))

; multiple use
(use mb_detect_encoding mb_internal_encoding (mb_get_info mbinfo))
```

The *import* function expects a symbol with the package class name to import.

```
; import_example.em
; usage examples of import

; import MathPackage class
(import eMacros\Package\MathPackage)
(:= _sin (sin Math::PI_2))

; if no class is found then import tries to recover the package from the eMacros\Package namespace (and adding "Package" as suffix)
(import CType)
(if (digit (%0)) "Argument is a digit" "Argument is not a digit")
```

\##User packages

The preferable way to implement user functions is through packages. By keeping our customized functions within packages we can import them into any environment more efficiently. The following example shows the implementation of a sample package that adds the symbols *MY\_CONSTANT* and *message* to the environment's symbol table.

```
namespace Acme;

use eMacros\Package\Package;

class CustomPackage extends Package {
    public function __construct() {
        //declare and ID for this package
        parent::__construct('Custom');

        $this['MY_CONSTANT'] = 42;
        $this['message'] = "this is a custom package";
    }
}
```

While it is possible to import the symbols of this package through *import*, it turns more convenient to use a customized environment. The following example shows the implementation of a runtime environment defined by the user.

```
namespace Acme;

use eMacros\Environment\Environment;
use eMacros\Package\CorePackage;
use eMacros\Package\StringPackage;

class CustomEnvironment extends Environment {
    public function __construct() {
        $this->import(new CustomPackage);
        $this->import(new StringPackage);
        $this->import(new CorePackage);
    }
}
```

Having already prepared our new user-defined environment we can make the implementation of programs using the previously declared symbols.

```
; custom.em
; An example using a user-defined environment
(symbol;

        //get symbol value
        $value = $arguments[0]->evaluate($scope);

        if ($nargs > 1) {
            $value += intval($arguments[1]->evaluate($scope));
        }
        else {
            $value++;
        }

        $scope->symbols[$ref] = $value;
        return true;
    }
}
```

Notice that this class ensures that the first parameter is a symbol or otherwise an exception is thrown.

```
namespace Acme;

use eMacros\Package\Package;
use Acme\Runtime\Increment

class UserPackage extends Package {
    public function __construct() {
        parent::__construct('User');

        /**
         * Increments a variable value
         * Usaeg: (inc _x) (inc _y 3)
         */
        $this['inc'] = new Increment();
    }
}
```

The following code imports the *UserPackage* class and shows an usage example of the *inc* function.

```
; inc.em
; Example using the inc function
(import Acme\UserPackage)
(:= _x 1)
(inc _x) ; _x = 2
(inc _x 3) ; _x = 5
```

\##Macros

Macros are functions that instead of being associated with a symbol they're generated from a regular expression. Macros are declared using the *macro* method. This method expects a regular expression string and a *Closure* instance (or anonymous function). This anonymous function receives all matches found for the given regular expression. Its main purpose is to generate a valid environment function with those matches. The following example shows the implementation of a macro to calculate the distance between 2 points. The coordinates of the starting point are declared as part of the operator and then captured by the anonymous function.

```
namespace Acme\Runtime;

use eMacros\Runtime\GenericFunction;

class Distance extends GenericFunction {
    public $x;
    public $y;

    public function __construct($coordX, $coordY) {
        $this->x = $coordX;
        $this->y = $coordY;
    }

    /**
     * Calculates the distance between 2 point
     * Usage: (dist:X1Y7 3 5)
     */
    public function execute(array $args) {
        if (count($args) < 2) {
            throw new \BadFunctionCallException("Distance: Destination not specified.");
        }

        $x = intval($args[0]);
        $y = intval($args[1]);

        $distance = pow($x - $this->x, 2) + pow($y - $this->y, 2);
        return sqrt($distance);
    }
}
```

The *dist* macro can be invoked directly without the need of specifying coordinates of origin. In that case, the distance will be calculated from the coordinates (0,0). The following code shows the implementation of the *GeometryPackage* class. This class adds *dist* to the symbol table and defines the customizable macro for calculating distances.

```
namespace Acme;

use eMacros\Package\Package;
use Acme\Runtime\Distance;

class GeometryPackage extends Package {
    public function __construct() {
        parent::__construct('Geometry');

        //default distance
        $this['dist'] = new Distance(0, 0);

        //macro style
        $this->macro('@dist:X(\d+)Y(\d+)@', function ($matches) {
            return new Distance(intval($matches[1]), intval($matches[2]));
        });
    }
}
```

The next example invokes the \*dist" macro using both modes (with and without coordinates).

```
; distance.em
; User-defined macro example
(import Acme\GeometryPackage)

; distance from (0,0)
(dist 4 2)

; distance from (4, 2)
(dist:X4Y2 5 7)
```

\##Appendix I - Available packages

   Class name Description Prefix     CorePackage Basic symbols and operators Core   ArrayPackage [Array functions](http://php.net/manual/en/ref.array.php) Array   BufferPackage [Output control functions](http://php.net/manual/en/ref.outcontrol.php) Buffer   CTypePackage [CType functions](http://php.net/manual/en/ref.ctype.php) CType   DatePackage [Date/Time functions](http://php.net/manual/en/ref.datetime.php) Date   FilePackage [Filesystem functions](http://php.net/manual/en/ref.filesystem.php) File   FilterPackage [Filter functions](http://php.net/manual/en/ref.filter.php) Filter   HashPackage Hashing functions (sha1,md5, etc) Hash   HTMLPackage HTML functions (nl2br, strip-tags, etc) HTML   JSONPackage [JSON functions](http://php.net/manual/en/ref.json.php) JSON   MathPackage [Math functions](http://php.net/manual/en/ref.math.php) Math   RegexPackage [PCRE functions](http://php.net/manual/en/ref.pcre.php) Regex   RequestPackage Request global vars (GET, POST, etc) Request   StringPackage [String functions](http://php.net/manual/en/ref.strings.php) String
\##License

This code is licensed under the BSD 2-Clause license.

###  Health Score

30

—

LowBetter than 62% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity16

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~78 days

Total

5

Last Release

4185d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/d6241918835cf405d0b48d0fc2eaabb3f3edcf53523844b138dc80df663ae99d?d=identicon)[emaphp](/maintainers/emaphp)

---

Top Contributors

[![emaphp](https://avatars.githubusercontent.com/u/3780753?v=4)](https://github.com/emaphp "emaphp (36 commits)")

---

Tags

macrosinterpreterlispemacross-expressions

### Embed Badge

![Health badge](/badges/emacros-emacros/health.svg)

```
[![Health](https://phpackages.com/badges/emacros-emacros/health.svg)](https://phpackages.com/packages/emacros-emacros)
```

###  Alternatives

[phel-lang/phel-lang

Phel is a functional programming language that compiles to PHP

5155.1k17](/packages/phel-lang-phel-lang)[appstract/laravel-response-macros

Extra Response Macro's for Laravel

321.5k](/packages/appstract-laravel-response-macros)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
