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.
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.
- 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
- 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
- The mainline codebase targets
PHP 7.0+ - For
PHP 5.2+, use the php5 branch - Current project version:
2.2.0
| 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 |
/path/to/phpize
./configure --with-php-config=/path/to/php-config
make && make installThe repository also includes a minimal build helper:
./travis/compile.shAdd the extension to php.ini:
extension=linger_framework.sophp -m | grep linger_framework
php --ri linger_frameworkWhen instantiating Application, the following configuration keys are relevant:
app_directory: application source root, requiredview_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',
],
]);linger_framework.display_errors = 1
linger_framework.throw_exception = 1linger_framework.display_errors: controls whether framework-level PHP errors are emittedlinger_framework.throw_exception: controls whether framework failures are escalated as exceptions
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
<?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');
}
}<?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();
}
}<?php
$app = new \Linger\Framework\Application([
'app_directory' => __DIR__ . '/app',
'view_directory' => __DIR__ . '/app/views',
]);
$app->init([
\boot\Router::class,
]);
$app->run();$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');$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 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>$this->getResponse()
->status(200)
->header('X-App', 'linger')
->json([
'name' => 'liubang',
'age' => 25,
])
->send();$this->getResponse()->body('ok')->send();
$this->getResponse()->redirect('/login');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');make testOr use the repository helper script:
./travis/run-test.shThe 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
- Example project: linger_framework_example
- IDE helper: linger_framework_idehelper