PHPackages                             adaiasmagdiel/erlenmeyer - 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. [Framework](/categories/framework)
4. /
5. adaiasmagdiel/erlenmeyer

ActiveLibrary[Framework](/categories/framework)

adaiasmagdiel/erlenmeyer
========================

Erlenmeyer is a lightweight PHP framework designed to create web applications simply and efficiently.

v5.0.0(5mo ago)0581↑40%2GPL-3.0-onlyPHPPHP ^8.1

Since Apr 13Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/AdaiasMagdiel/erlenmeyer)[ Packagist](https://packagist.org/packages/adaiasmagdiel/erlenmeyer)[ RSS](/packages/adaiasmagdiel-erlenmeyer/feed)WikiDiscussions main Synced yesterday

READMEChangelogDependencies (1)Versions (34)Used By (2)

Erlenmeyer - Minimal PHP Framework for Web Applications
=======================================================

[](#erlenmeyer---minimal-php-framework-for-web-applications)

[![License: GPL v3](https://camo.githubusercontent.com/48bf9b56d44f38db53ce21294cf0b9487d0a3734ab3ba1fe4c69858ae20db2c1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d47504c76332d626c75652e737667)](https://www.gnu.org/licenses/gpl-3.0)
[![Composer](https://camo.githubusercontent.com/bf1d7e3afdc010af79b9ebca2f7b441cf66a105758fa4b84a973559197ff3f03/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6d706f7365722d6164616961736d61676469656c2f65726c656e6d657965722d626c7565)](https://packagist.org/packages/adaiasmagdiel/erlenmeyer)
[![GitHub Repository](https://camo.githubusercontent.com/373353379d3399e8a9fa0be5d04bbc261de589735d22e201e7ffddebeb706a8c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4769744875622d4164616961734d61676469656c2f45726c656e6d657965722d626c7565)](https://github.com/AdaiasMagdiel/Erlenmeyer)

**Erlenmeyer** is a lightweight PHP framework designed for simplicity and efficiency in building web applications. Inspired by the minimalism of Python's Flask, Erlenmeyer is not a direct clone but a unique solution tailored for PHP developers. It is currently in its early stages, making it perfect for small projects, APIs, or microservices where a lean setup is preferred. I created Erlenmeyer to streamline my own projects, but it's open for anyone seeking a straightforward, no-frills framework.

Table of Contents
-----------------

[](#table-of-contents)

- [Introduction](#introduction)
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Routing](#routing)
- [Middlewares](#middlewares)
- [Error Handling](#error-handling)
- [Session Management](#session-management)
- [Request and Response Objects](#request-and-response-objects)
- [Logging](#logging)
- [Tests](#tests)
- [Use Cases](#use-cases)
- [License](#license)
- [Reference](#reference)

Introduction
------------

[](#introduction)

Erlenmeyer is a lightweight PHP framework designed for simplicity and efficiency in building web applications. Inspired by the minimalism of Python's Flask, Erlenmeyer is not a direct clone but a unique solution tailored for PHP developers. It is currently in its early stages, making it perfect for small projects, APIs, or microservices where a lean setup is preferred. I created Erlenmeyer to streamline my own projects, but it's open for anyone seeking a straightforward, no-frills framework.

**Key Characteristics:**

- **Minimalist**: Small footprint, easy to learn and use.
- **Flexible**: Supports various use cases, from simple scripts to full applications.
- **Extensible**: Built with extensibility in mind, allowing custom functionality.
- **Flask-Inspired**: Familiar routing and handler concepts for developers coming from Python.

Features
--------

[](#features)

- Simple and intuitive routing system with support for dynamic routes.
- Support for global and route-specific middlewares.
- Custom error handling for 404 errors and exceptions.
- Integrated session management with flash messages.
- Comprehensive `Request` and `Response` objects for handling HTTP requests and responses.
- Logging with file rotation for application event monitoring.

Requirements
------------

[](#requirements)

- **PHP**: 8.1 or higher
- **Composer**: For dependency management
- **Web Server**: Apache with `mod_rewrite` or Nginx
- **PHP Extensions**: `json`, `mbstring`
- **Optional**: `getallheaders` for enhanced header support (not always necessary)

Installation
------------

[](#installation)

Install Erlenmeyer using Composer:

```
composer require adaiasmagdiel/erlenmeyer
```

Include it in your PHP project:

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

Getting Started
---------------

[](#getting-started)

First, make sure to import the necessary classes:

```
use AdaiasMagdiel\Erlenmeyer\App;
use AdaiasMagdiel\Erlenmeyer\Request;
use AdaiasMagdiel\Erlenmeyer\Response;
```

Create a new instance of the `App` class:

```
$app = new App();
```

Define routes:

```
$app->get('/', function (Request $req, Response $res, $params) {
    $res->withHtml('Hello, World!')->send();
});
```

Run the application:

```
$app->run();
```

Routing
-------

[](#routing)

Erlenmeyer supports various HTTP methods for routing:

```
$app->get('/path', $handler);
$app->post('/path', $handler);
$app->put('/path', $handler);
$app->delete('/path', $handler);
$app->patch('/path', $handler);
$app->options('/path', $handler);
$app->head('/path', $handler);
$app->any('/path', $handler); // Matches any HTTP method
$app->match(['GET', 'POST'], '/path', $handler); // Matches specified methods
```

### Dynamic Routes

[](#dynamic-routes)

Define routes with parameters:

```
$app->get('/user/[id]', function (Request $req, Response $res, $params) {
    $id = $params->id;
    $res->withHtml("User ID: $id")->send();
});
```

### Redirects

[](#redirects)

Set up redirects:

```
$app->redirect('/old', '/new', false); // Temporary redirect (302)
```

Middlewares
-----------

[](#middlewares)

Add global middlewares:

```
$app->addMiddleware(function (Request $req, Response $res, callable $next, $params) {
    // Middleware logic
    $next($req, $res, $params);
});
```

Add route-specific middlewares:

```
$app->get('/admin', $handler, [$middleware1, $middleware2]);
```

Error Handling
--------------

[](#error-handling)

Set a custom 404 handler:

```
$app->set404Handler(function (Request $req, Response $res, $params) {
    $res->setStatusCode(404)->withHtml('Custom 404')->send();
});
```

Set exception handlers:

```
$app->setExceptionHandler(\Exception::class, function (Request $req, Response $res, \Exception $e) {
    $res->setStatusCode(500)->withHtml('Error: ' . $e->getMessage())->send();
});
```

Session Management
------------------

[](#session-management)

Use the `Session` class to manage sessions:

```
use AdaiasMagdiel\Erlenmeyer\Session;

Session::set('key', 'value');
$value = Session::get('key', 'default');
Session::flash('message', 'Flash message');
$flash = Session::getFlash('message');
```

Request and Response Objects
----------------------------

[](#request-and-response-objects)

### Request

[](#request)

The `Request` object provides access to request data:

```
$method = $req->getMethod();
$uri = $req->getUri();
$queryParams = $req->getQueryParams();
$formData = $req->getFormData();
$jsonData = $req->getJson();
$files = $req->getFiles();
$isAjax = $req->isAjax();
$isSecure = $req->isSecure();
```

### Response

[](#response)

The `Response` object allows building responses:

```
$res->withHtml('HTML content');
$res->withJson(['key' => 'value']);
$res->withText('Plain text');
$res->withFile('/path/to/file');
$res->redirect('/path');
$res->setStatusCode(404);
$res->setHeader('Key', 'Value');
$res->setCORS(['origin' => '*', 'methods' => 'GET,POST']);
$res->send();
```

Logging
-------

[](#logging)

Erlenmeyer provides a flexible and extensible logging system to help you monitor and debug your application. Logging is essential for tracking events, identifying issues, and understanding application behavior. The logging system is based on the `LoggerInterface`, which defines the contract for logging messages and exceptions.

### Using Loggers

[](#using-loggers)

Erlenmeyer provides two built-in loggers: `FileLogger` for file-based logging with rotation, and `ConsoleLogger` for logging to the command line using `error_log`. You can choose either by passing an instance to the `App` constructor.

**Example with FileLogger:**

```
use AdaiasMagdiel\Erlenmeyer\Logging\FileLogger;
use AdaiasMagdiel\Erlenmeyer\App;

$logger = new FileLogger('/path/to/logs');
$app = new App(logger: $logger);
```

- Logs are written to `/path/to/logs/info.log`.
- The `FileLogger` automatically rotates the log file when it exceeds 3MB, keeping up to 5 rotated files (e.g., `info.log.1`, `info.log.2`, etc.).
- If no log directory is provided, `FileLogger` will not log anything.

**Example with ConsoleLogger:**

```
use AdaiasMagdiel\Erlenmeyer\Logging\ConsoleLogger;
use AdaiasMagdiel\Erlenmeyer\App;

$logger = new ConsoleLogger();
$app = new App(logger: $logger);
```

- Logs are output to the command line using `error_log`, appearing in the terminal or server error log.
- No configuration is required for `ConsoleLogger`, making it ideal for debugging or CLI environments.

### Log Levels

[](#log-levels)

The logging system supports the following levels, defined in the `LogLevel` enum:

LevelDescription`INFO`General operational information`DEBUG`Detailed debug information`WARNING`Indicates something unexpected but recoverable`ERROR`Indicates a serious error affecting functionality`CRITICAL`Indicates a critical error that may cause the application to crashThese levels can be used when logging messages to categorize their severity.

### Creating a Custom Logger

[](#creating-a-custom-logger)

If you need advanced logging features, such as logging to a database, sending logs to an external service, or using a custom format, you can create a custom logger by implementing the `LoggerInterface`.

**Example of a Custom Logger:**

```
use AdaiasMagdiel\Erlenmeyer\Logging\LoggerInterface;
use AdaiasMagdiel\Erlenmeyer\Logging\LogLevel;
use Throwable;
use AdaiasMagdiel\Erlenmeyer\Request;

class CustomLogger implements LoggerInterface
{
    private $logFile;

    public function __construct(string $logFile)
    {
        $this->logFile = $logFile;
    }

    public function log(LogLevel $level, string $message): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $logEntry = "[$timestamp] [$level->value] $message\n";
        file_put_contents($this->logFile, $logEntry, FILE_APPEND);
    }

    public function logException(Throwable $e, ?Request $request = null): void
    {
        $timestamp = date('Y-m-d H:i:s');
        $message = "[$timestamp] [ERROR] Exception: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine() . "\n";
        if ($request) {
            $message .= "Request: " . $request->getMethod() . " " . $request->getUri() . "\n";
        }
        $message .= $e->getTraceAsString() . "\n";
        file_put_contents($this->logFile, $message, FILE_APPEND);
    }
}
```

To use the custom logger, pass an instance to the `App` constructor:

```
$customLogger = new CustomLogger('/path/to/custom.log');
$app = new App(logger: $customLogger);
```

**Important Note:** If no logger is explicitly provided, the `App` uses a `NullLogger` — a no-op implementation that silently discards all log messages. To enable logging, pass a `FileLogger` or `ConsoleLogger` explicitly.

Tests
-----

[](#tests)

Erlenmeyer uses PestPHP for testing. Run tests with:

```
./vendor/bin/pest
```

Use Cases
---------

[](#use-cases)

Erlenmeyer is suitable for a wide range of web applications. Here are some example use cases:

Use CaseDescription**Simple REST API**Create an API with endpoints for GET, POST, PUT, and DELETE, returning JSON responses.**Basic Web Application**Develop an application with routes for HTML pages and session management.**Static Page Generator**Build apps with routes for HTML pages; static assets are served by Apache or Nginx.**Forms and Uploads**Handle POST forms and file uploads with validation.**Example REST API:**

```
$app->get('/api/users/[id]', function (Request $req, Response $res, $params) {
    $id = $params->id;
    $res->withJson(['id' => $id, 'name' => 'User ' . $id])->send();
});
```

**Example Form Handling:**

```
$app->post('/submit', function (Request $req, Response $res, $params) {
    $name = $req->getFormDataParam('name', 'Guest');
    Session::flash('message', 'Form submitted successfully!');
    $res->redirect('/thank-you')->send();
});
```

Development
-----------

[](#development)

Documentation using mkdocs

```
py -m venv .venv
.venv/bin/activate  # .venv\Scripts\activate (on windows)
pip install mkdocs mkdocs-material

```

License
-------

[](#license)

Erlenmeyer is licensed under the GPLv3. See the [LICENSE](LICENSE) and the [COPYRIGHT](COPYRIGHT) files for details.

Reference
---------

[](#reference)

### App

[](#app)

MethodDescription`__construct(?LoggerInterface $logger = null)`Initializes the application.`route(string $method, string $route, callable $action, array $middlewares = [])`Registers a route for an HTTP method.`get(string $route, callable $action, array $middlewares = [])`Registers a GET route.`post(string $route, callable $action, array $middlewares = [])`Registers a POST route.`any(string $route, callable $action, array $middlewares = [])`Registers a route for any HTTP method.`match(array $methods, string $route, callable $action, array $middlewares = [])`Registers a route for specified methods.`redirect(string $from, string $to, bool $permanent = false)`Registers a redirect.`set404Handler(callable $action)`Sets the 404 error handler.`setFallbackHandler(callable $action)`Sets a fallback handler called before 404.`addMiddleware(callable $middleware)`Adds a global middleware.`setExceptionHandler(string $exceptionClass, callable $handler)`Sets an exception handler.`run()`Runs the application.### Session

[](#session)

MethodDescription`static get(string $key, $default = null)`Gets a session value.`static set(string $key, $value)`Sets a session value.`static has(string $key): bool`Checks if a session key exists.`static remove(string $key)`Removes a session key.`static regenerate(bool $deleteOldSession = true)`Regenerates session ID (prevents fixation).`static close()`Releases the session lock.`static flash(string $key, $value)`Sets a flash message.`static getFlash(string $key, $default = null)`Gets and removes a flash message.`static hasFlash(string $key): bool`Checks if a flash message exists.### Request

[](#request-1)

MethodDescription`__construct(?array $server = null, ?array $get = null, ?array $post = null, ?array $files = null, string $inputStream = 'php://input')`Initializes the request.`getHeader(string $name): ?string`Gets a specific header.`getHeaders(): array`Gets all headers.`getMethod(): string`Gets the HTTP method.`getUri(): string`Gets the request URI.`getQueryParams(): array`Gets query parameters.`getFormData(): array`Gets form data.`getJson(): mixed`Gets JSON data from the body.`getFiles(): array`Gets uploaded files.`isAjax(): bool`Checks if the request is AJAX.`isSecure(): bool`Checks if the request is secure (HTTPS).### Response

[](#response-1)

MethodDescription`__construct(int $statusCode = 200, array $headers = [])`Initializes the response.`setStatusCode(int $code): self`Sets the HTTP status code.`getStatusCode(): int`Gets the HTTP status code.`setHeader(string $name, string $value): self`Sets an HTTP header.`removeHeader(string $name): self`Removes an HTTP header.`getHeaders(): array`Gets all headers.`setContentType(string $contentType): self`Sets the content type.`getContentType(): string`Gets the content type.`setBody(string $body): self`Sets the response body.`getBody(): ?string`Gets the response body.`withHtml(string $html): self`Sets HTML content.`withTemplate(string $templatePath, array $data = []): self`Sets content from a template.`withJson($data, int $options = JSON_PRETTY_PRINT): self`Sets JSON content.`withText(string $text): self`Sets plain text content.`redirect(string $url, int $statusCode = 302): self`Sets a redirect.`withCookie(string $name, string $value, int $expire = 0, string $path = '/', string $domain = '', bool $secure = false, bool $httpOnly = true): self`Sets a cookie.`send(): void`Sends the response.`isSent(): bool`Checks if the response has been sent.`clear(): self`Clears the response body and headers.`withError(int $statusCode, string $message = '', ?callable $logger = null): self`Sets an error response.`withFile(string $filePath): self`Sets the response to send a file.`setCORS(array $options): self`Configures CORS headers.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance78

Regular maintenance activity

Popularity16

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 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 ~8 days

Total

33

Last Release

164d ago

Major Versions

v0.2.1 → v1.0.02025-04-21

v1.0.3 → v2.0.02025-04-24

v2.3.0 → v3.0.02025-05-07

v3.2.1 → v4.0.02025-10-13

v4.2.8 → v5.0.02026-01-20

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/22068596?v=4)[Adaías Magdiel](/maintainers/adaiasmagdiel)[@AdaiasMagdiel](https://github.com/AdaiasMagdiel)

---

Top Contributors

[![AdaiasMagdiel](https://avatars.githubusercontent.com/u/22068596?v=4)](https://github.com/AdaiasMagdiel "AdaiasMagdiel (115 commits)")

###  Code Quality

TestsPest

### Embed Badge

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

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

###  Alternatives

[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k39.6M299](/packages/laravel-dusk)[nineinchnick/edatatables

Grid widget for the Yii Framework, wrapper for the DataTables jQuery plugin

173.2k](/packages/nineinchnick-edatatables)[link-cloud/fast-hyperf

LinkCloud Fast Hyperf

241.2k1](/packages/link-cloud-fast-hyperf)

PHPackages © 2026

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