Skip to content

Latest commit

 

History

History
328 lines (242 loc) · 8.58 KB

File metadata and controls

328 lines (242 loc) · 8.58 KB

linger_framework

Build Status License: MIT GitHub release (latest by date)

linger_framework is a lightweight PHP web framework implemented in C and distributed as a native PHP extension. It moves the application lifecycle, routing, request abstraction, response emission, view rendering, and configuration management into the extension layer while preserving an idiomatic PHP development model and reducing userland runtime overhead.

Overview

linger_framework is designed for PHP applications that require framework-level capabilities with lower bootstrap cost and tighter runtime control than a purely userland framework can typically provide. The project exposes a compact MVC-style programming model while executing the core dispatch pipeline inside a compiled extension.

Key Capabilities

  • Native PHP extension architecture with framework primitives implemented in C
  • First-class support for application bootstrap, routing, controllers, requests, responses, views, and configuration
  • Namespace-based autoloading derived from the configured application root
  • Parameterized routing rules such as /home/@id:([0-9]+)
  • HTML template rendering and JSON response serialization
  • Bootstrap contract for route registration and application initialization

Typical Use Cases

  • Performance-sensitive PHP services that need a minimal framework bootstrap path
  • Projects that want to retain PHP controller and template ergonomics while shifting core dispatch concerns into native code
  • Experimental or infrastructure-oriented PHP stacks built around extension-level abstractions

Version Compatibility

  • The mainline codebase targets PHP 7.0+
  • For PHP 5.2+, use the php5 branch
  • Current project version: 2.2.0

Architecture

Component Responsibility
Linger\Framework\Application Application entry point responsible for configuration hydration, autoloader registration, router initialization, and dispatcher initialization
Linger\Framework\Bootstrap Bootstrap contract used to register routes or execute startup logic
Linger\Framework\Router Route registry supporting get, post, put, and delete semantics
Linger\Framework\RouterRule Route definition object encapsulating the HTTP method, URI pattern, controller class, and action method
Linger\Framework\Dispatcher Dispatch layer that resolves the current route and invokes the target controller action
Linger\Framework\Controller Abstract controller base class exposing Request, Response, and View instances
Linger\Framework\Request Request abstraction for method, URI, query parameters, route parameters, form data, cookies, and uploaded files
Linger\Framework\Response Response abstraction for HTTP status, headers, body payload, redirects, and JSON serialization
Linger\Framework\View Template rendering layer for .phtml scripts with variable binding and nested rendering
Linger\Framework\Config Configuration container supporting Iterator, ArrayAccess, and Countable

Installation

Build the Extension

/path/to/phpize
./configure --with-php-config=/path/to/php-config
make && make install

The repository also includes a minimal build helper:

./travis/compile.sh

Enable the Extension

Add the extension to php.ini:

extension=linger_framework.so

Verify the Installation

php -m | grep linger_framework
php --ri linger_framework

Configuration

Application Configuration

When instantiating Application, the following configuration keys are relevant:

  • app_directory: application source root, required
  • view_directory: template root, optional

Example:

<?php

$app = new Linger\Framework\Application([
    'app_directory' => __DIR__ . '/app',
    'view_directory' => __DIR__ . '/app/views',
    'db' => [
        'host' => '127.0.0.1',
        'name' => 'demo',
    ],
]);

Extension-Level INI Directives

linger_framework.display_errors = 1
linger_framework.throw_exception = 1
  • linger_framework.display_errors: controls whether framework-level PHP errors are emitted
  • linger_framework.throw_exception: controls whether framework failures are escalated as exceptions

Directory Conventions

The built-in autoloader resolves namespaces relative to app_directory. For example:

  • Class: boot\Router
  • File: <app_directory>/boot/Router.php

Recommended project layout:

app/
├── boot/
│   └── Router.php
├── handler/
│   └── Home.php
└── views/
    ├── header.phtml
    └── index.phtml

Quick Start

1. Define a Bootstrap Class

<?php
namespace boot;

use handler\Home;

class Router implements \Linger\Framework\Bootstrap
{
    public function bootstrap(\Linger\Framework\Application $app): void
    {
        $app->getRouter()
            ->get('/index.html', Home::class, 'index')
            ->get('/home/@id:([0-9]+)', Home::class, 'show');
    }
}

2. Implement a Controller

<?php
namespace handler;

class Home extends \Linger\Framework\Controller
{
    protected function _init(): void
    {
        $this->getView()->setScriptPath(__DIR__ . '/../views');
    }

    public function index()
    {
        $this->getView()
            ->assign('title', 'linger framework')
            ->assign('list', [
                ['name' => 'liubang', 'email' => 'it.liubang@gmail.com'],
            ])
            ->display('index.phtml');
    }

    public function show()
    {
        $id = $this->getRequest()->getParam('id', 0, 'intval');

        $this->getResponse()
            ->status(200)
            ->json(['id' => $id])
            ->send();
    }
}

3. Bootstrap and Run the Application

<?php

$app = new \Linger\Framework\Application([
    'app_directory' => __DIR__ . '/app',
    'view_directory' => __DIR__ . '/app/views',
]);

$app->init([
    \boot\Router::class,
]);

$app->run();

Routing

Static Routes

$app->getRouter()
    ->get('/home', Home::class, 'index')
    ->post('/home', Home::class, 'store')
    ->put('/home/@id:(\\d+)', Home::class, 'update')
    ->delete('/home/@id:(\\d+)', Home::class, 'delete');

Parameterized Routes

$app->getRouter()
    ->get('/home/@name:([a-z]+)/@age:(\\d+)/@id:(\\d+)', Home::class, 'profile');

Route parameters can be accessed directly from the controller:

$name = $this->getRequest()->getParam('name');
$age = $this->getRequest()->getParam('age', 0, 'intval');
$id = $this->getRequest()->getParam('id', 0, 'intval');

View Rendering

View renders .phtml templates and supports variable assignment, template evaluation, and nested rendering:

$this->getView()
    ->assign('title', 'Demo')
    ->assign('list', $rows)
    ->display('index.phtml');

Template example:

<!doctype html>
<html>
<head>
    <title><?= $title ?></title>
</head>
<body>
<?= $this->render('header.phtml') ?>
</body>
</html>

Response Handling

JSON Responses

$this->getResponse()
    ->status(200)
    ->header('X-App', 'linger')
    ->json([
        'name' => 'liubang',
        'age' => 25,
    ])
    ->send();

Raw Body Responses and Redirects

$this->getResponse()->body('ok')->send();
$this->getResponse()->redirect('/login');

Configuration Container

Linger\Framework\Config supports both object-style and array-style access patterns:

$config = $app->getConfig();

$all = $config->get();
$appDir = $config['app_directory'];
$db = $config->get('db');

Development and Testing

Run the Test Suite

make test

Or use the repository helper script:

./travis/run-test.sh

Covered Behaviors

The tests/ suite exercises the following framework behaviors:

  • Extension loading
  • Configuration access patterns
  • Bootstrap execution
  • Request mutation and parameter retrieval
  • Route matching and dynamic parameter extraction
  • Controller dispatch
  • View rendering
  • JSON response emission
  • Autoloading and application bootstrapping from the configured application directory

Related Projects

License

MIT